diff --git a/crates/primitives/src/abi.rs b/crates/primitives/src/abi.rs index 1da5ffbd8..3f2eaa3a5 100644 --- a/crates/primitives/src/abi.rs +++ b/crates/primitives/src/abi.rs @@ -52,6 +52,7 @@ macro_rules! define_abi { address to; uint128 amount; bytes32 memo; + address bouncebackRecipient; } /// Encrypted deposit payload (ECIES encrypted recipient and memo) @@ -72,6 +73,7 @@ macro_rules! define_abi { uint128 amount; uint256 keyIndex; EncryptedDepositPayload encrypted; + address bouncebackRecipient; } #[derive(Debug)] @@ -123,6 +125,7 @@ macro_rules! define_abi { uint128 netAmount, uint128 fee, bytes32 memo, + address bouncebackRecipient, uint64 depositNumber ); @@ -160,7 +163,7 @@ macro_rules! define_abi { event WithdrawalProcessed(address indexed to, address token, uint128 amount, bool callbackSuccess); #[derive(Debug)] - event BounceBack( + event WithdrawalBounceBack( bytes32 indexed newCurrentDepositQueueHash, address indexed fallbackRecipient, address token, @@ -168,6 +171,13 @@ macro_rules! define_abi { uint64 depositNumber ); + #[derive(Debug)] + event DepositBounceBack( + address indexed bouncebackRecipient, + address token, + uint128 amount + ); + #[derive(Debug)] event SequencerTransferStarted( address indexed currentSequencer, @@ -212,7 +222,7 @@ macro_rules! define_abi { // -- State-changing functions -- - function deposit(address token, address to, uint128 amount, bytes32 memo) + function deposit(address token, address to, uint128 amount, bytes32 memo, address bouncebackRecipient) external returns (bytes32 newCurrentDepositQueueHash); @@ -234,7 +244,8 @@ macro_rules! define_abi { address token, uint128 amount, uint256 keyIndex, - EncryptedDepositPayload calldata encrypted + EncryptedDepositPayload calldata encrypted, + address bouncebackRecipient ) external returns (bytes32 newCurrentDepositQueueHash); function setSequencerEncryptionKey( @@ -744,6 +755,7 @@ mod tests { to: address!("0x0000000000000000000000000000000000000002"), amount: 1000u128, memo: B256::ZERO, + bouncebackRecipient: Address::ZERO, }; let encoded = d.abi_encode(); @@ -767,6 +779,7 @@ mod tests { to: address!("0x0000000000000000000000000000000000000002"), amount: 1000u128, memo: B256::ZERO, + bouncebackRecipient: Address::ZERO, }; let deposit_data = Bytes::from(deposit.abi_encode()); @@ -826,6 +839,7 @@ mod tests { to: address!("0x0000000000000000000000000000000000000002"), amount: 1000u128, memo: B256::ZERO, + bouncebackRecipient: Address::ZERO, }; let prev_hash = B256::ZERO; diff --git a/crates/tempo-zone/src/builder.rs b/crates/tempo-zone/src/builder.rs index 3828e97bc..791c49c54 100644 --- a/crates/tempo-zone/src/builder.rs +++ b/crates/tempo-zone/src/builder.rs @@ -600,7 +600,7 @@ pub fn build_advance_tempo_tx(prepared: &PreparedL1Block) -> Recovered Self { + pub fn from_bounce_back(event: WithdrawalBounceBack, portal_address: Address) -> Self { Self { token: event.token, sender: portal_address, @@ -813,6 +816,7 @@ impl Deposit { amount: event.amount, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, } } } @@ -840,6 +844,8 @@ pub struct EncryptedDeposit { pub nonce: [u8; 12], /// GCM authentication tag (16 bytes). pub tag: [u8; 16], + /// Bounceback recipient on L1 (receives funds if the zone rejects the deposit). + pub bounceback_recipient: Address, } impl EncryptedDeposit { @@ -856,6 +862,7 @@ impl EncryptedDeposit { ciphertext: event.ciphertext.to_vec(), nonce: event.nonce.0, tag: event.tag.0, + bounceback_recipient: Address::ZERO, } } } @@ -882,6 +889,7 @@ impl L1Deposit { to: d.to, amount: d.amount, memo: d.memo, + bouncebackRecipient: d.bounceback_recipient, }, prev_hash, ) @@ -902,6 +910,7 @@ impl L1Deposit { nonce: d.nonce.into(), tag: d.tag.into(), }, + bouncebackRecipient: d.bounceback_recipient, }, prev_hash, ) @@ -983,7 +992,7 @@ impl L1PortalEvents { const SIGNATURE_HASHES: [B256; 6] = [ DepositMade::SIGNATURE_HASH, EncryptedDepositMade::SIGNATURE_HASH, - BounceBack::SIGNATURE_HASH, + WithdrawalBounceBack::SIGNATURE_HASH, TokenEnabled::SIGNATURE_HASH, SequencerTransferStarted::SIGNATURE_HASH, SequencerTransferred::SIGNATURE_HASH, @@ -1034,7 +1043,7 @@ impl L1PortalEvents { self.deposits .push(L1Deposit::Encrypted(EncryptedDeposit::from_event(event))); } - ZonePortalEvents::BounceBack(event) => { + ZonePortalEvents::WithdrawalBounceBack(event) => { info!( l1_block = block_number, token = %event.token, @@ -1145,6 +1154,7 @@ impl L1BlockDeposits { to: d.to, amount: d.amount, memo: d.memo, + bouncebackRecipient: d.bounceback_recipient, }; queued_deposits.push(abi::QueuedDeposit { depositType: abi::DepositType::Regular, @@ -1167,6 +1177,7 @@ impl L1BlockDeposits { nonce: d.nonce.into(), tag: d.tag.into(), }, + bouncebackRecipient: d.bounceback_recipient, } .abi_encode(), ), @@ -1992,7 +2003,7 @@ mod tests { let portal_address = address!("0x0000000000000000000000000000000000000ABC"); let fallback_recipient = address!("0x00000000000000000000000000000000000000F1"); let token = address!("0x0000000000000000000000000000000000002000"); - let event = BounceBack { + let event = WithdrawalBounceBack { newCurrentDepositQueueHash: B256::with_last_byte(0x42), fallbackRecipient: fallback_recipient, token, @@ -2192,6 +2203,7 @@ mod tests { amount: 1000, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); queue.enqueue( @@ -2218,6 +2230,7 @@ mod tests { amount: 2000, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); queue.enqueue( @@ -2239,6 +2252,7 @@ mod tests { amount: 1000, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }), L1Deposit::Regular(Deposit { token: address!("0x0000000000000000000000000000000000001000"), @@ -2247,6 +2261,7 @@ mod tests { amount: 2000, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }), ]; @@ -2278,6 +2293,7 @@ mod tests { amount: 500, fee: 0, memo: FixedBytes::from([0xABu8; 32]), + bounceback_recipient: Address::ZERO, })]; queue.enqueue( @@ -2302,6 +2318,7 @@ mod tests { amount: 100, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); let d2 = L1Deposit::Regular(Deposit { @@ -2311,6 +2328,7 @@ mod tests { amount: 200, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); let h10 = make_test_header(10); @@ -2349,6 +2367,7 @@ mod tests { ciphertext: vec![0x42u8; 64], nonce: [0x01; 12], tag: [0x02; 16], + bounceback_recipient: Address::ZERO, }; // Compute via PendingDeposits (Rust implementation) @@ -2368,6 +2387,7 @@ mod tests { nonce: encrypted.nonce.into(), tag: encrypted.tag.into(), }, + bouncebackRecipient: Address::ZERO, }; let expected = keccak256((DepositType::Encrypted, abi_encrypted, B256::ZERO).abi_encode()); @@ -2395,6 +2415,7 @@ mod tests { amount: 500_000, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }; let encrypted = EncryptedDeposit { @@ -2408,6 +2429,7 @@ mod tests { ciphertext: vec![0x55u8; 64], nonce: [0x0A; 12], tag: [0x0B; 16], + bounceback_recipient: Address::ZERO, }; let deposits = vec![ @@ -2427,6 +2449,7 @@ mod tests { to: regular.to, amount: regular.amount, memo: regular.memo, + bouncebackRecipient: Address::ZERO, }, B256::ZERO, ) @@ -2448,6 +2471,7 @@ mod tests { nonce: encrypted.nonce.into(), tag: encrypted.tag.into(), }, + bouncebackRecipient: Address::ZERO, }, hash_1, ) @@ -2474,6 +2498,7 @@ mod tests { ciphertext: vec![0x99u8; 64], nonce: [0x03; 12], tag: [0x04; 16], + bounceback_recipient: Address::ZERO, }; let deposits = vec![L1Deposit::Encrypted(encrypted)]; @@ -2694,6 +2719,7 @@ mod tests { amount: 100, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); assert!(matches!( queue.try_enqueue(seal(h1), L1PortalEvents::from_deposits(vec![d1]), vec![]), @@ -2709,6 +2735,7 @@ mod tests { amount: 200, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }); assert!(matches!( queue.try_enqueue(seal(h2), L1PortalEvents::from_deposits(vec![d2]), vec![]), @@ -2742,6 +2769,7 @@ mod tests { amount, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, }) } diff --git a/crates/tempo-zone/tests/advance_tempo.rs b/crates/tempo-zone/tests/advance_tempo.rs index e837ad128..aef07a4b5 100644 --- a/crates/tempo-zone/tests/advance_tempo.rs +++ b/crates/tempo-zone/tests/advance_tempo.rs @@ -195,12 +195,13 @@ fn setup_zone_evm_with_contracts() -> TempoEvm> { ); nonce += 1; - // 3. ZoneInbox(address config, address tempoPortal, address tempoState) + // 3. ZoneInbox(address config, address tempoPortal, address tempoState, address outbox) let zone_inbox_bytecode = load_artifact("ZoneInbox"); let zone_inbox_args = alloy_sol_types::SolValue::abi_encode_params(&( ZONE_CONFIG_ADDRESS, tempo_portal, TEMPO_STATE_ADDRESS, + ZONE_OUTBOX_ADDRESS, )); deploy_contract( &mut evm, diff --git a/crates/tempo-zone/tests/assets/zone-test-genesis.json b/crates/tempo-zone/tests/assets/zone-test-genesis.json index 3990561cf..fe36f35d1 100644 --- a/crates/tempo-zone/tests/assets/zone-test-genesis.json +++ b/crates/tempo-zone/tests/assets/zone-test-genesis.json @@ -41,7 +41,7 @@ "0x1c00000000000000000000000000000000000000": { "nonce": "0x1", "balance": "0x0", - "code": "0x60806040526004361015610011575f80fd5b5f3560e01c80631d04645f146101245780632245d0831461011f5780632e224dee1461011a5780633d7a27611461011557806346903867146101105780634732f8bb1461010b57806352d922a51461010657806358c3659914610101578063615cf854146100fc5780636aba6931146100f757806380a4cbc8146100f257806381e3da6b146100ed5780639a7361eb146100e8578063c334cd20146100e3578063f3b52855146100de578063f495be0b146100d95763fe770099146100d4575f80fd5b61052e565b610505565b6104dc565b6104bf565b6104a2565b610345565b610329565b6102b1565b61023a565b610214565b6101f7565b6101d1565b6101b1565b610194565b610177565b61014e565b3461014a575f36600319011261014a5760206001600160401b0360075416604051908152f35b5f80fd5b3461014a575f36600319011261014a5760206001600160401b0360015460401c16604051908152f35b3461014a575f36600319011261014a576020600454604051908152f35b3461014a575f36600319011261014a576020600954604051908152f35b3461014a575f36600319011261014a57602060075460c01c604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360085416604051908152f35b3461014a575f36600319011261014a576020600254604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360015416604051908152f35b3461014a575f36600319011261014a576003546040516001600160a01b039091168152602090f35b600435906001600160a01b038216820361014a57565b60206040818301928281528451809452019201905f5b81811061029b5750505090565b825184526020938401939092019160010161028e565b3461014a57604036600319011261014a576102ca610262565b6024356001600160401b03811161014a573660238201121561014a5780600401356001600160401b03811161014a573660248260051b8401011161014a57610325926024610319930190610655565b60405191829182610278565b0390f35b3461014a575f36600319011261014a5760205f54604051908152f35b3461014a57604036600319011261014a5761035e610262565b3360016007609a1b01141580610491575b80610480575b61041557600754604051631e7d027560e31b81526001600160a01b03909216600483015260248035908301526001600160401b0316604482015260208160648160046007609a1b015afa801561041057610325915f916103e1575b506040519081529081906020820190565b610403915060203d602011610409575b6103fb8183610742565b8101906107f6565b5f6103d0565b503d6103f1565b6107eb565b60405162461bcd60e51b815260206004820152603b60248201527f54656d706f53746174653a206f6e6c79207a6f6e652073797374656d20636f6e60448201527f7472616374732063616e20726561642054656d706f20737461746500000000006064820152608490fd5b503360036007609a1b011415610375565b503360026007609a1b01141561036f565b3461014a575f36600319011261014a576020600554604051908152f35b3461014a575f36600319011261014a576020600654604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360075460401c16604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360075460801c16604051908152f35b3461014a57602036600319011261014a576004356001600160401b03811161014a573660238201121561014a578060040135906001600160401b03821161014a57366024838301011161014a576007609a1b193301610646576105b26105ad5f54926105a26007546001600160401b031690565b946024369201610805565b6108c6565b60025403610637576001600160401b036105ec6105e06105da6007546001600160401b031690565b9361085e565b6001600160401b031690565b9116908103610628575f546004546040519081527fdd85219569c3c880f014955916f426d1ca039714b59ce33e24f151f155ac26b990602090a3005b631391e11b60e21b5f5260045ffd5b63591c836760e01b5f5260045ffd5b6303300c7360e31b5f5260045ffd5b91903360016007609a1b0114158061071d575b8061070c575b61041557600754604051632593f8c960e01b81526001600160a01b03909416600485015260606024850152606484018390526001600160401b03166001600160fb1b03831161014a578380926084925f9560051b8092858501376044830152810103018160046007609a1b015afa908115610410575f916106ed575090565b61070991503d805f833e6107018183610742565b810190610768565b90565b503360036007609a1b01141561066e565b503360026007609a1b011415610668565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761076357604052565b61072e565b60208183031261014a578051906001600160401b03821161014a57019080601f8301121561014a578151916001600160401b038311610763578260051b90604051936107b76020840186610742565b845260208085019282010192831161014a57602001905b8282106107db5750505090565b81518152602091820191016107ce565b6040513d5f823e3d90fd5b9081602091031261014a575190565b9291926001600160401b038211610763576040519161082e601f8201601f191660200184610742565b82948184528183011161014a578281602093845f960137010152565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b036001911601906001600160401b03821161087c57565b61084a565b906001820180921161087c57565b600101908160011161087c57565b906021820180921161087c57565b906015820180921161087c57565b9190820180921161087c57565b805160208201205f556108d881610c28565b80915015610ba85761098b61095a61091c836109166108fa6109939688610dd1565b6001600160401b03166001600160401b03196001541617600155565b85610ea6565b905061095461092b8287610dd1565b67ffffffffffffffff60401b6001549160401b169067ffffffffffffffff60401b191617600155565b84610ea6565b90506109856109698286610dd1565b6001600160401b03166001600160401b03196008541617600855565b83610ea6565b905082610d0e565b91908215610ba857610b77610b6f610b5b610b53610b1f610add610aa5610a74610a6c610a648b610a5e610a598f610a3c610a286109f16109e9846109e36109de610a50978b611020565b600255565b88610ea6565b905087610ea6565b9050610a22610a0082896110f0565b60018060a01b03166bffffffffffffffffffffffff60a01b6003541617600355565b86610ea6565b9050610916610a378288611020565b600455565b9050610954610a4b8287611020565b600555565b93849150611020565b600655565b8c610ea6565b90508b610ea6565b90508a610ea6565b9050610a9f610a83828c610dd1565b6001600160401b03166001600160401b03196007541617600755565b89610ea6565b90506109e3610ab4828b610dd1565b67ffffffffffffffff60401b6007549160401b169067ffffffffffffffff60401b191617600755565b9050610b19610aec828a610dd1565b6007805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b87610ea6565b9050610a22610b2e8289610dd1565b600780546001600160c01b031660c09290921b6001600160c01b031916919091179055565b905085610ea6565b9050610954610b6a8287611020565b600955565b905083610ea6565b9050905b610b8581856108b9565b821015610ba257610b99610b859284610ea6565b90509150610b7b565b50505050565b6305787a5560e41b5f5260045ffd5b908151811015610bc8570160200190565b634e487b7160e01b5f52603260045260245ffd5b60ff60f6199116019060ff821161087c57565b60ff60bf199116019060ff821161087c57565b60ff607f199116019060ff821161087c57565b60ff60b6199116019060ff821161087c57565b805115610d0757610c53610c4d610c3f5f84610bb7565b516001600160f81b03191690565b60f81c90565b9060ff821660bf8111610c69575050505f905f90565b60f710610c8d5750610c7d610c8391610bef565b60ff1690565b906107095f610881565b9190610c7d610c9b91610bdc565b610cad81610ca85f610881565b6108b9565b835110610cff575f925f905b828210610ccf57505061070990610ca85f610881565b909360019060081b610cf6610c7d610c4d610c3f610cf08a610ca85f610881565b87610bb7565b17940190610cb9565b505f91508190565b505f905f90565b9190918051831015610cff57610d2a610c4d610c3f8584610bb7565b9060ff821660bf8111610d425750505090505f905f90565b60f710610d5f5750610d59610c7d61070992610bef565b92610881565b9290610c7d610d6d91610bdc565b90610d7b82610ca883610881565b845110610dc7575f935f905b838210610d9d57505090610ca861070992610881565b909460019060081b610dbe610c7d610c4d610c3f610cf08b610ca88a610881565b17950190610d87565b505090505f905f90565b8051821015610ba857610dea610c4d610c3f8484610bb7565b60ff81169290607f8411610dfe5750505090565b90919392608081145f14610e1457505f93505050565b60818110159081610e9a575b5015610ba857610c7d610e3291610c02565b90610e4082610ca883610881565b845110610ba85792905f935f925b828410610e5b5750505050565b90919294610e7660019167ffffffffffffff009060081b1690565b610e8f610c7d610c4d610c3f610cf08b610ca88a610881565b179501929190610e4e565b6088915011155f610e20565b9190918051831015610ba857610ec2610c4d610c3f8584610bb7565b9060ff8216607f8111610ee15750505090610edc90610881565b600191565b60b78111610f0c575050610efa610c7d61070992610c02565b610ca8610f068261088f565b94610881565b60bf8111610f78575090610c7d610f2291610c15565b5f915f905b828210610f4e57505090610ca882610ca8610f4884610ca86107099761088f565b96610881565b909260019060081b610f6f610c7d610c4d610c3f610cf089610ca88d610881565b17930190610f27565b60f710610f8f5750610efa610c7d61070992610bef565b90610c7d610f9c91610bdc565b5f915f905b828210610fc257505090610ca882610ca8610f4884610ca86107099761088f565b909260019060081b610fe3610c7d610c4d610c3f610cf089610ca88d610881565b17930190610fa1565b602003906020821161087c57565b5f1981019190821161087c57565b600381901b91906001600160fd1b0381160361087c57565b908151811015610ba85761103a610c4d610c3f8385610bb7565b60ff81169060a082036110615750506110528161089d565b825110610ba857016021015190565b909290607f84116110725750505090565b909192608081101590816110e4575b5015610ba857610c7d61109391610c02565b91826110a0575050505f90565b60208311610ba8576110b583610ca883610881565b825110610ba8576110d96110d460216001936110df9501015194610fec565b611008565b1b610ffa565b191690565b60b7915011155f611081565b908151811015610ba85760ff61110c610c4d610c3f8486610bb7565b1660948103611131575061111f816108ab565b825110610ba857016021015160601c90565b608014159150610ba89050575f9056fea2646970667358221220edf4c2545437da93d3b806c70cbb2dec6940eaf8cf99e5dbda66a3e0192368b064736f6c63430008210033", + "code": "0x60806040526004361015610011575f80fd5b5f3560e01c80631d04645f146101245780632245d0831461011f5780632e224dee1461011a5780633d7a27611461011557806346903867146101105780634732f8bb1461010b57806352d922a51461010657806358c3659914610101578063615cf854146100fc5780636aba6931146100f757806380a4cbc8146100f257806381e3da6b146100ed5780639a7361eb146100e8578063c334cd20146100e3578063f3b52855146100de578063f495be0b146100d95763fe770099146100d4575f80fd5b61052e565b610505565b6104dc565b6104bf565b6104a2565b610345565b610329565b6102b1565b61023a565b610214565b6101f7565b6101d1565b6101b1565b610194565b610177565b61014e565b3461014a575f36600319011261014a5760206001600160401b0360075416604051908152f35b5f80fd5b3461014a575f36600319011261014a5760206001600160401b0360015460401c16604051908152f35b3461014a575f36600319011261014a576020600454604051908152f35b3461014a575f36600319011261014a576020600954604051908152f35b3461014a575f36600319011261014a57602060075460c01c604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360085416604051908152f35b3461014a575f36600319011261014a576020600254604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360015416604051908152f35b3461014a575f36600319011261014a576003546040516001600160a01b039091168152602090f35b600435906001600160a01b038216820361014a57565b60206040818301928281528451809452019201905f5b81811061029b5750505090565b825184526020938401939092019160010161028e565b3461014a57604036600319011261014a576102ca610262565b6024356001600160401b03811161014a573660238201121561014a5780600401356001600160401b03811161014a573660248260051b8401011161014a57610325926024610319930190610655565b60405191829182610278565b0390f35b3461014a575f36600319011261014a5760205f54604051908152f35b3461014a57604036600319011261014a5761035e610262565b3360016007609a1b01141580610491575b80610480575b61041557600754604051631e7d027560e31b81526001600160a01b03909216600483015260248035908301526001600160401b0316604482015260208160648160046007609a1b015afa801561041057610325915f916103e1575b506040519081529081906020820190565b610403915060203d602011610409575b6103fb8183610742565b8101906107f6565b5f6103d0565b503d6103f1565b6107eb565b60405162461bcd60e51b815260206004820152603b60248201527f54656d706f53746174653a206f6e6c79207a6f6e652073797374656d20636f6e60448201527f7472616374732063616e20726561642054656d706f20737461746500000000006064820152608490fd5b503360036007609a1b011415610375565b503360026007609a1b01141561036f565b3461014a575f36600319011261014a576020600554604051908152f35b3461014a575f36600319011261014a576020600654604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360075460401c16604051908152f35b3461014a575f36600319011261014a5760206001600160401b0360075460801c16604051908152f35b3461014a57602036600319011261014a576004356001600160401b03811161014a573660238201121561014a578060040135906001600160401b03821161014a57366024838301011161014a576007609a1b193301610646576105b26105ad5f54926105a26007546001600160401b031690565b946024369201610805565b6108c6565b60025403610637576001600160401b036105ec6105e06105da6007546001600160401b031690565b9361085e565b6001600160401b031690565b9116908103610628575f546004546040519081527fdd85219569c3c880f014955916f426d1ca039714b59ce33e24f151f155ac26b990602090a3005b631391e11b60e21b5f5260045ffd5b63591c836760e01b5f5260045ffd5b6303300c7360e31b5f5260045ffd5b91903360016007609a1b0114158061071d575b8061070c575b61041557600754604051632593f8c960e01b81526001600160a01b03909416600485015260606024850152606484018390526001600160401b03166001600160fb1b03831161014a578380926084925f9560051b8092858501376044830152810103018160046007609a1b015afa908115610410575f916106ed575090565b61070991503d805f833e6107018183610742565b810190610768565b90565b503360036007609a1b01141561066e565b503360026007609a1b011415610668565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761076357604052565b61072e565b60208183031261014a578051906001600160401b03821161014a57019080601f8301121561014a578151916001600160401b038311610763578260051b90604051936107b76020840186610742565b845260208085019282010192831161014a57602001905b8282106107db5750505090565b81518152602091820191016107ce565b6040513d5f823e3d90fd5b9081602091031261014a575190565b9291926001600160401b038211610763576040519161082e601f8201601f191660200184610742565b82948184528183011161014a578281602093845f960137010152565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b036001911601906001600160401b03821161087c57565b61084a565b906001820180921161087c57565b600101908160011161087c57565b906021820180921161087c57565b906015820180921161087c57565b9190820180921161087c57565b805160208201205f556108d881610c28565b80915015610ba85761098b61095a61091c836109166108fa6109939688610dd1565b6001600160401b03166001600160401b03196001541617600155565b85610ea6565b905061095461092b8287610dd1565b67ffffffffffffffff60401b6001549160401b169067ffffffffffffffff60401b191617600155565b84610ea6565b90506109856109698286610dd1565b6001600160401b03166001600160401b03196008541617600855565b83610ea6565b905082610d0e565b91908215610ba857610b77610b6f610b5b610b53610b1f610add610aa5610a74610a6c610a648b610a5e610a598f610a3c610a286109f16109e9846109e36109de610a50978b611020565b600255565b88610ea6565b905087610ea6565b9050610a22610a0082896110f0565b60018060a01b03166bffffffffffffffffffffffff60a01b6003541617600355565b86610ea6565b9050610916610a378288611020565b600455565b9050610954610a4b8287611020565b600555565b93849150611020565b600655565b8c610ea6565b90508b610ea6565b90508a610ea6565b9050610a9f610a83828c610dd1565b6001600160401b03166001600160401b03196007541617600755565b89610ea6565b90506109e3610ab4828b610dd1565b67ffffffffffffffff60401b6007549160401b169067ffffffffffffffff60401b191617600755565b9050610b19610aec828a610dd1565b6007805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b87610ea6565b9050610a22610b2e8289610dd1565b600780546001600160c01b031660c09290921b6001600160c01b031916919091179055565b905085610ea6565b9050610954610b6a8287611020565b600955565b905083610ea6565b9050905b610b8581856108b9565b821015610ba257610b99610b859284610ea6565b90509150610b7b565b50505050565b6305787a5560e41b5f5260045ffd5b908151811015610bc8570160200190565b634e487b7160e01b5f52603260045260245ffd5b60ff60f6199116019060ff821161087c57565b60ff60bf199116019060ff821161087c57565b60ff607f199116019060ff821161087c57565b60ff60b6199116019060ff821161087c57565b805115610d0757610c53610c4d610c3f5f84610bb7565b516001600160f81b03191690565b60f81c90565b9060ff821660bf8111610c69575050505f905f90565b60f710610c8d5750610c7d610c8391610bef565b60ff1690565b906107095f610881565b9190610c7d610c9b91610bdc565b610cad81610ca85f610881565b6108b9565b835110610cff575f925f905b828210610ccf57505061070990610ca85f610881565b909360019060081b610cf6610c7d610c4d610c3f610cf08a610ca85f610881565b87610bb7565b17940190610cb9565b505f91508190565b505f905f90565b9190918051831015610cff57610d2a610c4d610c3f8584610bb7565b9060ff821660bf8111610d425750505090505f905f90565b60f710610d5f5750610d59610c7d61070992610bef565b92610881565b9290610c7d610d6d91610bdc565b90610d7b82610ca883610881565b845110610dc7575f935f905b838210610d9d57505090610ca861070992610881565b909460019060081b610dbe610c7d610c4d610c3f610cf08b610ca88a610881565b17950190610d87565b505090505f905f90565b8051821015610ba857610dea610c4d610c3f8484610bb7565b60ff81169290607f8411610dfe5750505090565b90919392608081145f14610e1457505f93505050565b60818110159081610e9a575b5015610ba857610c7d610e3291610c02565b90610e4082610ca883610881565b845110610ba85792905f935f925b828410610e5b5750505050565b90919294610e7660019167ffffffffffffff009060081b1690565b610e8f610c7d610c4d610c3f610cf08b610ca88a610881565b179501929190610e4e565b6088915011155f610e20565b9190918051831015610ba857610ec2610c4d610c3f8584610bb7565b9060ff8216607f8111610ee15750505090610edc90610881565b600191565b60b78111610f0c575050610efa610c7d61070992610c02565b610ca8610f068261088f565b94610881565b60bf8111610f78575090610c7d610f2291610c15565b5f915f905b828210610f4e57505090610ca882610ca8610f4884610ca86107099761088f565b96610881565b909260019060081b610f6f610c7d610c4d610c3f610cf089610ca88d610881565b17930190610f27565b60f710610f8f5750610efa610c7d61070992610bef565b90610c7d610f9c91610bdc565b5f915f905b828210610fc257505090610ca882610ca8610f4884610ca86107099761088f565b909260019060081b610fe3610c7d610c4d610c3f610cf089610ca88d610881565b17930190610fa1565b602003906020821161087c57565b5f1981019190821161087c57565b600381901b91906001600160fd1b0381160361087c57565b908151811015610ba85761103a610c4d610c3f8385610bb7565b60ff81169060a082036110615750506110528161089d565b825110610ba857016021015190565b909290607f84116110725750505090565b909192608081101590816110e4575b5015610ba857610c7d61109391610c02565b91826110a0575050505f90565b60208311610ba8576110b583610ca883610881565b825110610ba8576110d96110d460216001936110df9501015194610fec565b611008565b1b610ffa565b191690565b60b7915011155f611081565b908151811015610ba85760ff61110c610c4d610c3f8486610bb7565b1660948103611131575061111f816108ab565b825110610ba857016021015160601c90565b608014159150610ba89050575f9056fea26469706673582212208176eb33b7f0b8592debc001ddf6b6df2c01cb16d05406fc42c47090b866db1d64736f6c634300081e0033", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xb049644b1d5a0ec9d785dd48f95099e0f566112084acb1ba0814112209b432a1", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -58,17 +58,17 @@ "0x1c00000000000000000000000000000000000001": { "nonce": "0x1", "balance": "0x0", - "code": "0x60806040526004361015610011575f80fd5b5f3560e01c80631fbb25ad146100745780632d4884821461006f57806379502c551461006a57806382648c3b14610065578063a21de6d9146100605763d01e8d311461005b575f80fd5b6101f0565b61014c565b610130565b6100ec565b6100c6565b346100b8575f3660031901126100b8577f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03166080908152602090f35b5f80fd5b5f9103126100b857565b346100b8575f3660031901126100b85760206001600160401b0360015416604051908152f35b346100b8575f3660031901126100b8576040517f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03168152602090f35b346100b8575f3660031901126100b85760205f54604051908152f35b346100b8575f3660031901126100b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b9181601f840112156100b8578235916001600160401b0383116100b8576020808501948460051b0101116100b857565b9181601f840112156100b8578235916001600160401b0383116100b85760208085019460c085020101116100b857565b346100b85760803660031901126100b8576004356001600160401b0381116100b857366023820112156100b8578060040135906001600160401b0382116100b85736602483830101116100b8576024356001600160401b0381116100b85761025c903690600401610190565b6044929192356001600160401b0381116100b85761027e9036906004016101c0565b91606435946001600160401b0386116100b8576102ae966102a56024973690600401610190565b979096016109ae565b005b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b038211176102df57604052565b6102b0565b90601f801991011681019081106001600160401b038211176102df57604052565b6001600160a01b038116036100b857565b908160209103126100b8575161032b81610305565b90565b6040513d5f823e3d90fd5b908060209392818452848401375f828201840152601f01601f1916010190565b91602061032b938181520191610339565b634e487b7160e01b5f52603260045260245ffd5b91908110156103a05760051b81013590607e19813603018212156100b8570190565b61036a565b3561032b81610305565b903590601e19813603018212156100b857018035906001600160401b0382116100b8576020019181360383136100b857565b95939161040d9061041b9461032b99979360018060a01b03168952608060208a01526080890191610339565b918683036040880152610339565b926060818503910152610339565b9492909361044761032b979561045594606089526060890191610339565b918683036020880152610339565b926040818503910152610339565b91908110156103a05760051b81013590603e19813603018212156100b8570190565b6002111561048f57565b634e487b7160e01b5f52602160045260245ffd5b3560028110156100b85790565b35906001600160801b03821682036100b857565b60ff8116036100b857565b6001600160401b0381116102df57601f01601f191660200190565b35906001600160a01b0319821682036100b857565b35906001600160801b0319821682036100b857565b919060a0838203126100b8576040519061052d826102c4565b8193803583526020810135610541816104c4565b602084015260408101356001600160401b0381116100b857810182601f820112156100b857803591610572836104cf565b9361058060405195866102e4565b838552602084840101116100b8576080935f6020856105c19682899701838601378301015260408601526105b6606082016104ea565b6060860152016104ff565b910152565b6020818303126100b8578035906001600160401b0382116100b8570160a0818303126100b857604051916105f9836102c4565b813561060481610305565b8352602082013561061481610305565b6020840152610625604083016104b0565b60408401526060820135606084015260808201356001600160401b0381116100b8576106519201610514565b608082015290565b634e487b7160e01b5f52601160045260245ffd5b5f19811461067b5760010190565b610659565b91908110156103a05760c0020190565b3561032b816104c4565b519081151582036100b857565b908160209103126100b85761032b9061069a565b604051906106ca6040836102e4565b600d82526c65636965732d6165732d6b657960981b6020830152565b91906040838203126100b85782516001600160401b0381116100b857830181601f820112156100b85780519161071b836104cf565b9061072960405192836102e4565b838252602084840101116100b8575f60208461032b95828096018386015e83010152930161069a565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b926107ac9060809360209397969786526bffffffffffffffffffffffff60a01b168386015260a0604086015260a0850190610752565b83810360608501525f815201936001600160801b031916910152565b90600282101561048f5752565b92919060806040916107e88660016107c8565b6060602087015260018060a01b03815116606087015260018060a01b03602082015116828701526001600160801b03838201511660a0870152606081015160c0870152015160a060e0860152805161010086015260ff6020820151166101208601526108648282015160a06101408801526101a0870190610752565b60608201516001600160a01b0319166101608701526080909101516001600160801b031916610180860152930152565b908160a09103126100b8576080604051916108ae836102c4565b80356108b981610305565b835260208101356108c981610305565b602084015260408101356108dc81610305565b60408401526108ed606082016104b0565b60608401520135608082015290565b60c09093929193608060e0820195610914835f6107c8565b80516001600160a01b039081166020858101919091528201518116604080860191909152820151166060808501919091528101516001600160801b031682840152015160a08201520152565b908160209103126100b8575190565b906001600160401b03809116911601906001600160401b03821161067b57565b908160209103126100b857516001600160401b03811681036100b85790565b9591949392969033151580611499575b61148a577f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b031696873b156100b85760405163fe77009960e01b8152915f9183918291610a16919060048401610359565b0381838b5af18015610bde57611476575b505f9492945b81811061135b575050505f54925f915f915b878310610c445750505003610c35576040516381e3da6b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166004808301919091526024820152602081604481865afa8015610bde57610c18575b50805f55610aee610ad26001600160401b038516610acd6001546001600160401b031690565b61096f565b6001600160401b03166001600160401b03196001541617600155565b604051631014997960e31b815291602083600481845afa928315610bde575f93610be3575b50602060049160405192838092631d04645f60e01b82525afa8015610bde577fd2d2bf1e295f62cd08f0f0ab45818efeaba78b58310526f7b7e9686b8aeded1a926001600160401b03925f92610ba9575b50610ba490610b7b6001546001600160401b031690565b6040805198895260208901929092526001600160401b0316908701529116939081906060820190565b0390a3565b610ba4919250610bd09060203d602011610bd7575b610bc881836102e4565b81019061098f565b9190610b64565b503d610bbe565b61032e565b6004919350610c09602091823d8411610c11575b610c0181836102e4565b810190610960565b939150610b13565b503d610bf7565b610c309060203d602011610c1157610c0181836102e4565b610aa7565b6361aba18160e11b5f5260045ffd5b909194610c52868985610463565b610c5b816104a3565b610c6481610485565b610e1957610c79816020610c819301906103af565b810190610894565b90604051610ca681610c98602082019486866108fc565b03601f1981018352826102e4565b5190208151909690610cce90610cc2906001600160a01b031681565b6001600160a01b031690565b6040830180519091906001600160a01b0316906060850191610cf783516001600160801b031690565b823b156100b8576040516340c10f1960e01b81526001600160a01b039290921660048301526001600160801b03166024820152905f908290604490829084905af18015610bde576001958b927fd5277bc9597c7da3fab9cdbba4de6005f48b9eb7389cf2389c4ea9eea3172c2192610dff575b506020810151610d8b906001600160a01b031695516001600160a01b031690565b8151610df390608090610db0906001600160a01b03165b97516001600160801b031690565b930151604080516001600160a01b0390981688526001600160801b0390941660208801529286019290925260a088901b8890039081169516939081906060820190565b0390a45b019190610a3f565b80610e0d5f610e13936102e4565b806100bc565b5f610d6a565b610e2d816020610e359399949901906103af565b8101906105c6565b908585101561134c57610e52610e4a8661066d565b958785610680565b60608301610e608151611559565b9160808601926020608086610ee68751610e7f85825192015160ff1690565b95833598610e8e878601610690565b604051635f8a996960e01b8152600481019490945260ff9889166024850152604484018b905288166064840152608483015290951660a48601529101803560c48501526020013560e484015282908190610104820190565b0381731c000000000000000000000000000000000001005afa908115610bde575f9161131e575b501561130f57518251516040516bffffffffffffffffffffffff197f000000000000000000000000000000000000000000000000000000000000000060601b166020820152603481019290925260548083019190915281525f91610f859190610f776074836102e4565b610f7f6106bb565b906116ca565b915160608101519092906001600160a01b03191690610fd2610fb7608060408701519601516001600160801b03191690565b60405163f4a7eb1360e01b8152958694859460048601610776565b0381731c000000000000000000000000000000000001015afa8015610bde575f915f916112eb575b50806112e0575b156112d85761100f90611736565b9061101f610cc2604085016103a5565b6001600160a01b039091161490816112ca575b50975b60405161104b81610c98602082019488866107d5565b519020976111855750815161106a90610cc2906001600160a01b031681565b602083018051909391906001600160a01b031691604081019261109484516001600160801b031690565b833b156100b8576040516340c10f1960e01b81526001600160a01b039290921660048301526001600160801b03166024820152915f908390604490829084905af1908115610bde5761113b61112d61111f6001988e967f95705d99ac13cf82894fd274cd871942e6f301c98c186271337e8fedbbb9d7ea96611171575b50516001600160a01b031690565b92516001600160a01b031690565b94516001600160801b031690565b604080516001600160a01b039690961686526001600160801b0391909116602086015260a087901b8790039190911693a3610df7565b80610e0d5f61117f936102e4565b5f611111565b825161119b90610cc2906001600160a01b031681565b9060408101916111aa836103a5565b9160408601926111c184516001600160801b031690565b833b156100b8576040516340c10f1960e01b81526001600160a01b039290921660048301526001600160801b03166024820152915f908390604490829084905af1908115610bde576001968c937ffc236d1b4402e76c2b0a882db36ad3a6fb0f5b6b7edc8ae317d993f10434c436936112b6575b506112ae606061126b610da261125d611257602087015160018060a01b031690565b9a6103a5565b94516001600160a01b031690565b604080516001600160a01b0390991689526001600160801b0390911660208901529301359286019290925260a088901b8890039081169516939081906060820190565b0390a4610df7565b80610e0d5f6112c4936102e4565b5f611235565b90506060820135145f611032565b505f97611035565b506040815114611001565b905061130991503d805f833e61130181836102e4565b8101906106e6565b5f610ffa565b63fb1f4a4960e01b5f5260045ffd5b61133f915060203d8111611345575b61133781836102e4565b8101906106a7565b5f610f0d565b503d61132d565b6351de8c1f60e01b5f5260045ffd5b61136981838598969861037e565b90611373826103a5565b91602081019061138382826103af565b9092604083019361139485856103af565b91909760608601986113a68a886103af565b9061083f60921b3b156100b8575f956113d493604051998a9788976374ae5b3760e11b8952600489016103e1565b03818361083f60921b5af18015610bde576001967f4ac4dcc08b0c26c3fb6b58c64c1392b7934b1ce6b0382a5986ea5c3de795e053946114379461145693611462575b5061143f61142e611427836103a5565b95836103af565b969098836103af565b9390926103af565b9290916040519687968c8060a01b03169987610429565b0390a201949294610a2d565b80610e0d5f611470936102e4565b5f611417565b80610e0d5f611484936102e4565b5f610a27565b63bb62587160e01b5f5260045ffd5b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610bde575f916114f9575b506001600160a01b03163314156109be565b61151b915060203d602011611521575b61151381836102e4565b810190610316565b5f6114e7565b503d611509565b908160011b918083046002149015171561067b57565b906001820180921161067b57565b9190820180921161067b57565b61158a90611584604051602081019061157b81610c9884906006602083019252565b51902091611528565b9061154c565b906116136115978361153e565b6040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000818116600484015260248301969096527f0000000000000000000000001c0000000000000000000000000000000000000016949092909190602090849081906044820190565b0381885afa928315610bde575f93611697575b50821561130f576040516381e3da6b60e01b81526001600160a01b03929092166004830152602482015292602090849060449082905afa928315610bde575f93611673575b509160ff1690565b60ff9193506116909060203d602011610c1157610c0181836102e4565b929061166b565b6116b191935060203d602011610c1157610c0181836102e4565b915f611626565b805191908290602001825e015f815290565b9161171e60016116f861032b9561170995604051916020830152602082526116f36040836102e4565b61177f565b9260405194859160208301906116b8565b8260f81b815203601e198101855201836102e4565b604051906020820152602081526116f36040826102e4565b9081516040810361175257506034602083015160601c92015190565b633fbbeba160e21b5f52600452604060245260445ffd5b61032b93926040928252602082015201906116b8565b5f908051604081115f1461188b57505f6117a1602092604051918280926116b8565b039060025afa15610bde5760205f61181c610c986118108351965b6040519283917f363636363636363636363636363636363636363636363636363636363636363689187f36363636363636363636363636363636363636363636363636363636363636368b18898501611769565b604051918280926116b8565b039060025afa15610bde5761187b7f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c6118105f93610c986020968651908560405196879518911889850191606093918352602083015260408201520190565b039060025afa15610bde575f5190565b60208083015194908211935091600184146118fa57505f925b602082106118e4575b60408210166118ca575b505f61181c610c986118106020946117bc565b600160409190910360031b1b5f190119909116905f6118b7565b935f1960018360200360031b1b011916936118ad565b60400151926118a456fea2646970667358221220f16dbd2f7da7fd90e61eb54c05c7184cb79b274f442504ec67305348da4ca56a64736f6c63430008210033" + "code": "0x60806040526004361015610011575f80fd5b5f3560e01c80631fbb25ad146100845780632d4884821461007f57806379502c551461007a57806382648c3b14610075578063a21de6d914610070578063ce11e6ab1461006b5763d01e8d3114610066575f80fd5b610244565b6101a0565b61015c565b610140565b6100fc565b6100d6565b346100c8575f3660031901126100c8577f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03166080908152602090f35b5f80fd5b5f9103126100c857565b346100c8575f3660031901126100c85760206001600160401b0360015416604051908152f35b346100c8575f3660031901126100c8576040517f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03168152602090f35b346100c8575f3660031901126100c85760205f54604051908152f35b346100c8575f3660031901126100c8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100c8575f3660031901126100c8576040517f0000000000000000000000001c000000000000000000000000000000000000026001600160a01b03168152602090f35b9181601f840112156100c8578235916001600160401b0383116100c8576020808501948460051b0101116100c857565b9181601f840112156100c8578235916001600160401b0383116100c85760208085019460c085020101116100c857565b346100c85760803660031901126100c8576004356001600160401b0381116100c857366023820112156100c8578060040135906001600160401b0382116100c85736602483830101116100c8576024356001600160401b0381116100c8576102b09036906004016101e4565b6044929192356001600160401b0381116100c8576102d2903690600401610214565b91606435946001600160401b0386116100c857610302966102f960249736906004016101e4565b97909601610acb565b005b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b0382111761033357604052565b610304565b60c081019081106001600160401b0382111761033357604052565b90601f801991011681019081106001600160401b0382111761033357604052565b6001600160a01b038116036100c857565b908160209103126100c8575161039a81610374565b90565b6040513d5f823e3d90fd5b908060209392818452848401375f828201840152601f01601f1916010190565b91602061039a9381815201916103a8565b634e487b7160e01b5f52603260045260245ffd5b919081101561040f5760051b81013590607e19813603018212156100c8570190565b6103d9565b3561039a81610374565b903590601e19813603018212156100c857018035906001600160401b0382116100c8576020019181360383136100c857565b95939161047c9061048a9461039a99979360018060a01b03168952608060208a015260808901916103a8565b9186830360408801526103a8565b9260608185039101526103a8565b949290936104b661039a97956104c4946060895260608901916103a8565b9186830360208801526103a8565b9260408185039101526103a8565b919081101561040f5760051b81013590603e19813603018212156100c8570190565b600211156104fe57565b634e487b7160e01b5f52602160045260245ffd5b3560028110156100c85790565b359061052a82610374565b565b35906001600160801b03821682036100c857565b60ff8116036100c857565b6001600160401b03811161033357601f01601f191660200190565b35906001600160a01b0319821682036100c857565b35906001600160801b0319821682036100c857565b919060a0838203126100c857604051906105a982610318565b81938035835260208101356105bd81610540565b602084015260408101356001600160401b0381116100c857810182601f820112156100c8578035916105ee8361054b565b936105fc6040519586610353565b838552602084840101116100c8576080935f60208561063d96828997018386013783010152604086015261063260608201610566565b60608601520161057b565b910152565b6020818303126100c8578035906001600160401b0382116100c8570160c0818303126100c8576040519161067583610338565b813561068081610374565b835261068e6020830161051f565b602084015261069f6040830161052c565b6040840152606082013560608401526080820135916001600160401b0383116100c8576106d360a0926106de948301610590565b60808501520161051f565b60a082015290565b634e487b7160e01b5f52601160045260245ffd5b5f1981146107085760010190565b6106e6565b919081101561040f5760c0020190565b3561039a81610540565b519081151582036100c857565b908160209103126100c85761039a90610727565b60405190610757604083610353565b600d82526c65636965732d6165732d6b657960981b6020830152565b91906040838203126100c85782516001600160401b0381116100c857830181601f820112156100c8578051916107a88361054b565b906107b66040519283610353565b838252602084840101116100c8575f60208461039a95828096018386015e830101529301610727565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b926108399060809360209397969786526bffffffffffffffffffffffff60a01b168386015260a0604086015260a08501906107df565b83810360608501525f815201936001600160801b031916910152565b9060028210156104fe5752565b929190604090610873856001610855565b6060602086015260018060a01b03815116606086015260018060a01b0360208201511660808601526001600160801b03828201511660a0860152606081015160c086015261093c60a060808301519260c060e0890152835161012089015260ff6020850151166101408901526108f885850151836101608b01526101c08a01906107df565b60608501516bffffffffffffffffffffffff841b166101808a01526080909401516001600160801b0319166101a089015201516001600160a01b0316610100870152565b930152565b6001600160a01b0390911681526001600160801b03909116602082015260400190565b6001600160a01b0391821681526001600160801b039092166020830152909116604082015260600190565b908160c09103126100c85760a0604051916109a983610338565b80356109b481610374565b835260208101356109c481610374565b602084015260408101356109d781610374565b60408401526109e86060820161052c565b60608401526080810135608084015201356106de81610374565b610100810193929160e09190610a18825f610855565b60018060a01b03815116602083015260018060a01b03602082015116604083015260018060a01b0360408201511660608301526001600160801b036060820151166080830152608081015160a083015260a0600180821b039101511660c08201520152565b908160209103126100c8575190565b906001600160401b03809116911601906001600160401b03821161070857565b908160209103126100c857516001600160401b03811681036100c85790565b9591949392969033151580611afa575b611aeb577f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b031696873b156100c85760405163fe77009960e01b8152915f9183918291610b339190600484016103c8565b0381838b5af18015610cfb57611ad7575b505f9492945b8181106119bc575050505f54925f915f915b878310610d615750505003610d52576040516381e3da6b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166004808301919091526024820152602081604481865afa8015610cfb57610d35575b50805f55610c0b610bef6001600160401b038516610bea6001546001600160401b031690565b610a8c565b6001600160401b03166001600160401b03196001541617600155565b604051631014997960e31b815291602083600481845afa928315610cfb575f93610d00575b50602060049160405192838092631d04645f60e01b82525afa8015610cfb577fd2d2bf1e295f62cd08f0f0ab45818efeaba78b58310526f7b7e9686b8aeded1a926001600160401b03925f92610cc6575b50610cc190610c986001546001600160401b031690565b6040805198895260208901929092526001600160401b0316908701529116939081906060820190565b0390a3565b610cc1919250610ced9060203d602011610cf4575b610ce58183610353565b810190610aac565b9190610c81565b503d610cdb565b61039d565b6004919350610d26602091823d8411610d2e575b610d1e8183610353565b810190610a7d565b939150610c30565b503d610d14565b610d4d9060203d602011610d2e57610d1e8183610353565b610bc4565b6361aba18160e11b5f5260045ffd5b909194610d6f8689856104d2565b610d7881610512565b610d81816104f4565b61117957610d96816020610d9e93019061041e565b81019061098f565b90604051610dc381610db560208201948686610a02565b03601f198101835282610353565b5190209560a0820191610deb610ddf845160018060a01b031690565b6001600160a01b031690565b156110ab578051610e0690610ddf906001600160a01b031681565b604082018051909491906001600160a01b03166060840191610e2f83516001600160801b031690565b91813b156100c8578c92610e5c925f92836040518096819582946340c10f1960e01b845260048401610941565b03925af19081611097575b50610fdb575082516001600160a01b037f0000000000000000000000001c00000000000000000000000000000000000002811692911681516001600160801b031684519093906001600160a01b031690803b156100c857610ee2945f8094604051978895869485936338b8fb9760e21b855260048501610964565b03925af1958615610cfb57610fb58c947f3c1af70310b8c9d43b0a7207217f398e4a3114f1728987c40addb451399ac87c94600199610fc1575b506020870151610f7390610f6590610f5790610f49906001600160a01b031696516001600160a01b031690565b99516001600160a01b031690565b95516001600160801b031690565b91516001600160a01b031690565b906040519485948b8060a01b031698856001600160a01b03918216815291811660208301526001600160801b0390921660408201529116606082015260800190565b0390a35b019190610b5c565b80610fcf5f610fd593610353565b806100cc565b5f610f1c565b60208401516001969492935090917fd5277bc9597c7da3fab9cdbba4de6005f48b9eb7389cf2389c4ea9eea3172c2191611027906001600160a01b03165b95516001600160a01b031690565b815161108f9060809061104c906001600160a01b03165b97516001600160801b031690565b930151604080516001600160a01b0390981688526001600160801b0390941660208801529286019290925260a088901b8890039081169516939081906060820190565b0390a4610fb9565b80610fcf5f6110a593610353565b5f610e67565b80519092506110c490610ddf906001600160a01b031681565b6040830180519091906001600160a01b03169060608501916110ed83516001600160801b031690565b823b156100c857611117925f92836040518096819582946340c10f1960e01b845260048401610941565b03925af18015610cfb576001958b927fd5277bc9597c7da3fab9cdbba4de6005f48b9eb7389cf2389c4ea9eea3172c2192611165575b506020810151611027906001600160a01b0316611019565b80610fcf5f61117393610353565b5f61114d565b61118d81602061119593999499019061041e565b810190610642565b90858510156119ad576111b26111aa866106fa565b95878561070d565b606083016111c08151611bba565b916080860192602060808661124687516111df85825192015160ff1690565b958335986111ee87860161071d565b604051635f8a996960e01b8152600481019490945260ff9889166024850152604484018b905288166064840152608483015290951660a48601529101803560c48501526020013560e484015282908190610104820190565b0381731c000000000000000000000000000000000001005afa908115610cfb575f9161197f575b501561197057518251516040516bffffffffffffffffffffffff197f000000000000000000000000000000000000000000000000000000000000000060601b166020820152603481019290925260548083019190915281525f916112e591906112d7607483610353565b6112df610748565b90611d2b565b915160608101519092906001600160a01b03191690611332611317608060408701519601516001600160801b03191690565b60405163f4a7eb1360e01b8152958694859460048601610803565b0381731c000000000000000000000000000000000001015afa8015610cfb575f915f9161194c575b5080611941575b156119395761136f90611d97565b9061137f610ddf60408501610414565b6001600160a01b0390911614908161192b575b50975b6040516113ab81610db560208201948886610862565b5190209761162b575060a0820180516113cc906001600160a01b0316610ddf565b156115c05782516113e790610ddf906001600160a01b031681565b6020840180519094919291906001600160a01b0316604082019361141285516001600160801b031690565b91813b156100c8578c9261143f925f92836040518096819582946340c10f1960e01b845260048401610941565b03925af190816115ac575b5061156c575080516001600160a01b037f0000000000000000000000001c0000000000000000000000000000000000000281169116906114a261149486516001600160801b031690565b94516001600160a01b031690565b90803b156100c8576114ce945f8094604051978895869485936338b8fb9760e21b855260048501610964565b03925af1908115610cfb5761153861152a61151c6001988e967f95705d99ac13cf82894fd274cd871942e6f301c98c186271337e8fedbbb9d7ea96611558575b50516001600160a01b031690565b92516001600160a01b031690565b94516001600160801b031690565b90611550604051928392898060a01b03169683610941565b0390a3610fb9565b80610fcf5f61156693610353565b5f61150e565b945160019592507f95705d99ac13cf82894fd274cd871942e6f301c98c186271337e8fedbbb9d7ea91906115389061152a906001600160a01b031661151c565b80610fcf5f6115ba93610353565b5f61144a565b5081516115d790610ddf906001600160a01b031681565b602083018051909391906001600160a01b031691604081019261160184516001600160801b031690565b833b156100c8576114ce935f92836040518097819582946340c10f1960e01b845260048401610941565b60a083018051919391611646906001600160a01b0316610ddf565b1561185457815161166190610ddf906001600160a01b031681565b604085019461166f86610414565b90604085019261168684516001600160801b031690565b92813b156100c8578d936116b3925f92836040518096819582946340c10f1960e01b845260048401610941565b03925af19081611840575b506117ad57505082516001600160a01b037f0000000000000000000000001c00000000000000000000000000000000000002811692911681516001600160801b031684519093906001600160a01b031690803b156100c85761173a945f8094604051978895869485936338b8fb9760e21b855260048501610964565b03925af1958615610cfb576115508c947f3c1af70310b8c9d43b0a7207217f398e4a3114f1728987c40addb451399ac87c94600199611799575b506020870151610f7390610f6590610f5790610f49906001600160a01b031696610414565b80610fcf5f6117a793610353565b5f611774565b7ffc236d1b4402e76c2b0a882db36ad3a6fb0f5b6b7edc8ae317d993f10434c436919293508461108f60606117fd61103e6114946117f7602060019e9c015160018060a01b031690565b9a610414565b604080516001600160a01b0390991689526001600160801b0390911660208901529301359286019290925260a088901b8890039081169516939081906060820190565b80610fcf5f61184e93610353565b5f6116be565b50805190929061186e90610ddf906001600160a01b031681565b90604081019161187d83610414565b91604086019261189484516001600160801b031690565b833b156100c8576118be935f92836040518097819582946340c10f1960e01b845260048401610941565b03925af1908115610cfb576001968c937ffc236d1b4402e76c2b0a882db36ad3a6fb0f5b6b7edc8ae317d993f10434c43693611917575b5061108f60606117fd61103e6114946117f7602087015160018060a01b031690565b80610fcf5f61192593610353565b5f6118f5565b90506060820135145f611392565b505f97611395565b506040815114611361565b905061196a91503d805f833e6119628183610353565b810190610773565b5f61135a565b63fb1f4a4960e01b5f5260045ffd5b6119a0915060203d81116119a6575b6119988183610353565b810190610734565b5f61126d565b503d61198e565b6351de8c1f60e01b5f5260045ffd5b6119ca8183859896986103ed565b906119d482610414565b9160208101906119e4828261041e565b909260408301936119f5858561041e565b9190976060860198611a078a8861041e565b9061083f60921b3b156100c8575f95611a3593604051998a9788976374ae5b3760e11b895260048901610450565b03818361083f60921b5af18015610cfb576001967f4ac4dcc08b0c26c3fb6b58c64c1392b7934b1ce6b0382a5986ea5c3de795e05394611a9894611ab793611ac3575b50611aa0611a8f611a8883610414565b958361041e565b9690988361041e565b93909261041e565b9290916040519687968c8060a01b03169987610498565b0390a201949294610b4a565b80610fcf5f611ad193610353565b5f611a78565b80610fcf5f611ae593610353565b5f610b44565b63bb62587160e01b5f5260045ffd5b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610cfb575f91611b5a575b506001600160a01b0316331415610adb565b611b7c915060203d602011611b82575b611b748183610353565b810190610385565b5f611b48565b503d611b6a565b908160011b918083046002149015171561070857565b906001820180921161070857565b9190820180921161070857565b611beb90611be56040516020810190611bdc81610db584906006602083019252565b51902091611b89565b90611bad565b90611c74611bf883611b9f565b6040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000818116600484015260248301969096527f0000000000000000000000001c0000000000000000000000000000000000000016949092909190602090849081906044820190565b0381885afa928315610cfb575f93611cf8575b508215611970576040516381e3da6b60e01b81526001600160a01b03929092166004830152602482015292602090849060449082905afa928315610cfb575f93611cd4575b509160ff1690565b60ff919350611cf19060203d602011610d2e57610d1e8183610353565b9290611ccc565b611d1291935060203d602011610d2e57610d1e8183610353565b915f611c87565b805191908290602001825e015f815290565b91611d7f6001611d5961039a95611d6a9560405191602083015260208252611d54604083610353565b611de0565b926040519485916020830190611d19565b8260f81b815203601e19810185520183610353565b60405190602082015260208152611d54604082610353565b90815160408103611db357506034602083015160601c92015190565b633fbbeba160e21b5f52600452604060245260445ffd5b61039a9392604092825260208201520190611d19565b5f908051604081115f14611eec57505f611e0260209260405191828092611d19565b039060025afa15610cfb5760205f611e7d610db5611e718351965b6040519283917f363636363636363636363636363636363636363636363636363636363636363689187f36363636363636363636363636363636363636363636363636363636363636368b18898501611dca565b60405191828092611d19565b039060025afa15610cfb57611edc7f5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c611e715f93610db56020968651908560405196879518911889850191606093918352602083015260408201520190565b039060025afa15610cfb575f5190565b6020808301519490821193509160018414611f5b57505f925b60208210611f45575b6040821016611f2b575b505f611e7d610db5611e71602094611e1d565b600160409190910360031b1b5f190119909116905f611f18565b935f1960018360200360031b1b01191693611f0e565b6040015192611f0556fea2646970667358221220acd15a29bff784370e22974a4e5049df86722d9db8180fb8ff85d9922329f0b164736f6c634300081e0033" }, "0x1c00000000000000000000000000000000000002": { "nonce": "0x1", "balance": "0x0", - "code": "0x6080806040526004361015610012575f80fd5b5f3560e01c9081632c37826e14610776575080633406527214610751578063378fa8fa1461073657806343c3cb831461071b57806344ee09321461069157806348aa41081461063757806353a8d7391461061b578063545525f1146105fe57806379502c55146105ba57806379fa3289146104ae5780637b9c9aa41461046e578063a94cd931146103eb578063b3b200aa14610347578063b79a6c0c1461024c578063bba9282e14610224578063c9b6ca9b14610208578063ce7025e914610135578063d93af1d2146101135763f490ca96146100ed575f80fd5b3461010f575f36600319011261010f576020604051670de0b6b3a76400008152f35b5f80fd5b3461010f575f36600319011261010f57602061012d610990565b604051908152f35b3461010f57606036600319011261010f5761014e610792565b604435906001600160401b03821161010f573660238301121561010f578160040135916001600160401b03831161010f5760248360051b82010136811161010f57610198846108d0565b936101a660405195866108af565b84526024820191602085015b8284106101c857602061012d8787600435610b47565b83356001600160401b03811161010f5782013660438201121561010f576020916101fd8392369060446024820135910161094b565b8152019301926101b2565b3461010f575f36600319011261010f57602060405161c3508152f35b3461010f575f36600319011261010f5760206001600160401b035f5460801c16604051908152f35b3461010f57602036600319011261010f57600435331515806102ad575b61029e576020817f4f0c4dec68e1e774843a5fc3a522ab2a832ecfc975b9ad8a5033736d9e47f09d92600555604051908152a1005b63bb62587160e01b5f5260045ffd5b50604051630b83774760e31b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561033c575f9161030d575b506001600160a01b0316331415610269565b61032f915060203d602011610335575b61032781836108af565b8101906108e7565b826102fb565b503d61031d565b6040513d5f823e3d90fd5b3461010f5761010036600319011261010f576103616107d4565b6103696107ea565b6103716107be565b6103796107a8565b610381610800565b9060c4356001600160401b03811161010f576103a1903690600401610816565b95909360e4356001600160401b03811161010f576103e9976103d76103cd6103df933690600401610816565b989092369161094b565b96369161094b565b95606435926111e6565b005b3461010f5760e036600319011261010f576104046107d4565b61040c6107ea565b6104146107be565b61041c6107a8565b610424610800565b9060c435946001600160401b03861161010f5761045261044b6103e9973690600401610816565b369161094b565b93604051956104626020886108af565b5f8752606435926111e6565b3461010f57602036600319011261010f576004356001600160401b038116810361010f5761049d602091610906565b6001600160801b0360405191168152f35b3461010f57602036600319011261010f576004356001600160801b03811680910361010f573315158061053b575b61029e57670de0b6b3a7640000811161052c576020817f6f864cce5237e12ffc9a99fc6c59af17222c2bbb3457690cc8753ab16b5d715e926001600160801b03195f5416175f55604051908152a1005b630d62f21160e11b5f5260045ffd5b50604051630b83774760e31b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561033c575f9161059b575b506001600160a01b03163314156104dc565b6105b4915060203d6020116103355761032781836108af565b82610589565b3461010f575f36600319011261010f576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461010f575f36600319011261010f576020600554604051908152f35b3461010f575f36600319011261010f5760206040516104008152f35b3461010f575f36600319011261010f575f602060405161065681610864565b82815201526040805161066881610864565b6001600160401b0360015491828152602082600254169101908152835192835251166020820152f35b3461010f57604036600319011261010f5760206004356106af610792565b816106bf60035460045490610843565b809111610713575b506106d1826108d0565b906106df60405192836108af565b828252601f196106ee846108d0565b01925f5b848110610704575061012d9350610b47565b606084820187015285016106f2565b9150836106c7565b3461010f575f36600319011261010f57602060405160718152f35b3461010f575f36600319011261010f57602060405160218152f35b3461010f575f36600319011261010f5760206001600160801b035f5416604051908152f35b3461010f575f36600319011261010f576020905f5460c01c8152f35b602435906001600160401b038216820361010f57565b608435906001600160401b038216820361010f57565b604435906001600160801b038216820361010f57565b600435906001600160a01b038216820361010f57565b602435906001600160a01b038216820361010f57565b60a435906001600160a01b038216820361010f57565b9181601f8401121561010f578235916001600160401b03831161010f576020838186019501011161010f57565b9190820391821161085057565b634e487b7160e01b5f52601160045260245ffd5b604081019081106001600160401b0382111761087f57604052565b634e487b7160e01b5f52604160045260245ffd5b61016081019081106001600160401b0382111761087f57604052565b90601f801991011681019081106001600160401b0382111761087f57604052565b6001600160401b03811161087f5760051b60200190565b9081602091031261010f57516001600160a01b038116810361010f5790565b6001600160401b031661c350016001600160401b038111610850576001600160401b036001600160801b035f54169116026001600160801b0381169081036108505790565b9291926001600160401b03821161087f5760405191610974601f8201601f1916602001846108af565b82948184528183011161010f578281602093845f960137010152565b60045460035490818110156109ab576109a891610843565b90565b50505f90565b6003548110156109cd5760035f52600960205f20910201905f90565b634e487b7160e01b5f52603260045260245ffd5b90600182811c92168015610a0f575b60208310146109fb57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916109f0565b9060405191825f825492610a2c846109e1565b8084529360018116908115610a975750600114610a53575b50610a51925003836108af565b565b90505f9291925260205f20905f915b818310610a7b575050906020610a51928201015f610a44565b6020919350806001915483858901015201910190918492610a62565b905060209250610a5194915060ff191682840152151560051b8201015f610a44565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b5f5b828110610aeb57505050565b5f82820155600101610adf565b610b0281546109e1565b9081610b0c575050565b81601f5f9311600114610b1d575055565b81835260208320610b3a91601f0160051c84190190600101610add565b8082528160208120915555565b9092915f9333151580611167575b61029e576001600160401b0380431691160361115857600354610b7b6004548092610843565b808411611150575b508151838103611139575082610c2a575b5050505f5460018160c01c01906001600160401b038211610850576001600160c01b031660c091821b6001600160c01b031916175f81905560405184927fec4aff46c65f485f4b15e3c2edadda1d57d002995f5aa262a27c76b9a680ec1692602092911c9081908390610c0681610864565b868152015283600155806001600160401b03196002541617600255604051908152a2565b5f1994509182019190828211610850579082915b818311610df65750505080600455600354809114610c5e575b8080610b94565b5f60035580610c73575b505f6004555f610c57565b806009029060098204036108505760035f525f5b818110610c945750610c68565b6009905f817fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c8201555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d8201555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e8201555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85f8201555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8608201555f7fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f861820155610dc57fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8628201610af8565b610df07fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8638201610af8565b01610c87565b9091945f19860195861161085057610e0d866109b1565b5060405190610e1b82610893565b60018060a01b03815416825260018060a01b036001820154169260208301938452886002830154936040810194855260018060a01b0360038501541693606082019485526004810154918960808201976001600160801b038516895260a083019460801c855260058401549060c08401918252600685015493610eea60e08201946001600160401b038716865261010083019660018060a01b039060401c168752610edc6008610ecd60078b01610a19565b9961012086019a8b5201610a19565b9961014084019a8b52610843565b8d518110156109cd5760051b8d0160200151975151611132575f5b885181810361111d5750506001600160801b036001600160401b0392819260018060a01b039051169d5190516040519060208201926bffffffffffffffffffffffff199060601b168352603482015260348152610f636054826108af565b5190209a60018060a01b039051169b511696511691519251169260018060a01b039051169351946040519a6101408c018c81106001600160401b0382111761087f576040528b5260208b0198895260408b01998a5260608b0190815260808b0191825260a08b0192835260c08b0193845260e08b019485526101008b019586526101208b01968752604051998a9960208b019c60408e52600160a01b6001900390511660608c01525160808b0152600160a01b6001900390511660a08a0152516001600160801b031660c0890152516001600160801b031660e088015251610100870152516001600160401b0316610120860152600160a01b6001900390511661014085015251610160840161014090526101a0840161108291610ab9565b9051838203605f190161018085015261109b9190610ab9565b90604083015203601f19810182526110b390826108af565b519020946110c0816109b1565b61110a576008815f61110393555f60018201555f60028201555f60038201555f60048201555f60058201555f60068201556110fd60078201610af8565b01610af8565b9190610c3e565b634e487b7160e01b5f525f60045260245ffd5b63521a2d4d60e11b5f5260045260245260445ffd5b6071610f05565b8390630db2128560e11b5f5260045260245260445ffd5b92505f610b83565b631391e11b60e21b5f5260045ffd5b50604051630b83774760e31b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561033c575f916111c7575b506001600160a01b0316331415610b55565b6111e0915060203d6020116103355761032781836108af565b5f6111b5565b5f969195909491936001600160a01b0390911692831561189c5761040085511161188d57611213896118ab565b60055480611848575b506001600160801b038061122f85610906565b92169116908181016001600160801b0381116108505760405163868a2e9d60e01b8152946020866004815f60056007609a1b015af195861561033c575f96611814575b508515611805576040516323b872dd60e01b81523360048201523060248201526001600160801b0392909216604483018190526001600160a01b0390991698916020816064815f8e5af190811561033c575f916117ca575b50156117bb57883b1561010f5760405191630852cd8d60e31b835260048301525f82602481838d5af191821561033c578c926117a4575b50876040519161131083610893565b8a8352886020840198338a5260408501908152606085019d60018060a01b03169d8e8152608086019088825260a08701908a825260c08801938c85526001600160401b0360e08a0197169d8e88526101008a019687526101208a019889526101408a019a8b526003546801000000000000000081101561178a5780600161139a92016003556109b1565b9a909a61177157518a546001600160a01b03199081166001600160a01b03928316178c55915160018c0180548416918316919091179055915160028b0155915160038a01805490931691161790559051905160801b6fffffffffffffffffffffffffffffffff19166001600160801b0391909116176004860155516005850155905160068401805492516001600160e01b03199093166001600160401b039283161760409390931b68010000000000000000600160e01b031692909217909155905180516007840192909190821161175d578d9061147884546109e1565b601f811161171a575b50602091601f84116001146116b45760089594936114b5939092836115e7575b50508160011b915f199060031b1c19161790565b90555b01905180516001600160401b0381116116a0578b6114d684546109e1565b601f8111611654575b505060208c601f83116001146115f2579061150d93836115e75750508160011b915f199060031b1c19161790565b90555b8854986001600160401b038a60801c16996001600160401b038b146115d357926115be95927f348c28d1410ff29393c038fe0f1998384082e98e315624b24c04a4fa6288b9de9a999895926115ce98958d60016001600160401b0360801b910160801b16906001600160401b0360801b1916179055604051998a998a5260208a015260408901526060880152608087015260a086015260c085015261012060e0850152610120840190610ab9565b8281036101008401523396610ab9565b0390a3565b634e487b7160e01b82526011600452602482fd5b015190505f806114a1565b9192601f198416858452828420935b81811061163c5750908460019594939210611624575b505050811b019055611510565b01515f1960f88460031b161c191690555f8080611617565b92936020600181928786015181550195019301611601565b84838211611663575b506114df565b61169092528d6020812091601f850160051c9160208610611698575b50601f82910160051c039101610add565b8b5f8461165d565b91508f61167f565b634e487b7160e01b8c52604160045260248cfd5b9190601f198416858452828420935b8181106117025750916001939185600898979694106116ea575b505050811b0190556114b8565b01515f1960f88460031b161c191690555f80806116dd565b929360206001819287860151815501950193016116c3565b838111156114815761174f908584526020842090601f860160051c9060208710611755575b601f82910160051c039101610add565b5f611481565b85915061173f565b634e487b7160e01b8e52604160045260248efd5b50505050505060248f634e487b7160e01b815280600452fd5b50505050505060248f634e487b7160e01b81526041600452fd5b5f919b506117b292506108af565b895f995f611301565b6312171d8360e31b5f5260045ffd5b90506020813d6020116117fd575b816117e5602093836108af565b8101031261010f5751801515810361010f575f6112ca565b3d91506117d8565b632968ee7f60e21b5f5260045ffd5b9095506020813d602011611840575b81611830602093836108af565b8101031261010f5751945f611272565b3d9150611823565b6007544303611880575b60065490811015611871575f198114610850576001016006555f61121c565b63124ab48560e11b5f5260045ffd5b436007555f600655611852565b634b8a874d60e11b5f5260045ffd5b63c29f0c7160e01b5f5260045ffd5b80518015611903576021036118e5578051156109cd57602001516001600160f81b031916600160f91b81141590816118f4575b506118e557565b6361d0136b60e11b5f5260045ffd5b600360f81b141590505f6118de565b505056fea2646970667358221220652e7449c8658b6fc3b3333b742e8b3959d13566217fc352249d4a8ad22860c164736f6c63430008220033" + "code": "0x60806040526004361015610011575f80fd5b5f3560e01c80632c37826e14610144578063340652721461013f578063378fa8fa1461013a57806343c3cb831461013557806348aa41081461013057806353a8d7391461012b578063545525f11461012657806379502c551461012157806379fa32891461011c5780637b9c9aa414610117578063a94cd93114610112578063b3b200aa1461010d578063b79a6c0c14610108578063bba9282e14610103578063c9b6ca9b146100fe578063ce7025e9146100f9578063d93af1d2146100f4578063e2e3ee5c146100ef5763f490ca96146100ea575f80fd5b610917565b6107cd565b6107ab565b610732565b610716565b6106ee565b610610565b610578565b6104e6565b610468565b6102ea565b610264565b610247565b61022b565b6101d1565b6101b6565b61019b565b610176565b610157565b5f91031261015357565b5f80fd5b34610153575f3660031901126101535760205f5460c01c604051908152f35b34610153575f3660031901126101535760206001600160801b035f5416604051908152f35b34610153575f36600319011261015357602060405160218152f35b34610153575f36600319011261015357602060405160718152f35b34610153575f366003190112610153575f60206040516101f08161094d565b8281520152604080516102028161094d565b6001600160401b0360015491828152602082600254169101908152835192835251166020820152f35b34610153575f3660031901126101535760206040516104008152f35b34610153575f366003190112610153576020600554604051908152f35b34610153575f366003190112610153576040517f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03168152602090f35b600435906001600160801b038216820361015357565b604435906001600160801b038216820361015357565b602435906001600160801b038216820361015357565b34610153576020366003190112610153576103036102a8565b331515806103a8575b61039957670de0b6b3a76400006001600160801b0382161161038a576103858161036b7f6f864cce5237e12ffc9a99fc6c59af17222c2bbb3457690cc8753ab16b5d715e936001600160801b03166001600160801b03195f5416175f55565b6040516001600160801b0390911681529081906020820190565b0390a1005b630d62f21160e11b5f5260045ffd5b63bb62587160e01b5f5260045ffd5b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610437575f91610408575b506001600160a01b031633141561030c565b61042a915060203d602011610430575b610422818361096d565b8101906109bf565b5f6103f6565b503d610418565b6109d7565b608435906001600160401b038216820361015357565b602435906001600160401b038216820361015357565b34610153576020366003190112610153576004356001600160401b038116810361015357610497602091610a19565b6001600160801b0360405191168152f35b6001600160a01b0381160361015357565b9181601f84011215610153578235916001600160401b038311610153576020838186019501011161015357565b346101535760e036600319011261015357600435610503816104a8565b60243590610510826104a8565b6105186102be565b9160643561052461043c565b60a43591610531836104a8565b60c435956001600160401b0387116101535761055e6105576105769836906004016104b9565b3691610a79565b946040519661056e60208961096d565b5f8852611027565b005b346101535761010036600319011261015357600435610596816104a8565b6024356105a2816104a8565b6105aa6102be565b916064356105b661043c565b9060a4356105c3816104a8565b60c4356001600160401b038111610153576105e29036906004016104b9565b93909260e435976001600160401b038911610153576106086105769936906004016104b9565b989097610ac3565b34610153576020366003190112610153576004353315158061066f575b610399576103858161065f7f4f0c4dec68e1e774843a5fc3a522ab2a832ecfc975b9ad8a5033736d9e47f09d93600555565b6040519081529081906020820190565b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610437575f916106cf575b506001600160a01b031633141561062d565b6106e8915060203d60201161043057610422818361096d565b5f6106bd565b34610153575f3660031901126101535760206001600160401b035f5460801c16604051908152f35b34610153575f36600319011261015357602060405161c3508152f35b346101535760603660031901126101535760043561074e610452565b604435916001600160401b0383116101535736602384011215610153578260040135916001600160401b038311610153573660248460051b86010111610153576107a161065f9360246107a79601610aea565b9161171e565b0390f35b34610153575f3660031901126101535760206107c5610b87565b604051908152f35b34610153576060366003190112610153576004356107ea816104a8565b6107f26102d4565b906044356107ff816104a8565b33151580610898575b610399576105769261084e61085e9261083161082261098e565b6001600160a01b039096168652565b5f6020860181905260408601526001600160a01b03166060850152565b6001600160801b03166080830152565b5f60a08201525f60c08201525f60e08201525f61010082015261087f610aaf565b61012082015261088d610aaf565b610140820152610d65565b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610437575f916108f8575b506001600160a01b0316331415610808565b610911915060203d60201161043057610422818361096d565b5f6108e6565b34610153575f366003190112610153576020604051670de0b6b3a76400008152f35b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761096857604052565b610939565b90601f801991011681019081106001600160401b0382111761096857604052565b6040519061099e6101608361096d565b565b6040519061099e6101408361096d565b6040519061099e60408361096d565b9081602091031261015357516109d4816104a8565b90565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b6001600160401b036001911601906001600160401b038211610a1457565b6109e2565b6001600160401b031661c350016001600160401b038111610a14576001600160401b036001600160801b035f54169116026001600160801b038116908103610a145790565b6001600160401b03811161096857601f01601f191660200190565b929192610a8582610a5e565b91610a93604051938461096d565b829481845281830111610153578281602093845f960137010152565b60405190610abe60208361096d565b5f8252565b97610adc610ae492939495969761099e9b993691610a79565b973691610a79565b96611027565b6001600160401b038211610968578160051b9060405192610b0e602084018561096d565b835260208301918101903682116101535780925b828410610b30575050505090565b83356001600160401b03811161015357820136601f8201121561015357602091610b61839236908481359101610a79565b815201930192610b22565b5f19810191908211610a1457565b91908203918211610a1457565b6004546003549081811015610ba2578103908111610a145790565b50505f90565b634e487b7160e01b5f52603260045260245ffd5b600354811015610bd85760035f52600960205f20910201905f90565b610ba8565b8054821015610bd8575f52600960205f20910201905f90565b634e487b7160e01b5f525f60045260245ffd5b90600182811c92168015610c37575b6020831014610c2357565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610c18565b818110610c4c575050565b5f8155600101610c41565b9190601f8111610c6657505050565b61099e925f5260205f20906020601f840160051c83019310610c90575b601f0160051c0190610c41565b9091508190610c83565b91909182516001600160401b03811161096857610cc181610cbb8454610c09565b84610c57565b6020601f8211600114610d00578190610cf19394955f92610cf5575b50508160011b915f199060031b1c19161790565b9055565b015190505f80610cdd565b601f19821690610d13845f5260205f2090565b915f5b818110610d4d57509583600195969710610d35575b505050811b019055565b01515f1960f88460031b161c191690555f8080610d2b565b9192602060018192868b015181550194019201610d16565b6003546801000000000000000081101561096857806001610d8b92016003556003610bdd565b610f1357815181546001600160a01b0319166001600160a01b0390911617815561099e916008906101409060208101516001850180546001600160a01b0319166001600160a01b039092169190911790556040810151600285015560608101516003850180546001600160a01b0319166001600160a01b03909216919091179055610e7460048501610e46610e2a60808501516001600160801b031690565b82546001600160801b0319166001600160801b03909116178255565b60a08301516001600160801b031681546001600160801b031660809190911b6001600160801b031916179055565b60c08101516005850155610ef860068501610eb9610e9c60e08501516001600160401b031690565b825467ffffffffffffffff19166001600160401b03909116178255565b6101008301516001600160a01b0316815468010000000000000000600160e01b03191660409190911b68010000000000000000600160e01b0316179055565b610f0a61012082015160078601610c9a565b01519101610c9a565b610bf6565b5f198114610a145760010190565b906001600160801b03809116911601906001600160801b038211610a1457565b90816020910312610153575190565b90816020910312610153575180151581036101535790565b6001600160401b03166001600160401b038114610a145760010190565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b6001600160a01b03918216815291811660208301526001600160801b03928316604083015292909116606082015260808101929092526001600160401b039290921660a0820152911660c082015261012060e082018190526109d493919261101891840190610f8a565b91610100818403910152610f8a565b95969092949693919360018060a01b03881615611341576104008151116113325761105182611ad3565b6005546112df575b61106283610a19565b9761106d8987610f26565b60405163868a2e9d60e01b8152979094906020896004815f60056007609a1b015af1988915610437575f996112ae575b50881561129f576040516323b872dd60e01b81523360048201523060248201526001600160801b03871660448201526001600160a01b038b16906020816064815f865af1908115610437575f91611270575b501561126157803b1561015357604051630852cd8d60e31b81526001600160801b039790971660048801525f908790602490829084905af18015610437577f348c28d1410ff29393c038fe0f1998384082e98e315624b24c04a4fa6288b9de99611242976111e392611247575b5061116561098e565b6001600160a01b038d1681529033602083015260408201526001600160a01b03891660608201526001600160801b038a1660808201526001600160801b038d1660a082015260c081018390526001600160401b03841660e08201526001600160a01b0385166101008201528561012082015286610140820152610d65565b5f5460801c6001600160401b03169a61122a6111fe8d610f6d565b5f805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b6040519889986001600160401b03339e169c8a610fae565b0390a3565b806112555f61125b9361096d565b80610149565b5f61115c565b6312171d8360e31b5f5260045ffd5b611292915060203d602011611298575b61128a818361096d565b810190610f55565b5f6110ef565b503d611280565b632968ee7f60e21b5f5260045ffd5b6112d191995060203d6020116112d8575b6112c9818361096d565b810190610f46565b975f61109d565b503d6112bf565b600754430361131b575b60065460055481101561130c5761130261130791610f18565b600655565b611059565b63124ab48560e11b5f5260045ffd5b61132443600755565b61132d5f600655565b6112e9565b634b8a874d60e11b5f5260045ffd5b63c29f0c7160e01b5f5260045ffd5b91908201809211610a1457565b9060405191825f82549261137084610c09565b80845293600181169081156113d95750600114611395575b5061099e9250038361096d565b90505f9291925260205f20905f915b8183106113bd57505090602061099e928201015f611388565b60209193508060019154838589010152019101909184926113a4565b90506020925061099e94915060ff191682840152151560051b8201015f611388565b906114fb600861140961098e565b84546001600160a01b031681529360018101546001600160a01b031660208601526002810154604086015260038101546001600160a01b0316606086015261148b61147b6004830154611475611465826001600160801b031690565b6001600160801b031660808a0152565b60801c90565b6001600160801b031660a0870152565b600581015460c08601526114e36114d260068301546114c36114b3826001600160401b031690565b6001600160401b031660e08a0152565b60401c6001600160a01b031690565b6001600160a01b0316610100870152565b6114ef6007820161135d565b6101208601520161135d565b610140830152565b8051821015610bd85760209160051b010190565b604080825282516001600160a01b0316908201529291906020906115dc9080830151606087015260408101516001600160a01b0316608087015260608101516001600160801b031660a087015260808101516001600160801b031660c087015260a081015160e087015260c08101516001600160401b031661010087015260e08101516001600160a01b03166101208701526101206115c7610100830151610140808a0152610180890190610f8a565b910151868203603f1901610160880152610f8a565b930152565b6115eb8154610c09565b90816115f5575050565b81601f5f9311600114611606575055565b8183526020832061162291601f0160051c810190600101610c41565b808252602082209081548360011b9084198560031b1c191617905555565b90610f13576008815f61099e93555f60018201555f60028201555f60038201555f60048201555f60058201555f600682015561167e600782016115e1565b016115e1565b6003545f600355806116935750565b80600902906009820403610a145760035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b908101905b8181106116d6575050565b6009905f81555f60018201555f60028201555f60038201555f60048201555f60058201555f600682015561170c600782016115e1565b611718600882016115e1565b016116cb565b9092915f9333151580611a54575b610399576001600160401b03804316911603611a4557600354906117536004548093610b7a565b808411611a3d575b508051838103611a26575082611833575b5050506117a96117856117805f5460c01c90565b6109f6565b5f80546001600160c01b031660c09290921b6001600160c01b031916919091179055565b817fec4aff46c65f485f4b15e3c2edadda1d57d002995f5aa262a27c76b9a680ec1661182e6117d95f5460c01c90565b6118146117e46109b0565b8581526001600160401b038316602090910181905260018690556002805467ffffffffffffffff19169091179055565b6040516001600160401b0390911681529081906020820190565b0390a2565b5f199450916118429082611350565b91825b82811161187c5750505060045560045460035414611866575b5f808061176c565b61186e611684565b6118775f600455565b61185e565b61188581610b6c565b9561188f87610bbc565b50611899906113fb565b6118a38589610b7a565b6118ad9085611503565b5180610140830151906118bf91611b48565b8151602080840151604080860151905160609290921b6bffffffffffffffffffffffff191692820192835260348083019190915281526001600160a01b03909216939161190d60548261096d565b51902060608201519091906001600160a01b031660808201516001600160801b031660a08301516001600160801b031660c08401519160e0850151611958906001600160401b031690565b6101008601519094906001600160a01b0316956101200151966119796109a0565b6001600160a01b03909a168a5260208a01526001600160a01b031660408901526001600160801b031660608801526001600160801b0316608087015260a08601526001600160401b031660c08501526001600160a01b031660e0840152610100830152610120820152604051809160208201936119f69185611517565b03601f1981018252611a08908261096d565b51902095611a1590610bbc565b611a1e91611640565b5f1901611845565b630db2128560e11b5f52600452602483905260445ffd5b92505f61175b565b631391e11b60e21b5f5260045ffd5b50604051630b83774760e31b81526020816004817f0000000000000000000000001c000000000000000000000000000000000000036001600160a01b03165afa908115610437575f91611ab4575b506001600160a01b031633141561172c565b611acd915060203d60201161043057610422818361096d565b5f611aa2565b80518015611b4457602103611b2657805115610bd85760208101516001600160f81b031916600160f91b8114159081611b35575b50611b2657611b1c6021611b20920151611bca565b1590565b611b2657565b6361d0136b60e11b5f5260045ffd5b600360f81b141590505f611b07565b5050565b51611b71575f905b51818103611b5c575050565b63521a2d4d60e11b5f5260045260245260445ffd5b607190611b50565b3d15611ba3573d90611b8a82610a5e565b91611b98604051938461096d565b82523d5f602084013e565b606090565b602081519101519060208110611bbc575090565b5f199060200360031b1b1690565b80158015611c88575b611c77575f8091604051611c4d81611c3f602082019460076401000003d019916401000003d019906401000003d019818009090860208087528087018190526040870152606086015263800001e9600160ff1b0360808601526401000003d01960a086015260c0850190565b03601f19810183528261096d565b519060055afa611c5b611b79565b90158015611c7c575b611c7757611c73600191611ba8565b1490565b505f90565b50602081511415611c64565b506401000003d019811015611bd356fea26469706673582212201913106f0f2e3f54303679f0bbb95cc068c350efba8fda42910a66aafd53ddd364736f6c634300081e0033" }, "0x1c00000000000000000000000000000000000003": { "nonce": "0x1", "balance": "0x0", - "code": "0x6080806040526004361015610012575f80fd5b5f3560e01c9081631beb1ab814610561575080631fbb25ad1461051d5780633488ce0d146102dd5780635c1bba381461023b5780636d46e98714610193578063a21de6d91461014f5763e202d99514610069575f80fd5b34610138575f366003190112610138576040516381e3da6b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260016024830152602090829060449082907f0000000000000000000000001c00000000000000000000000000000000000000165afa8015610144575f9061010d575b6040516001600160a01b039091168152602090f35b506020813d60201161013c575b816101276020938361067c565b8101031261013857602090516100f8565b5f80fd5b3d915061011a565b6040513d5f823e3d90fd5b34610138575f366003190112610138576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610138576020366003190112610138576004356001600160a01b0381169081900361013857604051630b83774760e31b8152602081600481305afa908115610144575f916101f6575b506040516001600160a01b039091169091148152602090f35b90506020813d602011610233575b816102116020938361067c565b810103126101385751906001600160a01b0382168203610138579060206101dd565b3d9150610204565b34610138575f366003190112610138576040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f6024830152602090829060449082907f0000000000000000000000001c00000000000000000000000000000000000000165afa8015610144575f9061010d576040516001600160a01b039091168152602090f35b34610138575f366003190112610138576040516381e3da6b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152600660248401527f0000000000000000000000001c00000000000000000000000000000000000000169190602082604481865afa918215610144575f926104e9575b5081156104da576040516020810190600682526020815261038f60408261067c565b519020915f1981019081116104c6578060011b90808204600214901517156104c65782018092116104c65760018201908183116104c6576040516381e3da6b60e01b81526001600160a01b03821660048201526024810193909352602083604481875afa928315610144575f9361048e575b506040516381e3da6b60e01b81526001600160a01b03909116600482015260248101919091529160209083908180604481015b03915afa918215610144575f92610459575b5060ff6040928351928352166020820152f35b91506020823d602011610486575b816104746020938361067c565b810103126101385790519060ff610446565b3d9150610467565b919092506020823d6020116104be575b816104ab6020938361067c565b8101031261013857905191610434610401565b3d915061049e565b634e487b7160e01b5f52601160045260245ffd5b630c322fb560e31b5f5260045ffd5b9091506020813d602011610515575b816105056020938361067c565b810103126101385751908361036d565b3d91506104f8565b34610138575f366003190112610138576040517f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03168152602090f35b34610138576020366003190112610138576004356001600160a01b0381169190829003610138576105fe9181602080930191825260076040820152604081526105ab60608261067c565b5190206040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602481019190915291829081906044820190565b03817f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03165afa8015610144575f90610649575b60209060ff604051911615158152f35b506020813d602011610674575b816106636020938361067c565b810103126101385760209051610639565b3d9150610656565b90601f8019910116810190811067ffffffffffffffff82111761069e57604052565b634e487b7160e01b5f52604160045260245ffdfea2646970667358221220615455022182404b5eef598e1c4e66b9fba2ee08aa579832c0c247d1afef17a164736f6c63430008210033" + "code": "0x6080806040526004361015610012575f80fd5b5f3560e01c9081631beb1ab814610561575080631fbb25ad1461051d5780633488ce0d146102dd5780635c1bba381461023b5780636d46e98714610193578063a21de6d91461014f5763e202d99514610069575f80fd5b34610138575f366003190112610138576040516381e3da6b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260016024830152602090829060449082907f0000000000000000000000001c00000000000000000000000000000000000000165afa8015610144575f9061010d575b6040516001600160a01b039091168152602090f35b506020813d60201161013c575b816101276020938361067c565b8101031261013857602090516100f8565b5f80fd5b3d915061011a565b6040513d5f823e3d90fd5b34610138575f366003190112610138576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610138576020366003190112610138576004356001600160a01b0381169081900361013857604051630b83774760e31b8152602081600481305afa908115610144575f916101f6575b506040516001600160a01b039091169091148152602090f35b90506020813d602011610233575b816102116020938361067c565b810103126101385751906001600160a01b0382168203610138579060206101dd565b3d9150610204565b34610138575f366003190112610138576040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f6024830152602090829060449082907f0000000000000000000000001c00000000000000000000000000000000000000165afa8015610144575f9061010d576040516001600160a01b039091168152602090f35b34610138575f366003190112610138576040516381e3da6b60e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038181166004840152600660248401527f0000000000000000000000001c00000000000000000000000000000000000000169190602082604481865afa918215610144575f926104e9575b5081156104da576040516020810190600682526020815261038f60408261067c565b519020915f1981019081116104c6578060011b90808204600214901517156104c65782018092116104c65760018201908183116104c6576040516381e3da6b60e01b81526001600160a01b03821660048201526024810193909352602083604481875afa928315610144575f9361048e575b506040516381e3da6b60e01b81526001600160a01b03909116600482015260248101919091529160209083908180604481015b03915afa918215610144575f92610459575b5060ff6040928351928352166020820152f35b91506020823d602011610486575b816104746020938361067c565b810103126101385790519060ff610446565b3d9150610467565b919092506020823d6020116104be575b816104ab6020938361067c565b8101031261013857905191610434610401565b3d915061049e565b634e487b7160e01b5f52601160045260245ffd5b630c322fb560e31b5f5260045ffd5b9091506020813d602011610515575b816105056020938361067c565b810103126101385751908361036d565b3d91506104f8565b34610138575f366003190112610138576040517f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03168152602090f35b34610138576020366003190112610138576004356001600160a01b0381169190829003610138576105fe9181602080930191825260076040820152604081526105ab60608261067c565b5190206040516381e3da6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152602481019190915291829081906044820190565b03817f0000000000000000000000001c000000000000000000000000000000000000006001600160a01b03165afa8015610144575f90610649575b60209060ff604051911615158152f35b506020813d602011610674575b816106636020938361067c565b810103126101385760209051610639565b3d9150610656565b90601f8019910116810190811067ffffffffffffffff82111761069e57604052565b634e487b7160e01b5f52604160045260245ffdfea26469706673582212206d5ac24419f3c1033cf08655bb868c6e2529bc9242233a4d3b37301537d3784864736f6c634300081e0033" }, "0x1c00000000000000000000000000000000000004": { "nonce": "0x1", diff --git a/crates/tempo-zone/tests/it/deposit.rs b/crates/tempo-zone/tests/it/deposit.rs index a3f7cd083..4aae4c001 100644 --- a/crates/tempo-zone/tests/it/deposit.rs +++ b/crates/tempo-zone/tests/it/deposit.rs @@ -123,7 +123,13 @@ async fn test_l1_deposit_mints_on_zone() -> eyre::Result<()> { // Execute deposit on L1 let deposit_receipt = portal - .deposit(l1_token_address, recipient, deposit_amount, B256::ZERO) + .deposit( + l1_token_address, + recipient, + deposit_amount, + B256::ZERO, + Address::ZERO, + ) .send() .await? .get_receipt() diff --git a/crates/tempo-zone/tests/it/l1_e2e.rs b/crates/tempo-zone/tests/it/l1_e2e.rs index 5cf0ac7c9..e6f954fe9 100644 --- a/crates/tempo-zone/tests/it/l1_e2e.rs +++ b/crates/tempo-zone/tests/it/l1_e2e.rs @@ -1128,6 +1128,7 @@ async fn test_encrypted_deposit_blacklisted_recipient() -> eyre::Result<()> { nonce: alloy_primitives::FixedBytes(enc.nonce), tag: alloy_primitives::FixedBytes(enc.tag), }, + Address::ZERO, ) .send() .await? @@ -1249,7 +1250,13 @@ async fn test_blacklisted_sender_transfer_rejected() -> eyre::Result<()> { let portal = ZonePortal::new(portal_address, &dev_provider); let receipt = portal - .deposit(PATH_USD_ADDRESS, alice, deposit_amount, B256::ZERO) + .deposit( + PATH_USD_ADDRESS, + alice, + deposit_amount, + B256::ZERO, + Address::ZERO, + ) .send() .await? .get_receipt() @@ -1364,6 +1371,7 @@ async fn test_deposit_to_blacklisted_recipient_reverts_on_l1() -> eyre::Result<( blacklisted_recipient, deposit_amount, B256::ZERO, + Address::ZERO, ) .send() .await; diff --git a/crates/tempo-zone/tests/it/utils.rs b/crates/tempo-zone/tests/it/utils.rs index d8d3b33d0..6b2c61358 100644 --- a/crates/tempo-zone/tests/it/utils.rs +++ b/crates/tempo-zone/tests/it/utils.rs @@ -1988,7 +1988,13 @@ impl ZoneAccount { let portal = ZonePortal::new(self.portal_address, &self.l1_provider); let receipt = portal - .deposit(PATH_USD_ADDRESS, recipient, amount, B256::ZERO) + .deposit( + PATH_USD_ADDRESS, + recipient, + amount, + B256::ZERO, + Address::ZERO, + ) .send() .await? .get_receipt() @@ -2043,7 +2049,7 @@ impl ZoneAccount { let portal = ZonePortal::new(self.portal_address, &self.l1_provider); let receipt = portal - .deposit(token, self.address, amount, B256::ZERO) + .deposit(token, self.address, amount, B256::ZERO, Address::ZERO) .send() .await? .get_receipt() @@ -2148,6 +2154,7 @@ impl ZoneAccount { nonce: alloy_primitives::FixedBytes(enc.nonce), tag: alloy_primitives::FixedBytes(enc.tag), }, + Address::ZERO, ) .send() .await? @@ -2626,7 +2633,7 @@ impl PrivateRpcTestCtx { private_rpc_call_no_auth(&self.private_rpc_url, method, params).await } - /// Build an auth token with custom zone_id and chain_id (for negative testing). + /// Build an auth token with custom zone_id, chain_id, and portal (for negative testing). pub(crate) fn build_bad_token( &self, signer: &alloy_signer_local::PrivateKeySigner, @@ -3057,6 +3064,7 @@ impl L1Fixture { amount, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, } } @@ -3123,6 +3131,7 @@ impl L1Fixture { ciphertext: vec![0u8; 64], // ENCRYPTED_PAYLOAD_PLAINTEXT_SIZE = 64 nonce: [0u8; 12], tag: [0u8; 16], + bounceback_recipient: Address::ZERO, } } @@ -3141,6 +3150,7 @@ impl L1Fixture { amount, fee: 0, memo: B256::ZERO, + bounceback_recipient: Address::ZERO, } } @@ -3202,6 +3212,7 @@ impl L1Fixture { ciphertext, nonce, tag, + bounceback_recipient: Address::ZERO, } } } diff --git a/specs/ref-impls/src/zone/IZone.sol b/specs/ref-impls/src/zone/IZone.sol index 0af0939cc..2733bbc15 100644 --- a/specs/ref-impls/src/zone/IZone.sol +++ b/specs/ref-impls/src/zone/IZone.sol @@ -67,6 +67,7 @@ struct Deposit { address to; uint128 amount; bytes32 memo; + address bouncebackRecipient; // L1 address for refund if zone-side processing fails (address(0) for bounce-back deposits) } /*////////////////////////////////////////////////////////////// @@ -94,6 +95,7 @@ struct EncryptedDeposit { uint128 amount; // Amount (public, for accounting) uint256 keyIndex; // Index of encryption key used (specified by depositor) EncryptedDepositPayload encrypted; // Encrypted (to, memo) + address bouncebackRecipient; // L1 address for refund if zone-side processing fails } /// @notice Historical record of an encryption key with its activation block @@ -500,6 +502,7 @@ interface IZonePortal { uint128 netAmount, uint128 fee, bytes32 memo, + address bouncebackRecipient, uint64 depositNumber ); @@ -515,7 +518,7 @@ interface IZonePortal { address indexed to, address token, uint128 amount, bool callbackSuccess ); - event BounceBack( + event WithdrawalBounceBack( bytes32 indexed newCurrentDepositQueueHash, address indexed fallbackRecipient, address token, @@ -523,6 +526,8 @@ interface IZonePortal { uint64 depositNumber ); + event DepositBounceBack(address indexed bouncebackRecipient, address token, uint128 amount); + event SequencerTransferStarted( address indexed currentSequencer, address indexed pendingSequencer ); @@ -705,7 +710,8 @@ interface IZonePortal { address token, address to, uint128 amount, - bytes32 memo + bytes32 memo, + address bouncebackRecipient ) external returns (bytes32 newCurrentDepositQueueHash); @@ -719,12 +725,14 @@ interface IZonePortal { /// @param amount Amount to deposit /// @param keyIndex Index of the encryption key used (from encryptionKeyAt) /// @param encrypted The encrypted payload (recipient and memo) + /// @param bouncebackRecipient L1 address for refund if zone-side processing fails /// @return newCurrentDepositQueueHash The new deposit queue hash function depositEncrypted( address token, uint128 amount, uint256 keyIndex, - EncryptedDepositPayload calldata encrypted + EncryptedDepositPayload calldata encrypted, + address bouncebackRecipient ) external returns (bytes32 newCurrentDepositQueueHash); @@ -886,6 +894,17 @@ interface IZoneInbox { event EncryptedDepositFailed( bytes32 indexed depositHash, address indexed sender, address token, uint128 amount ); + + /// @notice Emitted when a regular deposit fails zone-side (e.g., TIP-403 blocks the mint) + event DepositFailed( + bytes32 indexed depositHash, + address indexed sender, + address to, + address token, + uint128 amount, + address bouncebackRecipient + ); + /// @notice Emitted when a TIP-20 token is enabled on the zone via advanceTempo event TokenEnabled(address indexed token, string name, string symbol, string currency); @@ -1030,6 +1049,17 @@ interface IZoneOutbox { external returns (bytes32 withdrawalQueueHash); + /// @notice Enqueue a bounce-back withdrawal for a failed deposit + /// @dev Only callable by the ZoneInbox during advanceTempo when a deposit mint fails. + /// The bounce-back withdrawal returns escrowed funds to the depositor's + /// bouncebackRecipient on L1. + function enqueueDepositBounceBack( + address token, + uint128 amount, + address bouncebackRecipient + ) + external; + } /// @title IZoneConfig diff --git a/specs/ref-impls/src/zone/SwapAndDepositRouter.sol b/specs/ref-impls/src/zone/SwapAndDepositRouter.sol index bc681cc4a..ea421ee17 100644 --- a/specs/ref-impls/src/zone/SwapAndDepositRouter.sol +++ b/specs/ref-impls/src/zone/SwapAndDepositRouter.sol @@ -91,7 +91,8 @@ contract SwapAndDepositRouter is IWithdrawalReceiver { uint128 amountOut = _swapIfNeeded(tokenIn, tokenOut, amount, minAmountOut); ITIP20(tokenOut).approve(targetPortal, amountOut); - IZonePortal(targetPortal).depositEncrypted(tokenOut, amountOut, keyIndex, encrypted); + IZonePortal(targetPortal) + .depositEncrypted(tokenOut, amountOut, keyIndex, encrypted, msg.sender); } else { (, // skip isEncrypted address tokenOut, @@ -106,7 +107,7 @@ contract SwapAndDepositRouter is IWithdrawalReceiver { uint128 amountOut = _swapIfNeeded(tokenIn, tokenOut, amount, minAmountOut); ITIP20(tokenOut).approve(targetPortal, amountOut); - IZonePortal(targetPortal).deposit(tokenOut, recipient, amountOut, memo); + IZonePortal(targetPortal).deposit(tokenOut, recipient, amountOut, memo, msg.sender); } return IWithdrawalReceiver.onWithdrawalReceived.selector; diff --git a/specs/ref-impls/src/zone/ZoneInbox.sol b/specs/ref-impls/src/zone/ZoneInbox.sol index 46a7fd736..ab873df8c 100644 --- a/specs/ref-impls/src/zone/ZoneInbox.sol +++ b/specs/ref-impls/src/zone/ZoneInbox.sol @@ -16,6 +16,7 @@ import { ITempoState, IZoneConfig, IZoneInbox, + IZoneOutbox, IZoneToken, PORTAL_CURRENT_DEPOSIT_QUEUE_HASH_SLOT, PORTAL_ENCRYPTION_KEYS_SLOT, @@ -43,6 +44,9 @@ contract ZoneInbox is IZoneInbox { /// @notice The TempoState predeploy address (stored as concrete type for internal use) TempoState internal immutable _tempoState; + /// @notice The ZoneOutbox predeploy (for enqueuing deposit bouncebacks) + IZoneOutbox public immutable outbox; + /// @notice Last processed deposit queue hash (validated against Tempo state) bytes32 public processedDepositQueueHash; @@ -53,10 +57,16 @@ contract ZoneInbox is IZoneInbox { CONSTRUCTOR //////////////////////////////////////////////////////////////*/ - constructor(address _config, address _tempoPortalAddr, address _tempoStateAddr) { + constructor( + address _config, + address _tempoPortalAddr, + address _tempoStateAddr, + address _outbox + ) { config = IZoneConfig(_config); tempoPortal = _tempoPortalAddr; _tempoState = TempoState(_tempoStateAddr); + outbox = IZoneOutbox(_outbox); } /// @notice The TempoState predeploy address @@ -210,10 +220,23 @@ contract ZoneInbox is IZoneInbox { // Advance the hash chain with type discriminator currentHash = keccak256(abi.encode(DepositType.Regular, d, currentHash)); - // Mint the correct zone-side TIP-20 token to the recipient - IZoneToken(d.token).mint(d.to, d.amount); - - emit DepositProcessed(currentHash, d.sender, d.to, d.token, d.amount, d.memo); + if (d.bouncebackRecipient != address(0)) { + // Normal deposit: try minting, bounce back on failure + try IZoneToken(d.token).mint(d.to, d.amount) { + emit DepositProcessed( + currentHash, d.sender, d.to, d.token, d.amount, d.memo + ); + } catch { + outbox.enqueueDepositBounceBack(d.token, d.amount, d.bouncebackRecipient); + emit DepositFailed( + currentHash, d.sender, d.to, d.token, d.amount, d.bouncebackRecipient + ); + } + } else { + // Bounce-back deposit from a failed withdrawal — always succeeds + IZoneToken(d.token).mint(d.to, d.amount); + emit DepositProcessed(currentHash, d.sender, d.to, d.token, d.amount, d.memo); + } } else { // Decode encrypted deposit EncryptedDeposit memory ed = abi.decode(qd.depositData, (EncryptedDeposit)); @@ -275,16 +298,46 @@ contract ZoneInbox is IZoneInbox { currentHash = keccak256(abi.encode(DepositType.Encrypted, ed, currentHash)); if (!valid) { - // Decryption failed: credit the depositor's address on the zone. - // L1 funds remain escrowed in the portal. - IZoneToken(ed.token).mint(ed.sender, ed.amount); - emit EncryptedDepositFailed(currentHash, ed.sender, ed.token, ed.amount); + // Decryption failed: try crediting the depositor's address on the zone. + if (ed.bouncebackRecipient != address(0)) { + try IZoneToken(ed.token).mint(ed.sender, ed.amount) { + emit EncryptedDepositFailed(currentHash, ed.sender, ed.token, ed.amount); + } catch { + outbox.enqueueDepositBounceBack( + ed.token, ed.amount, ed.bouncebackRecipient + ); + emit EncryptedDepositFailed(currentHash, ed.sender, ed.token, ed.amount); + } + } else { + IZoneToken(ed.token).mint(ed.sender, ed.amount); + emit EncryptedDepositFailed(currentHash, ed.sender, ed.token, ed.amount); + } } else { - // Decryption succeeded - mint the correct zone-side TIP-20 to the decrypted recipient - IZoneToken(ed.token).mint(dec.to, ed.amount); - emit EncryptedDepositProcessed( - currentHash, ed.sender, dec.to, ed.token, ed.amount, dec.memo - ); + // Decryption succeeded: try minting to the decrypted recipient + if (ed.bouncebackRecipient != address(0)) { + try IZoneToken(ed.token).mint(dec.to, ed.amount) { + emit EncryptedDepositProcessed( + currentHash, ed.sender, dec.to, ed.token, ed.amount, dec.memo + ); + } catch { + outbox.enqueueDepositBounceBack( + ed.token, ed.amount, ed.bouncebackRecipient + ); + emit DepositFailed( + currentHash, + ed.sender, + dec.to, + ed.token, + ed.amount, + ed.bouncebackRecipient + ); + } + } else { + IZoneToken(ed.token).mint(dec.to, ed.amount); + emit EncryptedDepositProcessed( + currentHash, ed.sender, dec.to, ed.token, ed.amount, dec.memo + ); + } } } } diff --git a/specs/ref-impls/src/zone/ZoneOutbox.sol b/specs/ref-impls/src/zone/ZoneOutbox.sol index b3ccb19c2..6df45fd13 100644 --- a/specs/ref-impls/src/zone/ZoneOutbox.sol +++ b/specs/ref-impls/src/zone/ZoneOutbox.sol @@ -400,6 +400,36 @@ contract ZoneOutbox is IZoneOutbox { emit BatchFinalized(withdrawalQueueHash, currentWithdrawalBatchIndex); } + /// @notice Enqueue a bounce-back withdrawal for a failed deposit + /// @dev Only callable by the ZoneInbox during advanceTempo. Creates a zero-fee, + /// zero-callback withdrawal that returns escrowed funds to the depositor's + /// bouncebackRecipient on L1. + function enqueueDepositBounceBack( + address token, + uint128 amount, + address bouncebackRecipient + ) + external + { + if (msg.sender != address(0) && msg.sender != config.sequencer()) revert OnlySequencer(); + + _pendingWithdrawals.push( + PendingWithdrawal({ + token: token, + sender: address(0), + txHash: bytes32(0), + to: bouncebackRecipient, + amount: amount, + fee: 0, + memo: bytes32(0), + gasLimit: 0, + fallbackRecipient: address(0), + callbackData: "", + revealTo: "" + }) + ); + } + /// @notice Number of pending withdrawals function pendingWithdrawalsCount() external view returns (uint256) { if (_pendingWithdrawalsHead >= _pendingWithdrawals.length) { diff --git a/specs/ref-impls/src/zone/ZonePortal.sol b/specs/ref-impls/src/zone/ZonePortal.sol index 3ba2e5912..6f00fab4d 100644 --- a/specs/ref-impls/src/zone/ZonePortal.sol +++ b/specs/ref-impls/src/zone/ZonePortal.sol @@ -479,7 +479,8 @@ contract ZonePortal is IZonePortal { address _token, address to, uint128 amount, - bytes32 memo + bytes32 memo, + address bouncebackRecipient ) external returns (bytes32 newCurrentDepositQueueHash) @@ -499,6 +500,15 @@ contract ZonePortal is IZonePortal { revert DepositPolicyForbids(); } + // Validate bouncebackRecipient against TIP-403 at deposit time so that + // bounceback transfers on L1 are guaranteed to succeed even if the + // recipient is later blacklisted (portal has a TIP-403 bypass). + if (bouncebackRecipient != address(0)) { + if (!TIP403_REGISTRY.isAuthorizedRecipient(policyId, bouncebackRecipient)) { + revert DepositPolicyForbids(); + } + } + // Calculate deposit fee uint128 fee = calculateDepositFee(); if (amount <= fee) revert DepositTooSmall(); @@ -514,8 +524,14 @@ contract ZonePortal is IZonePortal { } // Build deposit struct with net amount (fee already paid to sequencer on Tempo) - Deposit memory depositData = - Deposit({ token: _token, sender: msg.sender, to: to, amount: netAmount, memo: memo }); + Deposit memory depositData = Deposit({ + token: _token, + sender: msg.sender, + to: to, + amount: netAmount, + memo: memo, + bouncebackRecipient: bouncebackRecipient + }); // Insert deposit into queue newCurrentDepositQueueHash = DepositQueueLib.enqueue(currentDepositQueueHash, depositData); @@ -523,7 +539,15 @@ contract ZonePortal is IZonePortal { uint64 thisDeposit = ++depositCount; emit DepositMade( - newCurrentDepositQueueHash, msg.sender, _token, to, netAmount, fee, memo, thisDeposit + newCurrentDepositQueueHash, + msg.sender, + _token, + to, + netAmount, + fee, + memo, + bouncebackRecipient, + thisDeposit ); } @@ -541,7 +565,8 @@ contract ZonePortal is IZonePortal { address _token, uint128 amount, uint256 keyIndex, - EncryptedDepositPayload calldata encrypted + EncryptedDepositPayload calldata encrypted, + address bouncebackRecipient ) external returns (bytes32 newCurrentDepositQueueHash) @@ -594,7 +619,8 @@ contract ZonePortal is IZonePortal { sender: msg.sender, amount: netAmount, keyIndex: keyIndex, - encrypted: encrypted + encrypted: encrypted, + bouncebackRecipient: bouncebackRecipient }); // Insert encrypted deposit into queue @@ -655,7 +681,9 @@ contract ZonePortal is IZonePortal { } if (!success) { - _enqueueBounceBack(_token, withdrawal.amount, withdrawal.fallbackRecipient); + _enqueueWithdrawalBounceBack( + _token, withdrawal.amount, withdrawal.fallbackRecipient + ); emit WithdrawalProcessed(withdrawal.to, _token, withdrawal.amount, false); return; } @@ -677,16 +705,16 @@ contract ZonePortal is IZonePortal { emit WithdrawalProcessed(withdrawal.to, _token, withdrawal.amount, true); } catch { // Callback failed: bounce back to zone (only amount, not fee) - _enqueueBounceBack(_token, withdrawal.amount, withdrawal.fallbackRecipient); + _enqueueWithdrawalBounceBack(_token, withdrawal.amount, withdrawal.fallbackRecipient); emit WithdrawalProcessed(withdrawal.to, _token, withdrawal.amount, false); } } - /// @notice Enqueue a bounce-back deposit for failed callback + /// @notice Enqueue a bounce-back deposit for a failed withdrawal callback /// @param _token The token from the failed withdrawal /// @param amount The amount to bounce back /// @param fallbackRecipient The zone address to receive the bounce-back - function _enqueueBounceBack( + function _enqueueWithdrawalBounceBack( address _token, uint128 amount, address fallbackRecipient @@ -698,7 +726,8 @@ contract ZonePortal is IZonePortal { sender: address(this), to: fallbackRecipient, amount: amount, - memo: bytes32(0) + memo: bytes32(0), + bouncebackRecipient: address(0) }); bytes32 newCurrentDepositQueueHash = @@ -706,7 +735,9 @@ contract ZonePortal is IZonePortal { currentDepositQueueHash = newCurrentDepositQueueHash; uint64 thisDeposit = ++depositCount; - emit BounceBack(newCurrentDepositQueueHash, fallbackRecipient, _token, amount, thisDeposit); + emit WithdrawalBounceBack( + newCurrentDepositQueueHash, fallbackRecipient, _token, amount, thisDeposit + ); } /*////////////////////////////////////////////////////////////// diff --git a/specs/ref-impls/test/zone/DepositQueueLib.t.sol b/specs/ref-impls/test/zone/DepositQueueLib.t.sol index 12f1d2207..ca34782ba 100644 --- a/specs/ref-impls/test/zone/DepositQueueLib.t.sol +++ b/specs/ref-impls/test/zone/DepositQueueLib.t.sol @@ -40,7 +40,8 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("memo") + memo: bytes32("memo"), + bouncebackRecipient: address(0) }); bytes32 newHash = DepositQueueLib.enqueue(bytes32(0), d); @@ -55,21 +56,24 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("d1") + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); Deposit memory d2 = Deposit({ token: address(0x1000), sender: address(0x300), to: address(0x200), amount: 200e6, - memo: bytes32("d2") + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); Deposit memory d3 = Deposit({ token: address(0x1000), sender: address(0x200), to: address(0x200), amount: 300e6, - memo: bytes32("d3") + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); bytes32 h1 = DepositQueueLib.enqueue(bytes32(0), d1); @@ -93,14 +97,16 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("first") + memo: bytes32("first"), + bouncebackRecipient: address(0) }); Deposit memory d2 = Deposit({ token: address(0x1000), sender: address(0x300), to: address(0x200), amount: 200e6, - memo: bytes32("second") + memo: bytes32("second"), + bouncebackRecipient: address(0) }); bytes32 h1 = DepositQueueLib.enqueue(bytes32(0), d1); @@ -113,7 +119,12 @@ contract DepositQueueLibTest is Test { function test_enqueue_emptyToEmpty() public pure { // An empty deposit struct should still produce a valid hash Deposit memory d = Deposit({ - token: address(0x1000), sender: address(0), to: address(0), amount: 0, memo: bytes32(0) + token: address(0x1000), + sender: address(0), + to: address(0), + amount: 0, + memo: bytes32(0), + bouncebackRecipient: address(0) }); bytes32 h = DepositQueueLib.enqueue(bytes32(0), d); @@ -128,14 +139,16 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("memo1") + memo: bytes32("memo1"), + bouncebackRecipient: address(0) }); Deposit memory d2 = Deposit({ token: address(0x1000), sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("memo2") // Only memo differs + memo: bytes32("memo2"), // Only memo differs + bouncebackRecipient: address(0) }); bytes32 h1 = DepositQueueLib.enqueue(bytes32(0), d1); @@ -150,7 +163,8 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("memo") + memo: bytes32("memo"), + bouncebackRecipient: address(0) }); bytes32 h1 = DepositQueueLib.enqueue(bytes32(0), d); @@ -175,7 +189,8 @@ contract DepositQueueLibTest is Test { ciphertext: new bytes(64), nonce: bytes12(0), tag: bytes16(0) - }) + }), + bouncebackRecipient: address(0) }); bytes32 newHash = DepositQueueLib.enqueueEncrypted(bytes32(0), ed); @@ -189,7 +204,8 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("d1") + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); EncryptedDeposit memory ed = EncryptedDeposit({ @@ -203,7 +219,8 @@ contract DepositQueueLibTest is Test { ciphertext: new bytes(64), nonce: bytes12(0), tag: bytes16(0) - }) + }), + bouncebackRecipient: address(0) }); Deposit memory d2 = Deposit({ @@ -211,7 +228,8 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x200), amount: 300e6, - memo: bytes32("d3") + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); bytes32 h1 = DepositQueueLib.enqueue(bytes32(0), d1); @@ -234,7 +252,8 @@ contract DepositQueueLibTest is Test { sender: address(0x200), to: address(0x300), amount: 100e6, - memo: bytes32("memo") + memo: bytes32("memo"), + bouncebackRecipient: address(0) }); EncryptedDeposit memory ed = EncryptedDeposit({ @@ -248,7 +267,8 @@ contract DepositQueueLibTest is Test { ciphertext: "", nonce: bytes12(0), tag: bytes16(0) - }) + }), + bouncebackRecipient: address(0) }); bytes32 regularHash = DepositQueueLib.enqueue(bytes32(0), d); diff --git a/specs/ref-impls/test/zone/SwapAndDepositRouter.t.sol b/specs/ref-impls/test/zone/SwapAndDepositRouter.t.sol index 6ac0355fb..c11f85512 100644 --- a/specs/ref-impls/test/zone/SwapAndDepositRouter.t.sol +++ b/specs/ref-impls/test/zone/SwapAndDepositRouter.t.sol @@ -95,7 +95,8 @@ contract MockZonePortalForRouter { address _token, address to, uint128 amount, - bytes32 memo + bytes32 memo, + address /* bouncebackRecipient */ ) external returns (bytes32) @@ -112,7 +113,8 @@ contract MockZonePortalForRouter { address _token, uint128 amount, uint256 keyIndex, - EncryptedDepositPayload calldata + EncryptedDepositPayload calldata, + address /* bouncebackRecipient */ ) external returns (bytes32) diff --git a/specs/ref-impls/test/zone/ZoneBridge.t.sol b/specs/ref-impls/test/zone/ZoneBridge.t.sol index cccadecc6..c318a4fb1 100644 --- a/specs/ref-impls/test/zone/ZoneBridge.t.sol +++ b/specs/ref-impls/test/zone/ZoneBridge.t.sol @@ -172,7 +172,8 @@ contract ZoneBridgeTest is BaseTest { ); // Zone inbox (advances Tempo state and processes deposits) - l2Inbox = new ZoneInbox(address(l2Config), address(l1Portal), address(l2TempoState)); + l2Inbox = + new ZoneInbox(address(l2Config), address(l1Portal), address(l2TempoState), address(0)); l2ZoneToken.setMinter(address(l2Inbox), true); // Zone outbox (handles withdrawals) @@ -252,7 +253,12 @@ contract ZoneBridgeTest is BaseTest { { // Record the deposit Deposit memory d = Deposit({ - token: address(l2ZoneToken), sender: sender, to: to, amount: amount, memo: memo + token: address(l2ZoneToken), + sender: sender, + to: to, + amount: amount, + memo: memo, + bouncebackRecipient: address(0) }); // Calculate the new hash (matches what Tempo portal computes) @@ -396,8 +402,9 @@ contract ZoneBridgeTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), depositAmount); - bytes32 l1DepositHash = - l1Portal.deposit(address(l2ZoneToken), alice, depositAmount, bytes32("hello zone")); + bytes32 l1DepositHash = l1Portal.deposit( + address(l2ZoneToken), alice, depositAmount, bytes32("hello zone"), address(0) + ); vm.stopPrank(); // Verify L1 state @@ -473,12 +480,12 @@ contract ZoneBridgeTest is BaseTest { // === Alice and Bob both deposit === vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 5000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("alice1")); + l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("alice1"), address(0)); vm.stopPrank(); vm.startPrank(bob); l2ZoneToken.approve(address(l1Portal), 5000e6); - l1Portal.deposit(address(l2ZoneToken), bob, 3000e6, bytes32("bob1")); + l1Portal.deposit(address(l2ZoneToken), bob, 3000e6, bytes32("bob1"), address(0)); vm.stopPrank(); // Sequencer observes and relays @@ -535,7 +542,7 @@ contract ZoneBridgeTest is BaseTest { // Setup: deposit to zone vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -594,7 +601,7 @@ contract ZoneBridgeTest is BaseTest { // Setup: deposit to zone vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -642,7 +649,7 @@ contract ZoneBridgeTest is BaseTest { // Deposit to Alice vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -671,7 +678,7 @@ contract ZoneBridgeTest is BaseTest { // Deposit to Alice vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -691,7 +698,7 @@ contract ZoneBridgeTest is BaseTest { // Deposit to Alice vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -707,7 +714,7 @@ contract ZoneBridgeTest is BaseTest { // Deposit on L1 vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -731,7 +738,7 @@ contract ZoneBridgeTest is BaseTest { // Deposit to Alice vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -756,7 +763,7 @@ contract ZoneBridgeTest is BaseTest { function test_l2_onlySequencerCanAdvanceTempo() public { vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); _sequencerObserveDeposit(alice, alice, 1000e6, bytes32("")); @@ -788,7 +795,7 @@ contract ZoneBridgeTest is BaseTest { // Make a deposit to get a non-zero currentDepositQueueHash vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("layout-test")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("layout-test"), address(0)); vm.stopPrank(); // Read via vm.load using our constant @@ -862,7 +869,8 @@ contract ZoneBridgeTest is BaseTest { sender: sender, amount: netAmount, keyIndex: keyIndex, - encrypted: encrypted + encrypted: encrypted, + bouncebackRecipient: address(0) }); // Calculate the new hash (matches what portal computes via DepositQueueLib) @@ -1018,7 +1026,7 @@ contract ZoneBridgeTest is BaseTest { vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), depositAmount); bytes32 l1DepositHash = - l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload); + l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload, address(0)); vm.stopPrank(); // Verify L1 state @@ -1083,7 +1091,7 @@ contract ZoneBridgeTest is BaseTest { vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), depositAmount); - l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload); + l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload, address(0)); vm.stopPrank(); // === STEP 3: Sequencer observes and relays with FAILED decryption === @@ -1122,15 +1130,17 @@ contract ZoneBridgeTest is BaseTest { // === STEP 2: Alice makes a regular deposit === vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), depositAmount * 2); - bytes32 h1 = - l1Portal.deposit(address(l2ZoneToken), alice, depositAmount, bytes32("regular")); + bytes32 h1 = l1Portal.deposit( + address(l2ZoneToken), alice, depositAmount, bytes32("regular"), address(0) + ); vm.stopPrank(); // === STEP 3: Bob makes an encrypted deposit === EncryptedDepositPayload memory payload = _makeEncryptedPayload(); vm.startPrank(bob); l2ZoneToken.approve(address(l1Portal), depositAmount); - bytes32 h2 = l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload); + bytes32 h2 = + l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload, address(0)); vm.stopPrank(); // === STEP 4: Carol makes another regular deposit === @@ -1140,7 +1150,9 @@ contract ZoneBridgeTest is BaseTest { l2ZoneToken.setMinter(address(this), false); vm.startPrank(carol); l2ZoneToken.approve(address(l1Portal), depositAmount); - bytes32 h3 = l1Portal.deposit(address(l2ZoneToken), carol, depositAmount, bytes32("carol")); + bytes32 h3 = l1Portal.deposit( + address(l2ZoneToken), carol, depositAmount, bytes32("carol"), address(0) + ); vm.stopPrank(); assertEq(l1Portal.currentDepositQueueHash(), h3, "L1 hash should be after 3rd deposit"); @@ -1154,7 +1166,8 @@ contract ZoneBridgeTest is BaseTest { sender: alice, to: alice, amount: depositAmount, - memo: bytes32("regular") + memo: bytes32("regular"), + bouncebackRecipient: address(0) }); bytes32 prevHash = l2Inbox.processedDepositQueueHash(); bytes32 hash1 = keccak256(abi.encode(DepositType.Regular, d1, prevHash)); @@ -1166,7 +1179,8 @@ contract ZoneBridgeTest is BaseTest { sender: bob, amount: netAmount, keyIndex: 0, - encrypted: payload + encrypted: payload, + bouncebackRecipient: address(0) }); bytes32 hash2 = keccak256(abi.encode(DepositType.Encrypted, ed, hash1)); assertEq(hash2, h2, "hash2 must match L1"); @@ -1177,7 +1191,8 @@ contract ZoneBridgeTest is BaseTest { sender: carol, to: carol, amount: depositAmount, - memo: bytes32("carol") + memo: bytes32("carol"), + bouncebackRecipient: address(0) }); bytes32 hash3 = keccak256(abi.encode(DepositType.Regular, d3, hash2)); assertEq(hash3, h3, "hash3 must match L1"); @@ -1254,7 +1269,8 @@ contract ZoneBridgeTest is BaseTest { vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), depositAmount); - bytes32 h1 = l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload1); + bytes32 h1 = + l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 0, payload1, address(0)); vm.stopPrank(); // === STEP 3: Sequencer rotates to second encryption key === @@ -1266,7 +1282,8 @@ contract ZoneBridgeTest is BaseTest { vm.startPrank(bob); l2ZoneToken.approve(address(l1Portal), depositAmount); - bytes32 h2 = l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 1, payload2); + bytes32 h2 = + l1Portal.depositEncrypted(address(l2ZoneToken), depositAmount, 1, payload2, address(0)); vm.stopPrank(); assertEq(l1Portal.currentDepositQueueHash(), h2, "L1 hash after both deposits"); @@ -1278,7 +1295,8 @@ contract ZoneBridgeTest is BaseTest { sender: alice, amount: netAmount, keyIndex: 0, - encrypted: payload1 + encrypted: payload1, + bouncebackRecipient: address(0) }); bytes32 hash1 = keccak256(abi.encode(DepositType.Encrypted, ed1, prevHash)); assertEq(hash1, h1, "hash1 must match L1"); @@ -1288,7 +1306,8 @@ contract ZoneBridgeTest is BaseTest { sender: bob, amount: netAmount, keyIndex: 1, - encrypted: payload2 + encrypted: payload2, + bouncebackRecipient: address(0) }); bytes32 hash2 = keccak256(abi.encode(DepositType.Encrypted, ed2, hash1)); assertEq(hash2, h2, "hash2 must match L1"); diff --git a/specs/ref-impls/test/zone/ZoneInbox.t.sol b/specs/ref-impls/test/zone/ZoneInbox.t.sol index 1774e7f12..e68d86486 100644 --- a/specs/ref-impls/test/zone/ZoneInbox.t.sol +++ b/specs/ref-impls/test/zone/ZoneInbox.t.sol @@ -51,7 +51,7 @@ contract ZoneInboxTest is Test { tempoState.setMockStorageValue( mockPortal, bytes32(uint256(0)), bytes32(uint256(uint160(sequencer))) ); - inbox = new ZoneInbox(address(config), mockPortal, address(tempoState)); + inbox = new ZoneInbox(address(config), mockPortal, address(tempoState), address(0)); zoneToken.setMinter(address(inbox), true); } @@ -101,7 +101,8 @@ contract ZoneInboxTest is Test { sender: alice, to: bob, amount: 1000e6, - memo: bytes32("payment") + memo: bytes32("payment"), + bouncebackRecipient: address(0) }); // Calculate expected hash @@ -121,13 +122,28 @@ contract ZoneInboxTest is Test { function test_advanceTempo_multipleDeposits() public { Deposit[] memory deposits = new Deposit[](3); deposits[0] = Deposit({ - token: address(zoneToken), sender: alice, to: alice, amount: 100e6, memo: bytes32("d1") + token: address(zoneToken), + sender: alice, + to: alice, + amount: 100e6, + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); deposits[1] = Deposit({ - token: address(zoneToken), sender: bob, to: bob, amount: 200e6, memo: bytes32("d2") + token: address(zoneToken), + sender: bob, + to: bob, + amount: 200e6, + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); deposits[2] = Deposit({ - token: address(zoneToken), sender: alice, to: bob, amount: 300e6, memo: bytes32("d3") + token: address(zoneToken), + sender: alice, + to: bob, + amount: 300e6, + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); // Calculate expected hash chain @@ -158,7 +174,8 @@ contract ZoneInboxTest is Test { sender: alice, to: bob, amount: 1000e6, - memo: bytes32("payment") + memo: bytes32("payment"), + bouncebackRecipient: address(0) }); // Set a different hash (simulating more deposits pending on Tempo) @@ -180,10 +197,20 @@ contract ZoneInboxTest is Test { // Partial processing is now allowed — the proof validates ancestor contiguity Deposit[] memory allDeposits = new Deposit[](2); allDeposits[0] = Deposit({ - token: address(zoneToken), sender: alice, to: alice, amount: 100e6, memo: bytes32("d1") + token: address(zoneToken), + sender: alice, + to: alice, + amount: 100e6, + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); allDeposits[1] = Deposit({ - token: address(zoneToken), sender: bob, to: bob, amount: 200e6, memo: bytes32("d2") + token: address(zoneToken), + sender: bob, + to: bob, + amount: 200e6, + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); // Set hash to be for both deposits @@ -244,10 +271,20 @@ contract ZoneInboxTest is Test { // First batch of deposits Deposit[] memory batch1 = new Deposit[](2); batch1[0] = Deposit({ - token: address(zoneToken), sender: alice, to: alice, amount: 100e6, memo: bytes32("d1") + token: address(zoneToken), + sender: alice, + to: alice, + amount: 100e6, + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); batch1[1] = Deposit({ - token: address(zoneToken), sender: bob, to: bob, amount: 200e6, memo: bytes32("d2") + token: address(zoneToken), + sender: bob, + to: bob, + amount: 200e6, + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); bytes32 h0 = bytes32(0); @@ -264,7 +301,12 @@ contract ZoneInboxTest is Test { // Second batch of deposits Deposit[] memory batch2 = new Deposit[](1); batch2[0] = Deposit({ - token: address(zoneToken), sender: alice, to: bob, amount: 500e6, memo: bytes32("d3") + token: address(zoneToken), + sender: alice, + to: bob, + amount: 500e6, + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); bytes32 h3 = keccak256(abi.encode(DepositType.Regular, batch2[0], h2)); @@ -290,7 +332,8 @@ contract ZoneInboxTest is Test { sender: alice, to: bob, amount: 1000e6, - memo: bytes32("payment") + memo: bytes32("payment"), + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Regular, deposits[0], bytes32(0))); @@ -319,7 +362,8 @@ contract ZoneInboxTest is Test { sender: alice, to: bob, amount: 1000e6, - memo: bytes32("payment") + memo: bytes32("payment"), + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Regular, deposits[0], bytes32(0))); @@ -343,7 +387,12 @@ contract ZoneInboxTest is Test { function test_advanceTempo_zeroAmountDeposit() public { Deposit[] memory deposits = new Deposit[](1); deposits[0] = Deposit({ - token: address(zoneToken), sender: alice, to: bob, amount: 0, memo: bytes32("empty") + token: address(zoneToken), + sender: alice, + to: bob, + amount: 0, + memo: bytes32("empty"), + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Regular, deposits[0], bytes32(0))); @@ -384,7 +433,8 @@ contract ZoneInboxTest is Test { sender: alice, to: bob, amount: uint128(i + 1) * 1e6, - memo: bytes32(i) + memo: bytes32(i), + bouncebackRecipient: address(0) }); currentHash = keccak256(abi.encode(DepositType.Regular, deposits[i], currentHash)); } @@ -437,7 +487,8 @@ contract ZoneInboxTest is Test { ciphertext: new bytes(64), nonce: bytes12(0), tag: bytes16(0) - }) + }), + bouncebackRecipient: address(0) }); qd = QueuedDeposit({ depositType: DepositType.Encrypted, depositData: abi.encode(ed) }); } @@ -572,7 +623,12 @@ contract ZoneInboxTest is Test { // Build regular deposit Deposit memory d = Deposit({ - token: address(zoneToken), sender: alice, to: bob, amount: 100e6, memo: bytes32("d1") + token: address(zoneToken), + sender: alice, + to: bob, + amount: 100e6, + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); QueuedDeposit memory qdRegular = QueuedDeposit({ depositType: DepositType.Regular, depositData: abi.encode(d) }); @@ -635,7 +691,12 @@ contract ZoneInboxTest is Test { function test_advanceTempo_extraDecryptionData() public { // Build a regular deposit only (no encrypted deposits) Deposit memory d = Deposit({ - token: address(zoneToken), sender: alice, to: bob, amount: 100e6, memo: bytes32("d1") + token: address(zoneToken), + sender: alice, + to: bob, + amount: 100e6, + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); QueuedDeposit memory qd = QueuedDeposit({ depositType: DepositType.Regular, depositData: abi.encode(d) }); diff --git a/specs/ref-impls/test/zone/ZoneIntegration.t.sol b/specs/ref-impls/test/zone/ZoneIntegration.t.sol index de585e8ac..7b106b7a9 100644 --- a/specs/ref-impls/test/zone/ZoneIntegration.t.sol +++ b/specs/ref-impls/test/zone/ZoneIntegration.t.sol @@ -113,8 +113,10 @@ contract ZoneIntegrationTest is BaseTest { l2TempoState.setMockStorageValue( address(l1Portal), bytes32(uint256(0)), bytes32(uint256(uint160(admin))) ); - l2Inbox = new ZoneInbox(address(l2Config), address(l1Portal), address(l2TempoState)); l2Outbox = new ZoneOutbox(address(l2Config)); + l2Inbox = new ZoneInbox( + address(l2Config), address(l1Portal), address(l2TempoState), address(l2Outbox) + ); l2ZoneToken.setMinter(address(l2Inbox), true); l2ZoneToken.setBurner(address(l2Outbox), true); @@ -200,18 +202,18 @@ contract ZoneIntegrationTest is BaseTest { // Alice, Bob, Charlie all deposit vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 10_000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("alice1")); - l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("alice2")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("alice1"), address(0)); + l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("alice2"), address(0)); vm.stopPrank(); vm.startPrank(bob); l2ZoneToken.approve(address(l1Portal), 5000e6); - l1Portal.deposit(address(l2ZoneToken), bob, 3000e6, bytes32("bob1")); + l1Portal.deposit(address(l2ZoneToken), bob, 3000e6, bytes32("bob1"), address(0)); vm.stopPrank(); vm.startPrank(charlie); l2ZoneToken.approve(address(l1Portal), 2000e6); - l1Portal.deposit(address(l2ZoneToken), charlie, 500e6, bytes32("charlie1")); + l1Portal.deposit(address(l2ZoneToken), charlie, 500e6, bytes32("charlie1"), address(0)); vm.stopPrank(); // Build deposit array @@ -221,24 +223,32 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 1000e6, - memo: bytes32("alice1") + memo: bytes32("alice1"), + bouncebackRecipient: address(0) }); deposits[1] = Deposit({ token: address(l2ZoneToken), sender: alice, to: alice, amount: 2000e6, - memo: bytes32("alice2") + memo: bytes32("alice2"), + bouncebackRecipient: address(0) }); deposits[2] = Deposit({ - token: address(l2ZoneToken), sender: bob, to: bob, amount: 3000e6, memo: bytes32("bob1") + token: address(l2ZoneToken), + sender: bob, + to: bob, + amount: 3000e6, + memo: bytes32("bob1"), + bouncebackRecipient: address(0) }); deposits[3] = Deposit({ token: address(l2ZoneToken), sender: charlie, to: charlie, amount: 500e6, - memo: bytes32("charlie1") + memo: bytes32("charlie1"), + bouncebackRecipient: address(0) }); // Set up L2 mock — hash chain uses l2ZoneToken consistently @@ -276,8 +286,10 @@ contract ZoneIntegrationTest is BaseTest { // Batch 1: Two deposits vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 10_000e6); - bytes32 d1 = l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("d1")); - bytes32 d2 = l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("d2")); + bytes32 d1 = + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("d1"), address(0)); + bytes32 d2 = + l1Portal.deposit(address(l2ZoneToken), alice, 2000e6, bytes32("d2"), address(0)); vm.stopPrank(); // Process only first deposit @@ -287,7 +299,8 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 1000e6, - memo: bytes32("d1") + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); // Deposit hash uses l2ZoneToken consistently @@ -326,7 +339,7 @@ contract ZoneIntegrationTest is BaseTest { // More deposits arrive vm.prank(alice); - l1Portal.deposit(address(l2ZoneToken), alice, 3000e6, bytes32("d3")); + l1Portal.deposit(address(l2ZoneToken), alice, 3000e6, bytes32("d3"), address(0)); // Process remaining deposits Deposit[] memory batch2 = new Deposit[](2); @@ -335,14 +348,16 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 2000e6, - memo: bytes32("d2") + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); batch2[1] = Deposit({ token: address(l2ZoneToken), sender: alice, to: alice, amount: 3000e6, - memo: bytes32("d3") + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); // Compute L2 hash chain continuing from l2Hash1 @@ -367,7 +382,7 @@ contract ZoneIntegrationTest is BaseTest { vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 10_000e6); bytes32 depositHash = - l1Portal.deposit(address(l2ZoneToken), alice, 5000e6, bytes32("deposit")); + l1Portal.deposit(address(l2ZoneToken), alice, 5000e6, bytes32("deposit"), address(0)); vm.stopPrank(); // Process deposit on L2 @@ -377,7 +392,8 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 5000e6, - memo: bytes32("deposit") + memo: bytes32("deposit"), + bouncebackRecipient: address(0) }); l2TempoState.setMockStorageValue( address(l1Portal), PORTAL_CURRENT_DEPOSIT_QUEUE_HASH_SLOT, depositHash @@ -441,8 +457,9 @@ contract ZoneIntegrationTest is BaseTest { // Initial deposit vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 100_000e6); - bytes32 depositHash = - l1Portal.deposit(address(l2ZoneToken), alice, 50_000e6, bytes32("big deposit")); + bytes32 depositHash = l1Portal.deposit( + address(l2ZoneToken), alice, 50_000e6, bytes32("big deposit"), address(0) + ); vm.stopPrank(); // Process on L2 @@ -452,7 +469,8 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 50_000e6, - memo: bytes32("big deposit") + memo: bytes32("big deposit"), + bouncebackRecipient: address(0) }); l2TempoState.setMockStorageValue( address(l1Portal), PORTAL_CURRENT_DEPOSIT_QUEUE_HASH_SLOT, depositHash @@ -582,12 +600,12 @@ contract ZoneIntegrationTest is BaseTest { // Phase 1: Initial deposits vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 100_000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 10_000e6, bytes32("d1")); + l1Portal.deposit(address(l2ZoneToken), alice, 10_000e6, bytes32("d1"), address(0)); vm.stopPrank(); vm.startPrank(bob); l2ZoneToken.approve(address(l1Portal), 100_000e6); - bytes32 d2 = l1Portal.deposit(address(l2ZoneToken), bob, 5000e6, bytes32("d2")); + bytes32 d2 = l1Portal.deposit(address(l2ZoneToken), bob, 5000e6, bytes32("d2"), address(0)); vm.stopPrank(); // Process both deposits @@ -597,10 +615,16 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 10_000e6, - memo: bytes32("d1") + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); deposits1[1] = Deposit({ - token: address(l2ZoneToken), sender: bob, to: bob, amount: 5000e6, memo: bytes32("d2") + token: address(l2ZoneToken), + sender: bob, + to: bob, + amount: 5000e6, + memo: bytes32("d2"), + bouncebackRecipient: address(0) }); l2TempoState.setMockStorageValue( @@ -625,7 +649,8 @@ contract ZoneIntegrationTest is BaseTest { // Phase 3: More deposits arrive while withdrawals are pending vm.startPrank(charlie); l2ZoneToken.approve(address(l1Portal), 20_000e6); - bytes32 d3 = l1Portal.deposit(address(l2ZoneToken), charlie, 7500e6, bytes32("d3")); + bytes32 d3 = + l1Portal.deposit(address(l2ZoneToken), charlie, 7500e6, bytes32("d3"), address(0)); vm.stopPrank(); // Submit batch with withdrawals @@ -654,7 +679,8 @@ contract ZoneIntegrationTest is BaseTest { sender: charlie, to: charlie, amount: 7500e6, - memo: bytes32("d3") + memo: bytes32("d3"), + bouncebackRecipient: address(0) }); l2TempoState.setMockStorageValue( @@ -694,7 +720,8 @@ contract ZoneIntegrationTest is BaseTest { // Deposit 10000 vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 10_000e6); - bytes32 d1 = l1Portal.deposit(address(l2ZoneToken), alice, 10_000e6, bytes32("d1")); + bytes32 d1 = + l1Portal.deposit(address(l2ZoneToken), alice, 10_000e6, bytes32("d1"), address(0)); vm.stopPrank(); Deposit[] memory deposits = new Deposit[](1); @@ -703,7 +730,8 @@ contract ZoneIntegrationTest is BaseTest { sender: alice, to: alice, amount: 10_000e6, - memo: bytes32("d1") + memo: bytes32("d1"), + bouncebackRecipient: address(0) }); l2TempoState.setMockStorageValue( address(l1Portal), PORTAL_CURRENT_DEPOSIT_QUEUE_HASH_SLOT, d1 @@ -738,7 +766,7 @@ contract ZoneIntegrationTest is BaseTest { // Make a deposit to get a non-zero currentDepositQueueHash vm.startPrank(alice); l2ZoneToken.approve(address(l1Portal), 1000e6); - l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("layout-test")); + l1Portal.deposit(address(l2ZoneToken), alice, 1000e6, bytes32("layout-test"), address(0)); vm.stopPrank(); // Read via vm.load using our constant diff --git a/specs/ref-impls/test/zone/ZoneOutbox.t.sol b/specs/ref-impls/test/zone/ZoneOutbox.t.sol index 7428bec7e..9142aa17d 100644 --- a/specs/ref-impls/test/zone/ZoneOutbox.t.sol +++ b/specs/ref-impls/test/zone/ZoneOutbox.t.sol @@ -42,8 +42,8 @@ contract ZoneOutboxTest is Test { tempoState.setMockStorageValue( mockPortal, bytes32(uint256(0)), bytes32(uint256(uint160(sequencer))) ); - inbox = new ZoneInbox(address(config), mockPortal, address(tempoState)); outbox = new ZoneOutbox(address(config)); + inbox = new ZoneInbox(address(config), mockPortal, address(tempoState), address(outbox)); // Grant minter role to inbox and burner role to outbox zoneToken.setMinter(address(inbox), true); diff --git a/specs/ref-impls/test/zone/ZonePortal.t.sol b/specs/ref-impls/test/zone/ZonePortal.t.sol index 4e4bfecf6..e66ff27dd 100644 --- a/specs/ref-impls/test/zone/ZonePortal.t.sol +++ b/specs/ref-impls/test/zone/ZonePortal.t.sol @@ -250,7 +250,8 @@ contract ZonePortalTest is BaseTest { // Approve and deposit vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - bytes32 hash1 = portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo1")); + bytes32 hash1 = + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo1"), address(0)); vm.stopPrank(); // Verify hash chain updated @@ -268,13 +269,14 @@ contract ZonePortalTest is BaseTest { // First deposit from alice vm.startPrank(alice); pathUSD.approve(address(portal), amount1); - bytes32 hash1 = portal.deposit(address(pathUSD), alice, amount1, bytes32("memo1")); + bytes32 hash1 = + portal.deposit(address(pathUSD), alice, amount1, bytes32("memo1"), address(0)); vm.stopPrank(); // Second deposit from bob vm.startPrank(bob); pathUSD.approve(address(portal), amount2); - bytes32 hash2 = portal.deposit(address(pathUSD), bob, amount2, bytes32("memo2")); + bytes32 hash2 = portal.deposit(address(pathUSD), bob, amount2, bytes32("memo2"), address(0)); vm.stopPrank(); // Hash chain should have updated @@ -297,15 +299,15 @@ contract ZonePortalTest is BaseTest { assertEq(initialHash, bytes32(0)); // After deposit 1 - portal.deposit(address(pathUSD), alice, amount, bytes32("d1")); + portal.deposit(address(pathUSD), alice, amount, bytes32("d1"), address(0)); bytes32 hash1 = portal.currentDepositQueueHash(); // After deposit 2: hash2 = keccak256(abi.encode(message2, hash1)) - portal.deposit(address(pathUSD), alice, amount, bytes32("d2")); + portal.deposit(address(pathUSD), alice, amount, bytes32("d2"), address(0)); bytes32 hash2 = portal.currentDepositQueueHash(); // After deposit 3: hash3 = keccak256(abi.encode(message3, hash2)) - portal.deposit(address(pathUSD), alice, amount, bytes32("d3")); + portal.deposit(address(pathUSD), alice, amount, bytes32("d3"), address(0)); bytes32 hash3 = portal.currentDepositQueueHash(); vm.stopPrank(); @@ -348,7 +350,7 @@ contract ZonePortalTest is BaseTest { vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); vm.expectRevert(IZonePortal.DepositPolicyForbids.selector); - portal.deposit(address(pathUSD), bob, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), bob, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); } @@ -383,7 +385,8 @@ contract ZonePortalTest is BaseTest { vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - bytes32 depositHash = portal.deposit(address(pathUSD), bob, depositAmount, bytes32("memo")); + bytes32 depositHash = + portal.deposit(address(pathUSD), bob, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); assertEq(portal.currentDepositQueueHash(), depositHash); @@ -400,7 +403,7 @@ contract ZonePortalTest is BaseTest { vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); bytes32 depositHash = - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); // Submit a batch (as sequencer) @@ -515,7 +518,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); // Create a withdrawal and add to queue via batch @@ -567,7 +570,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 2000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); // Create two withdrawals in the same batch @@ -627,7 +630,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 3000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); // Batch 1: withdrawal to bob @@ -696,7 +699,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); uint256 tailBefore = portal.withdrawalQueueTail(); @@ -732,7 +735,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); // Create withdrawal with callback @@ -784,7 +787,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); bytes32 depositHashBefore = portal.currentDepositQueueHash(); @@ -841,7 +844,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); bytes32 depositHashBefore = portal.currentDepositQueueHash(); @@ -894,7 +897,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); bytes32 depositHashBefore = portal.currentDepositQueueHash(); @@ -957,7 +960,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); Withdrawal memory w = @@ -996,7 +999,7 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo")); + portal.deposit(address(pathUSD), alice, depositAmount, bytes32("memo"), address(0)); vm.stopPrank(); Withdrawal memory w = @@ -1044,8 +1047,8 @@ contract ZonePortalTest is BaseTest { // Make deposits vm.startPrank(alice); pathUSD.approve(address(portal), 3000e6); - bytes32 h1 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d1")); - bytes32 h2 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d2")); + bytes32 h1 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d1"), address(0)); + bytes32 h2 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d2"), address(0)); vm.stopPrank(); // currentDepositQueueHash should be h2 (latest) @@ -1078,7 +1081,7 @@ contract ZonePortalTest is BaseTest { // New deposit arrives vm.startPrank(alice); - bytes32 h3 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d3")); + bytes32 h3 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d3"), address(0)); vm.stopPrank(); // currentDepositQueueHash updated @@ -1261,7 +1264,7 @@ contract ZonePortalTest is BaseTest { // Make a deposit first vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("memo")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32("memo"), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1296,8 +1299,8 @@ contract ZonePortalTest is BaseTest { // Make deposits vm.startPrank(alice); pathUSD.approve(address(portal), 3000e6); - bytes32 h1 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d1")); - bytes32 h2 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d2")); + bytes32 h1 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d1"), address(0)); + bytes32 h2 = portal.deposit(address(pathUSD), alice, 1000e6, bytes32("d2"), address(0)); vm.stopPrank(); vm.roll(block.number + 1); @@ -1352,7 +1355,7 @@ contract ZonePortalTest is BaseTest { function test_withdrawalQueue_emptyBatchDoesNotIncreaseTail() public { vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1386,7 +1389,7 @@ contract ZonePortalTest is BaseTest { // Fund portal vm.startPrank(alice); pathUSD.approve(address(portal), 10_000e6); - portal.deposit(address(pathUSD), alice, 10_000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 10_000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1451,7 +1454,7 @@ contract ZonePortalTest is BaseTest { // Fund portal vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHashBefore = portal.currentDepositQueueHash(); @@ -1499,7 +1502,7 @@ contract ZonePortalTest is BaseTest { // Fund portal vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1541,7 +1544,7 @@ contract ZonePortalTest is BaseTest { // Fund portal vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1590,7 +1593,7 @@ contract ZonePortalTest is BaseTest { // Fund portal vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHashBefore = portal.currentDepositQueueHash(); @@ -1637,7 +1640,8 @@ contract ZonePortalTest is BaseTest { sender: address(portal), to: bob, amount: 500e6, - memo: bytes32(0) + memo: bytes32(0), + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Regular, expectedBounceBack, depositHashBefore)); @@ -1651,7 +1655,7 @@ contract ZonePortalTest is BaseTest { function test_withdrawalBatchIndex_incrementsOnEachBatch() public { vm.startPrank(alice); pathUSD.approve(address(portal), 3000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); bytes32 depositHash = portal.currentDepositQueueHash(); @@ -1729,16 +1733,25 @@ contract ZonePortalTest is BaseTest { sender: alice, to: bob, amount: netAmount, - memo: bytes32("test") + memo: bytes32("test"), + bouncebackRecipient: address(0) }), bytes32(0) ) ); emit IZonePortal.DepositMade( - expectedHash, alice, address(pathUSD), bob, netAmount, fee, bytes32("test"), 1 + expectedHash, + alice, + address(pathUSD), + bob, + netAmount, + fee, + bytes32("test"), + address(0), + 1 ); - portal.deposit(address(pathUSD), bob, 500e6, bytes32("test")); + portal.deposit(address(pathUSD), bob, 500e6, bytes32("test"), address(0)); vm.stopPrank(); } @@ -1746,7 +1759,7 @@ contract ZonePortalTest is BaseTest { // Setup withdrawal vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); Withdrawal memory w = @@ -1779,7 +1792,7 @@ contract ZonePortalTest is BaseTest { // Setup withdrawal with failing callback vm.startPrank(alice); pathUSD.approve(address(portal), 1000e6); - portal.deposit(address(pathUSD), alice, 1000e6, bytes32("")); + portal.deposit(address(pathUSD), alice, 1000e6, bytes32(""), address(0)); vm.stopPrank(); Withdrawal memory w = _withdrawal( @@ -2056,8 +2069,9 @@ contract ZonePortalTest is BaseTest { uint128 depositAmount = 1000e6; vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - bytes32 hash = - portal.depositEncrypted(address(pathUSD), depositAmount, 0, _makeEncryptedPayload()); + bytes32 hash = portal.depositEncrypted( + address(pathUSD), depositAmount, 0, _makeEncryptedPayload(), address(0) + ); vm.stopPrank(); assertEq(portal.currentDepositQueueHash(), hash); @@ -2075,7 +2089,8 @@ contract ZonePortalTest is BaseTest { vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - bytes32 hash = portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted); + bytes32 hash = + portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted, address(0)); vm.stopPrank(); // Reconstruct expected hash using the same encoding as DepositQueueLib @@ -2084,7 +2099,8 @@ contract ZonePortalTest is BaseTest { sender: alice, amount: netAmount, keyIndex: 0, - encrypted: encrypted + encrypted: encrypted, + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Encrypted, ed, bytes32(0))); assertEq(hash, expectedHash); @@ -2098,10 +2114,12 @@ contract ZonePortalTest is BaseTest { // Regular deposit from alice vm.startPrank(alice); pathUSD.approve(address(portal), amount * 3); - bytes32 h1 = portal.deposit(address(pathUSD), alice, amount, bytes32("memo")); + bytes32 h1 = portal.deposit(address(pathUSD), alice, amount, bytes32("memo"), address(0)); // Encrypted deposit from alice - bytes32 h2 = portal.depositEncrypted(address(pathUSD), amount, 0, _makeEncryptedPayload()); + bytes32 h2 = portal.depositEncrypted( + address(pathUSD), amount, 0, _makeEncryptedPayload(), address(0) + ); vm.stopPrank(); // Both should update the same queue @@ -2122,7 +2140,9 @@ contract ZonePortalTest is BaseTest { vm.startPrank(alice); pathUSD.approve(address(portal), depositAmount); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, _makeEncryptedPayload()); + portal.depositEncrypted( + address(pathUSD), depositAmount, 0, _makeEncryptedPayload(), address(0) + ); vm.stopPrank(); assertEq(pathUSD.balanceOf(alice), aliceBefore - depositAmount); @@ -2148,7 +2168,8 @@ contract ZonePortalTest is BaseTest { sender: alice, amount: netAmount, keyIndex: 0, - encrypted: encrypted + encrypted: encrypted, + bouncebackRecipient: address(0) }); bytes32 expectedHash = keccak256(abi.encode(DepositType.Encrypted, ed, bytes32(0))); @@ -2167,7 +2188,7 @@ contract ZonePortalTest is BaseTest { encrypted.tag, 1 ); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted); + portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted, address(0)); vm.stopPrank(); } @@ -2188,7 +2209,9 @@ contract ZonePortalTest is BaseTest { // Should revert with EncryptionKeyExpired for key index 0 vm.expectRevert(); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, _makeEncryptedPayload()); + portal.depositEncrypted( + address(pathUSD), depositAmount, 0, _makeEncryptedPayload(), address(0) + ); vm.stopPrank(); } @@ -2199,7 +2222,9 @@ contract ZonePortalTest is BaseTest { // No keys set, index 0 is invalid vm.expectRevert(abi.encodeWithSelector(IZonePortal.InvalidEncryptionKeyIndex.selector, 0)); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, _makeEncryptedPayload()); + portal.depositEncrypted( + address(pathUSD), depositAmount, 0, _makeEncryptedPayload(), address(0) + ); vm.stopPrank(); } @@ -2219,7 +2244,7 @@ contract ZonePortalTest is BaseTest { }); vm.expectRevert(IZonePortal.InvalidEphemeralPubkey.selector); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted); + portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted, address(0)); vm.stopPrank(); } @@ -2239,7 +2264,7 @@ contract ZonePortalTest is BaseTest { }); vm.expectRevert(IZonePortal.InvalidEphemeralPubkey.selector); - portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted); + portal.depositEncrypted(address(pathUSD), depositAmount, 0, encrypted, address(0)); vm.stopPrank(); } @@ -2251,7 +2276,7 @@ contract ZonePortalTest is BaseTest { pathUSD.approve(address(portal), 100_000); vm.expectRevert(IZonePortal.DepositTooSmall.selector); - portal.depositEncrypted(address(pathUSD), 100_000, 0, _makeEncryptedPayload()); // amount == fee + portal.depositEncrypted(address(pathUSD), 100_000, 0, _makeEncryptedPayload(), address(0)); // amount == fee vm.stopPrank(); } @@ -2267,7 +2292,7 @@ contract ZonePortalTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(IZonePortal.InvalidCiphertextLength.selector, 63, 64) ); - portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload); + portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload, address(0)); vm.stopPrank(); } @@ -2283,7 +2308,7 @@ contract ZonePortalTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(IZonePortal.InvalidCiphertextLength.selector, 65, 64) ); - portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload); + portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload, address(0)); vm.stopPrank(); } @@ -2297,7 +2322,7 @@ contract ZonePortalTest is BaseTest { pathUSD.approve(address(portal), 1000e6); vm.expectRevert(abi.encodeWithSelector(IZonePortal.InvalidCiphertextLength.selector, 0, 64)); - portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload); + portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload, address(0)); vm.stopPrank(); } @@ -2313,7 +2338,7 @@ contract ZonePortalTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(IZonePortal.InvalidCiphertextLength.selector, 1024, 64) ); - portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload); + portal.depositEncrypted(address(pathUSD), 1000e6, 0, payload, address(0)); vm.stopPrank(); } diff --git a/specs/spec.md b/specs/spec.md index 1fe7e2ba3..65ae75393 100644 --- a/specs/spec.md +++ b/specs/spec.md @@ -1061,23 +1061,26 @@ interface IZonePortal { // Events event DepositMade( bytes32 indexed newCurrentDepositQueueHash, address indexed sender, - address token, address to, uint128 netAmount, uint128 fee, bytes32 memo + address token, address to, uint128 netAmount, uint128 fee, bytes32 memo, + address bouncebackRecipient, uint64 depositNumber ); event EncryptedDepositMade( bytes32 indexed newCurrentDepositQueueHash, address indexed sender, address token, uint128 netAmount, uint128 fee, uint256 keyIndex, bytes32 ephemeralPubkeyX, uint8 ephemeralPubkeyYParity, - bytes ciphertext, bytes12 nonce, bytes16 tag + bytes ciphertext, bytes12 nonce, bytes16 tag, uint64 depositNumber ); event BatchSubmitted( uint64 indexed withdrawalBatchIndex, bytes32 nextProcessedDepositQueueHash, - bytes32 nextBlockHash, bytes32 withdrawalQueueHash + bytes32 nextBlockHash, bytes32 withdrawalQueueHash, + uint64 lastProcessedDepositNumber ); event WithdrawalProcessed(address indexed to, address token, uint128 amount, bool callbackSuccess); - event BounceBack( + event WithdrawalBounceBack( bytes32 indexed newCurrentDepositQueueHash, address indexed fallbackRecipient, - address token, uint128 amount + address token, uint128 amount, uint64 depositNumber ); + event DepositBounceBack(address indexed bouncebackRecipient, address token, uint128 amount); event SequencerTransferStarted(address indexed currentSequencer, address indexed pendingSequencer); event SequencerTransferred(address indexed previousSequencer, address indexed newSequencer); event SequencerEncryptionKeyUpdated(bytes32 x, uint8 yParity, uint256 keyIndex, uint64 activationBlock); @@ -1096,11 +1099,16 @@ interface IZonePortal { function enabledTokenAt(uint256 index) external view returns (address); // Deposits - function deposit(address token, address to, uint128 amount, bytes32 memo) - external returns (bytes32 newCurrentDepositQueueHash); - function depositEncrypted(address token, uint128 amount, uint256 keyIndex, EncryptedDepositPayload calldata encrypted) - external returns (bytes32 newCurrentDepositQueueHash); + function deposit( + address token, address to, uint128 amount, bytes32 memo, address bouncebackRecipient + ) external returns (bytes32 newCurrentDepositQueueHash); + function depositEncrypted( + address token, uint128 amount, uint256 keyIndex, + EncryptedDepositPayload calldata encrypted, address bouncebackRecipient + ) external returns (bytes32 newCurrentDepositQueueHash); function calculateDepositFee() external view returns (uint128 fee); + function depositCount() external view returns (uint64); + function lastProcessedDepositNumber() external view returns (uint64); // Batch submission function submitBatch( diff --git a/xtask/src/demo_blacklist.rs b/xtask/src/demo_blacklist.rs index db9649f7d..aa0a97ab2 100644 --- a/xtask/src/demo_blacklist.rs +++ b/xtask/src/demo_blacklist.rs @@ -329,7 +329,7 @@ impl DemoBlacklist { let mut pending = None; for attempt in 0..5u32 { match portal - .deposit(token_addr, admin, deposit_amount, B256::ZERO) + .deposit(token_addr, admin, deposit_amount, B256::ZERO, Address::ZERO) .send() .await { @@ -467,7 +467,13 @@ impl DemoBlacklist { let gas_fund: u128 = 100_000; let l2_block_before = l2.get_block_number().await.unwrap_or(0); let receipt = portal - .deposit(PATH_USD_ADDRESS, target, gas_fund, B256::ZERO) + .deposit( + PATH_USD_ADDRESS, + target, + gas_fund, + B256::ZERO, + Address::ZERO, + ) .send_sync() .await?; check(&receipt, "deposit pathUSD to target for gas")?; @@ -646,7 +652,7 @@ async fn send_encrypted_deposit>( }; let receipt = portal - .depositEncrypted(token, amount, key_index, payload) + .depositEncrypted(token, amount, key_index, payload, Address::ZERO) .send_sync() .await .wrap_err("depositEncrypted send failed")?; diff --git a/xtask/src/demo_swap_and_deposit.rs b/xtask/src/demo_swap_and_deposit.rs index c2861cfeb..fe17082e1 100644 --- a/xtask/src/demo_swap_and_deposit.rs +++ b/xtask/src/demo_swap_and_deposit.rs @@ -264,6 +264,7 @@ impl DemoSwapAndDeposit { operator, pathusd_gross_deposit, B256::ZERO, + Address::ZERO, ) .send_sync() .await @@ -279,7 +280,13 @@ impl DemoSwapAndDeposit { .await .wrap_err("failed to approve AlphaUSD for portal")?; let receipt = portal_contract - .deposit(alpha, operator, alpha_gross_deposit, B256::ZERO) + .deposit( + alpha, + operator, + alpha_gross_deposit, + B256::ZERO, + Address::ZERO, + ) .send_sync() .await .wrap_err("failed to deposit AlphaUSD to the zone")?; diff --git a/xtask/src/encrypted_deposit.rs b/xtask/src/encrypted_deposit.rs index d4f215acb..9a7154cd2 100644 --- a/xtask/src/encrypted_deposit.rs +++ b/xtask/src/encrypted_deposit.rs @@ -117,7 +117,7 @@ impl EncryptedDeposit { println!("Sending encrypted deposit of {} to {to}...", self.amount); let receipt = portal - .depositEncrypted(self.token, self.amount, key_index, payload) + .depositEncrypted(self.token, self.amount, key_index, payload, Address::ZERO) .send_sync() .await .wrap_err("failed to send depositEncrypted transaction")?; diff --git a/xtask/src/generate_zone_genesis.rs b/xtask/src/generate_zone_genesis.rs index 077256891..411bd5757 100644 --- a/xtask/src/generate_zone_genesis.rs +++ b/xtask/src/generate_zone_genesis.rs @@ -162,8 +162,13 @@ impl GenerateZoneGenesis { nonce += 1; let zone_inbox_bytecode = load_artifact(&self.specs_out, "ZoneInbox")?; - let zone_inbox_args = - (ZONE_CONFIG_ADDRESS, self.tempo_portal, TEMPO_STATE_ADDRESS).abi_encode_params(); + let zone_inbox_args = ( + ZONE_CONFIG_ADDRESS, + self.tempo_portal, + TEMPO_STATE_ADDRESS, + ZONE_OUTBOX_ADDRESS, + ) + .abi_encode_params(); deploy_contract( &mut evm, &zone_inbox_bytecode, diff --git a/xtask/src/spam_deposits.rs b/xtask/src/spam_deposits.rs index 81c15f6d1..82d40cbd6 100644 --- a/xtask/src/spam_deposits.rs +++ b/xtask/src/spam_deposits.rs @@ -325,6 +325,7 @@ impl SpamDeposits { amount: self.amount, keyIndex: key_index, encrypted: payload, + bouncebackRecipient: Address::ZERO, } .abi_encode()) } else { @@ -333,6 +334,7 @@ impl SpamDeposits { to: recipient, amount: self.amount, memo: B256::ZERO, + bouncebackRecipient: Address::ZERO, } .abi_encode()) }