diff --git a/client/src/api/hooks/useTransactionModalApi.js b/client/src/api/hooks/useTransactionModalApi.js index 85ac202..3980c33 100644 --- a/client/src/api/hooks/useTransactionModalApi.js +++ b/client/src/api/hooks/useTransactionModalApi.js @@ -95,7 +95,8 @@ export const useTransactionModalApi = (tokenContract) => { ephemeral, tokenContract, utils.toBigInt(to_wei_token_amount), - options + OwshenWallet.wallet, + options, ); await tx.wait(); axios.get(`${coreEndpoint}/coins`).then((result) => { @@ -166,6 +167,7 @@ export const useTransactionModalApi = (tokenContract) => { address: OwshenWallet.wallet, new_amount: to_wei_token_amount, receiver_address: destOwshenWallet, + memo: OwshenWallet.wallet, }, }) .then(async (result) => { @@ -228,7 +230,8 @@ export const useTransactionModalApi = (tokenContract) => { result.data.obfuscated_receiver_amount, result.data.obfuscated_sender_amount, true, - options + options, + result.data.memo, ); console.log("Transaction response", txResponse); const txReceipt = await txResponse.wait(); @@ -329,7 +332,8 @@ export const useTransactionModalApi = (tokenContract) => { toBigInt(desireAmount), result.data.obfuscated_remaining_amount, address, - commitment + commitment, + OwshenWallet.wallet, ); console.log("Transaction response", txResponse); const txReceipt = await txResponse.wait(); diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 3dd5d31..77c05b8 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -3,5 +3,6 @@ solc-version = "0.8.20" src = "src" out = "out" libs = ["lib"] +viaIR = true # See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/contracts/src/Dive.sol b/contracts/src/Dive.sol index 300aa3e..84b0bb6 100644 --- a/contracts/src/Dive.sol +++ b/contracts/src/Dive.sol @@ -8,10 +8,8 @@ import "./MptPathVerifier.sol"; import "./MptLastVerifier.sol"; import "./SpendVerifier.sol"; - contract DiveToken is ERC20 { - uint256 constant FIELD_SIZE = - 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; struct Groth16Proof { uint256[2] a; @@ -48,11 +46,7 @@ contract DiveToken is ERC20 { event CoinGenerated(address recipient, uint256 coin); event CoinSpent( - address spender, - uint256 coin, - uint256 remainingCoin, - uint256 withdrawnBalance, - address destination + address spender, uint256 coin, uint256 remainingCoin, uint256 withdrawnBalance, address destination ); constructor(uint256 initialSupply) ERC20("Dive", "DIVE") { @@ -127,25 +121,14 @@ contract DiveToken is ERC20 { coins[coin] = false; require( - spend_verifier.verifyProof( - proof.a, - proof.b, - proof.c, - [coin, remainingCoin, withdrawnBalance] - ), + spend_verifier.verifyProof(proof.a, proof.b, proof.c, [coin, remainingCoin, withdrawnBalance]), "SpendVerifier: invalid proof" ); coins[remainingCoin] = true; _burnt_balances[destination] += withdrawnBalance; - emit CoinSpent( - msg.sender, - coin, - remainingCoin, - withdrawnBalance, - destination - ); + emit CoinSpent(msg.sender, coin, remainingCoin, withdrawnBalance, destination); emit CoinGenerated(destination, remainingCoin); } @@ -157,10 +140,7 @@ contract DiveToken is ERC20 { return (block.number - starting_block) / BLOCK_PER_EPOCH; } - function approximate( - uint256 amount_per_epoch, - uint256 num_epochs - ) public view returns (uint256) { + function approximate(uint256 amount_per_epoch, uint256 num_epochs) public view returns (uint256) { uint256 mint_amount = 0; uint256 currEpoch = currentEpoch(); for (uint256 i = 0; i < num_epochs; i++) { @@ -180,14 +160,8 @@ contract DiveToken is ERC20 { return reward; } - function participate( - uint256 amount_per_epoch, - uint256 num_epochs - ) external { - require( - _burnt_balances[msg.sender] >= amount_per_epoch * num_epochs, - "Insufficient balance" - ); + function participate(uint256 amount_per_epoch, uint256 num_epochs) external { + require(_burnt_balances[msg.sender] >= amount_per_epoch * num_epochs, "Insufficient balance"); _burnt_balances[msg.sender] -= amount_per_epoch * num_epochs; uint256 currEpoch = currentEpoch(); @@ -198,10 +172,7 @@ contract DiveToken is ERC20 { } function claim(uint256 starting_epoch, uint256 num_epochs) external { - require( - starting_epoch + num_epochs <= currentEpoch(), - "Cannot claim an ongoing epoch!" - ); + require(starting_epoch + num_epochs <= currentEpoch(), "Cannot claim an ongoing epoch!"); uint256 mint_amount = 0; for (uint256 i = 0; i < num_epochs; i++) { uint256 total = epoch_totals[starting_epoch + i]; diff --git a/contracts/src/Owshen.sol b/contracts/src/Owshen.sol index fd765ce..d4e26f0 100644 --- a/contracts/src/Owshen.sol +++ b/contracts/src/Owshen.sol @@ -27,7 +27,8 @@ contract Owshen { uint256 timestamp, uint256 hint_amount, uint256 hint_tokenAddress, - uint256 commitment + uint256 commitment, + string memo ); event Spend(uint256 nullifier); @@ -52,15 +53,18 @@ contract Owshen { depositIndex = _deposit_index; } - function deposit(Point calldata _pub_key, Point calldata _ephemeral, address _tokenAddress, uint256 _amount) - public - payable - { + function deposit( + Point calldata _pub_key, + Point calldata _ephemeral, + address _tokenAddress, + uint256 _amount, + string memory _memo + ) public payable { uint256 uint_tokenaddress = getUintTokenAddress(_tokenAddress); uint256 leaf = poseidon4.poseidon([_pub_key.x, _pub_key.y, _amount, uint_tokenaddress]); chc.set(leaf); _processDeposit(msg.sender, address(this), _tokenAddress, _amount); - emit Sent(_ephemeral, depositIndex, block.timestamp, _amount, uint_tokenaddress, leaf); + emit Sent(_ephemeral, depositIndex, block.timestamp, _amount, uint_tokenaddress, leaf, _memo); depositIndex += 1; } @@ -121,7 +125,8 @@ contract Owshen { uint256 _amount, uint256 _obfuscated_remaining_amount, address _to, - uint256 _commitment + uint256 _commitment, + string memory _memo ) public { uint256 uint_tokenaddress = getUintTokenAddress(_tokenAddress); uint256 null_commitment = poseidon4.poseidon([uint256(uint160(_to)), 0, _amount, uint_tokenaddress]); @@ -132,7 +137,13 @@ contract Owshen { IERC20 payToken = IERC20(_tokenAddress); payToken.transfer(_to, _amount); emit Sent( - _ephemeral, depositIndex, block.timestamp, _obfuscated_remaining_amount, uint_tokenaddress, _commitment + _ephemeral, + depositIndex, + block.timestamp, + _obfuscated_remaining_amount, + uint_tokenaddress, + _commitment, + _memo ); emit Spend(_nullifiers[0]); emit Spend(_nullifiers[1]); @@ -151,7 +162,8 @@ contract Owshen { uint256 _sender_token_address_hint, uint256 _receiver_amount_hint, uint256 _sender_amount_hint, - bool _is_dual_output + bool _is_dual_output, + string memory _memo ) public { spend(_proof, _checkpoint_head, _latest_values_commitment_head, _nullifiers, [_commitments[1], _commitments[0]]); chc.set(_commitments[1]); @@ -161,7 +173,8 @@ contract Owshen { block.timestamp, _receiver_amount_hint, _receiver_token_address_hint, - _commitments[1] + _commitments[1], + _memo ); depositIndex += 1; if (_is_dual_output) { @@ -172,7 +185,8 @@ contract Owshen { block.timestamp, _sender_amount_hint, _sender_token_address_hint, - _commitments[0] + _commitments[0], + _memo ); depositIndex += 1; } diff --git a/contracts/test/Owshen.t.sol b/contracts/test/Owshen.t.sol index 8c26b8d..b5ced2b 100644 --- a/contracts/test/Owshen.t.sol +++ b/contracts/test/Owshen.t.sol @@ -17,14 +17,16 @@ contract OwshenTest is Test { Owshen.Point({x: 123, y: 234}), Owshen.Point({x: 123, y: 234}), 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6, - 1000 + 1000, + "memo" ); assertEq(owshen.depositIndex(), 1); owshen.deposit( Owshen.Point({x: 234, y: 345}), Owshen.Point({x: 123, y: 234}), 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6, - 2000 // Add the amount here + 2000, // Add the amount here + "memo" ); assertEq(owshen.depositIndex(), 2); } diff --git a/src/apis/coins.rs b/src/apis/coins.rs index 67a8425..bdc1d31 100644 --- a/src/apis/coins.rs +++ b/src/apis/coins.rs @@ -198,6 +198,7 @@ fn sync_coins( let hint_token_address = sent_event.hint_token_address; let commitment = Fp::try_from(sent_event.commitment).ok()?; let shared_secret = stealth_priv.shared_secret(ephemeral); + if let Ok(Some((fp_hint_token_address, fp_hint_amount))) = extract_token_amount( hint_token_address, hint_amount, @@ -213,6 +214,7 @@ fn sync_coins( priv_key: stealth_priv, pub_key: stealth_pub, commitment: sent_event.commitment, + memo: sent_event.memo.clone(), }) } else { None diff --git a/src/apis/send.rs b/src/apis/send.rs index e143305..704f044 100644 --- a/src/apis/send.rs +++ b/src/apis/send.rs @@ -20,6 +20,7 @@ pub struct GetSendRequest { pub new_amount: String, pub receiver_address: String, pub address: String, + pub memo: String, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -36,6 +37,7 @@ pub struct GetSendResponse { pub obfuscated_sender_amount: U256, pub obfuscated_receiver_token_address: U256, pub obfuscated_sender_token_address: U256, + pub memo: String, } pub async fn send>( @@ -51,6 +53,7 @@ pub async fn send>( let new_amount = req.new_amount; let receiver_address = req.receiver_address; let address = req.address; + let memo = req.memo; let coins = context_send.lock().await.coins.clone(); let chc = context_send.lock().await.chc.clone(); let filtered_coin = coins.iter().find(|coin| coin.index == index); @@ -152,6 +155,7 @@ pub async fn send>( sender_commitment: u256_calc_sender_commitment, sender_ephemeral: address_ephemeral.point, receiver_ephemeral: receiver_address_pub_ephemeral.point, + memo, })) } else { log::warn!("No coin with index {} found", index); diff --git a/src/checkpointed_hashchain.rs b/src/checkpointed_hashchain.rs index b987786..0b744f7 100644 --- a/src/checkpointed_hashchain.rs +++ b/src/checkpointed_hashchain.rs @@ -127,7 +127,10 @@ impl CheckpointedHashchain { let mut chks = vec![]; chks.push(proof.checkpoints[0]); for i in 1..proof.checkpoints.len() { - chks.push(hash2([proof.checkpoints[i - 1], proof.checkpoint_commitments[i]])); + chks.push(hash2([ + proof.checkpoints[i - 1], + proof.checkpoint_commitments[i], + ])); } assert!(chks.contains(&proof.checkpoint_head)); diff --git a/src/config.rs b/src/config.rs index f97afc3..016ed6e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -128,7 +128,7 @@ pub struct NetworkManager { pub networks: HashMap>, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Coin { pub index: U256, pub uint_token: H160, @@ -137,6 +137,7 @@ pub struct Coin { pub pub_key: PublicKey, pub nullifier: U256, pub commitment: U256, + pub memo: String, } #[derive(Clone, Debug, Serialize, Deserialize, Default)] diff --git a/src/genesis/mod.rs b/src/genesis/mod.rs index da25f18..5802f26 100644 --- a/src/genesis/mod.rs +++ b/src/genesis/mod.rs @@ -23,6 +23,7 @@ pub struct Entry { hint_amount: Fp, hint_token_address: Fp, commitment: Fp, + memo: String, } impl Into for Entry { @@ -34,6 +35,7 @@ impl Into for Entry { hint_amount: self.hint_amount.into(), hint_token_address: self.hint_token_address.into(), commitment: self.commitment.into(), + memo: self.memo.into(), } } } @@ -51,6 +53,7 @@ unsafe impl Sync for Genesis {} pub fn gen_genesis_events(dive_token_address: H160) -> Vec { let dive_token_addr: Fp = h160_to_u256(dive_token_address).try_into().unwrap(); let coeff = Fp::from_str_vartime("1000000000000000000").unwrap(); + let memo = "genesis".to_string(); GENESIS .clone() .into_par_iter() @@ -72,6 +75,7 @@ pub fn gen_genesis_events(dive_token_address: H160) -> Vec { hint_amount: amount, hint_token_address: dive_token_addr, commitment: commit, + memo: memo.clone(), } }) .collect() diff --git a/src/hash.rs b/src/hash.rs index adf8d23..5fdd657 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -13,7 +13,7 @@ pub fn hash2(vals: [Fp; 2]) -> Fp { #[cfg(test)] mod tests { use crate::fp::Fp; - use crate::hash::{hash4, hash2}; + use crate::hash::{hash2, hash4}; use ff::PrimeField; #[test] fn poseidon4_hash() {