Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea/
**/README.md

**/build
5 changes: 5 additions & 0 deletions transfer_expiry/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/
16 changes: 16 additions & 0 deletions transfer_expiry/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"program": "transfer_public_expiry.aleo",
"version": "0.1.0",
"description": "",
"license": "MIT",
"leo": "3.2.0",
"dependencies": [
{
"name": "credits.aleo",
"location": "network",
"path": null,
"edition": null
}
],
"dev_dependencies": null
}
56 changes: 56 additions & 0 deletions transfer_expiry/src/main.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// The 'transfer_public_expiry' program.
import credits.aleo;

program transfer_public_expiry.aleo {

// Struct to hold address and nonce for hashing
struct NonceKey {
sender: address,
nonce: u64,
}

// Mapping to store used nonces for each sender address
// Key is the NonceKey struct containing address and nonce
mapping used_nonces: NonceKey => bool;

// Default constructor which doesn't allow for program upgrades.
@noupgrade
async constructor() {}

// Wrapper around credits.aleo::transfer_public with an expiry and nonce validation.
async transition transfer_public_with_expiry(
public to: address,
public amount: u64,
public expiry_block_height: u32,
public nonce: u64
) -> Future {
// Get the sender's address before entering async block
let sender: address = self.caller;

// Call the original transfer_public function from credits.aleo
let f1 = credits.aleo/transfer_public(to, amount);

let f2: Future = async {
// Create a NonceKey struct with the sender address and nonce
let nonce_key: NonceKey = NonceKey {
sender: sender,
nonce: nonce,
};

// Check if the nonce has already been used for this sender
let is_used: bool = used_nonces.get(nonce_key);
assert(!is_used);

// Store the nonce as used for this sender
used_nonces.set(nonce_key, true);

// Check if current block height is below the expiry block height
let current_block_height: u32 = block.height;
assert(current_block_height < expiry_block_height);
f1.await();
};

return f2;
}
}

27 changes: 27 additions & 0 deletions transfer_expiry/tests/test_transfer_public_expiry.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// The 'test_transfer_public_expiry' test program.
import transfer_public_expiry.aleo;

program test_transfer_public_expiry.aleo {
// Default constructor which doesn't allow for program upgrades.
@noupgrade
async constructor() {}

@test
async transition test_expiry() -> Future {
// Test the transfer_public_with_expiry function
// This would normally require proper setup with credits, but demonstrates the interface
let to: address = aleo1kanvv2cs88dpguwz5yrv890zz89rmycyk7qe6q4qm7vnz30flyzs56zae8;
let amount: u64 = 1000u64;
let expiry_block_height: u32 = 1000000u32;
let nonce: u64 = 1u64;

// Call the wrapper function
let f1 = transfer_public_expiry.aleo/transfer_public_with_expiry(to, amount, expiry_block_height, nonce);

let f2 = async {
f1.await();
};

return f2;
}
}