From 310698b2fb8722d318080b0031842c02cb5bd056 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 19 Dec 2024 22:31:04 +0000 Subject: [PATCH 01/16] fix: normalize transferred tokens by decimals --- evm/src/omni-bridge/contracts/BridgeTypes.sol | 3 +- evm/src/omni-bridge/contracts/OmniBridge.sol | 35 ++++++++++-- .../contracts/OmniBridgeWormhole.sol | 6 +- near/omni-bridge/src/lib.rs | 55 +++++++++++++++++-- near/omni-bridge/src/storage.rs | 6 ++ .../src/parsed_vaa.rs | 4 ++ near/omni-types/src/evm/events.rs | 13 +++-- near/omni-types/src/prover_result.rs | 2 + .../bridge_token_factory/src/constants.rs | 3 + .../src/instructions/user/deploy_token.rs | 10 +++- .../src/state/message/deploy_token.rs | 2 + 11 files changed, 119 insertions(+), 20 deletions(-) diff --git a/evm/src/omni-bridge/contracts/BridgeTypes.sol b/evm/src/omni-bridge/contracts/BridgeTypes.sol index 4f7e048f..2d0e381b 100644 --- a/evm/src/omni-bridge/contracts/BridgeTypes.sol +++ b/evm/src/omni-bridge/contracts/BridgeTypes.sol @@ -44,7 +44,8 @@ library BridgeTypes { string token, string name, string symbol, - uint8 decimals + uint8 decimals, + uint8 originNonce ); event LogMetadata( diff --git a/evm/src/omni-bridge/contracts/OmniBridge.sol b/evm/src/omni-bridge/contracts/OmniBridge.sol index e6f852f6..807de606 100644 --- a/evm/src/omni-bridge/contracts/OmniBridge.sol +++ b/evm/src/omni-bridge/contracts/OmniBridge.sol @@ -59,11 +59,26 @@ contract OmniBridge is _grantRole(PAUSABLE_ADMIN_ROLE, _msgSender()); } - function addCustomToken(string calldata nearTokenId, address tokenAddress, address customMinter) external onlyRole(DEFAULT_ADMIN_ROLE) { + function addCustomToken(string calldata nearTokenId, address tokenAddress, address customMinter, uint8 originDecimals) external onlyRole(DEFAULT_ADMIN_ROLE) { isBridgeToken[tokenAddress] = true; ethToNearToken[tokenAddress] = nearTokenId; nearToEthToken[nearTokenId] = tokenAddress; customMinters[tokenAddress] = customMinter; + + string memory name = IERC20Metadata(tokenAddress).name(); + string memory symbol = IERC20Metadata(tokenAddress).symbol(); + uint8 decimals = IERC20Metadata(tokenAddress).decimals(); + + deployTokenExtension(nearTokenId, tokenAddress, decimals, originDecimals); + + emit BridgeTypes.DeployToken( + tokenAddress, + nearTokenId, + name, + symbol, + decimals, + originDecimals + ); } function removeCustomToken(address tokenAddress) external onlyRole(DEFAULT_ADMIN_ROLE) { @@ -88,6 +103,7 @@ contract OmniBridge is } require(!isBridgeToken[nearToEthToken[metadata.token]], "ERR_TOKEN_EXIST"); + uint8 decimals = _normalizeDecimals(metadata.decimals); address bridgeTokenProxy = address( new ERC1967Proxy( @@ -96,18 +112,19 @@ contract OmniBridge is BridgeToken.initialize.selector, metadata.name, metadata.symbol, - metadata.decimals + decimals ) ) ); - deployTokenExtension(metadata.token, bridgeTokenProxy); + deployTokenExtension(metadata.token, bridgeTokenProxy, decimals, metadata.decimals); emit BridgeTypes.DeployToken( bridgeTokenProxy, metadata.token, metadata.name, metadata.symbol, + decimals, metadata.decimals ); @@ -118,7 +135,7 @@ contract OmniBridge is return bridgeTokenProxy; } - function deployTokenExtension(string memory token, address tokenAddress) internal virtual {} + function deployTokenExtension(string memory token, address tokenAddress, uint8 decimals, uint8 originDecimals) internal virtual {} function setMetadata( string calldata token, @@ -283,6 +300,16 @@ contract OmniBridge is proxy.upgradeToAndCall(implementation, bytes("")); } + function _normalizeDecimals( + uint8 decimals + ) internal pure returns (uint8) { + uint8 maxAllowedDecimals = 18; + if (decimals > maxAllowedDecimals) { + return maxAllowedDecimals; + } + return decimals; + } + function _authorizeUpgrade( address newImplementation ) internal override onlyRole(DEFAULT_ADMIN_ROLE) {} diff --git a/evm/src/omni-bridge/contracts/OmniBridgeWormhole.sol b/evm/src/omni-bridge/contracts/OmniBridgeWormhole.sol index 855e556b..d59bb369 100644 --- a/evm/src/omni-bridge/contracts/OmniBridgeWormhole.sol +++ b/evm/src/omni-bridge/contracts/OmniBridgeWormhole.sol @@ -38,12 +38,14 @@ contract OmniBridgeWormhole is OmniBridge { _consistencyLevel = consistencyLevel; } - function deployTokenExtension(string memory token, address tokenAddress) internal override { + function deployTokenExtension(string memory token, address tokenAddress, uint8 decimals, uint8 originDecimals) internal override { bytes memory payload = bytes.concat( bytes1(uint8(MessageType.DeployToken)), Borsh.encodeString(token), bytes1(omniBridgeChainId), - Borsh.encodeAddress(tokenAddress) + Borsh.encodeAddress(tokenAddress), + bytes1(decimals), + bytes1(originDecimals) ); _wormhole.publishMessage{value: msg.value}( wormholeNonce, diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index 0fcff7e8..970f3bde 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -27,7 +27,7 @@ use omni_types::{ BasicMetadata, ChainKind, Fee, InitTransferMsg, MetadataPayload, Nonce, OmniAddress, PayloadType, SignRequest, TransferId, TransferMessage, TransferMessagePayload, UpdateFee, }; -use storage::{TransferMessageStorage, TransferMessageStorageValue, NEP141_DEPOSIT}; +use storage::{Decimals, TransferMessageStorage, TransferMessageStorageValue, NEP141_DEPOSIT}; mod errors; mod storage; @@ -70,6 +70,7 @@ enum StorageKey { TokenDeployerAccounts, DeployedTokens, DestinationNonces, + TokenDecimals, } #[derive(AccessControlRole, Deserialize, Serialize, Copy, Clone)] @@ -164,6 +165,7 @@ pub struct Contract { pub finalised_transfers: LookupSet, pub token_id_to_address: LookupMap<(ChainKind, AccountId), OmniAddress>, pub token_address_to_id: LookupMap, + pub token_decimals: LookupMap, pub deployed_tokens: LookupSet, pub token_deployer_accounts: LookupMap, pub mpc_signer: AccountId, @@ -248,6 +250,7 @@ impl Contract { finalised_transfers: LookupSet::new(StorageKey::FinalisedTransfers), token_id_to_address: LookupMap::new(StorageKey::TokenIdToAddress), token_address_to_id: LookupMap::new(StorageKey::TokenAddressToId), + token_decimals: LookupMap::new(StorageKey::TokenDecimals), deployed_tokens: LookupSet::new(StorageKey::DeployedTokens), token_deployer_accounts: LookupMap::new(StorageKey::TokenDeployerAccounts), mpc_signer, @@ -398,12 +401,18 @@ impl Contract { ) .unwrap_or_else(|| env::panic_str("ERR_FAILED_TO_GET_TOKEN_ADDRESS")); + let decimals = self.token_decimals.get(&token_address); + let amount_to_transfer = Self::normalize_amount( + transfer_message.amount.0 - transfer_message.fee.fee.0, + decimals, + ); + let transfer_payload = TransferMessagePayload { prefix: PayloadType::TransferMessage, destination_nonce: transfer_message.destination_nonce, transfer_id, token_address, - amount: U128(transfer_message.amount.0 - transfer_message.fee.fee.0), + amount: U128(amount_to_transfer), recipient: transfer_message.recipient, fee_recipient, }; @@ -495,14 +504,19 @@ impl Contract { "Unknown factory" ); + let decimals = self.token_decimals.get(&init_transfer.token); + let destination_nonce = self.get_next_destination_nonce(init_transfer.recipient.get_chain()); let transfer_message = TransferMessage { origin_nonce: init_transfer.origin_nonce, token: init_transfer.token, - amount: init_transfer.amount, + amount: Self::de_normalize_amount(init_transfer.amount.0, decimals).into(), recipient: init_transfer.recipient, - fee: init_transfer.fee, + fee: Fee { + fee: Self::de_normalize_amount(init_transfer.fee.fee.0, decimals).into(), + native_fee: init_transfer.fee.native_fee, + }, sender: init_transfer.sender, msg: init_transfer.msg, destination_nonce, @@ -564,7 +578,11 @@ impl Contract { ); let message = self.remove_transfer_message(fin_transfer.transfer_id); - let fee = message.amount.0 - fin_transfer.amount.0; + let de_normalized_amount = Self::de_normalize_amount( + fin_transfer.amount.0, + self.token_decimals.get(&message.token), + ); + let fee = message.amount.0 - de_normalized_amount; if message.fee.native_fee.0 != 0 { if message.get_origin_chain() == ChainKind::Near { @@ -774,6 +792,15 @@ impl Contract { ); self.token_address_to_id .insert(&deploy_token.token_address, &deploy_token.token); + + self.token_decimals.insert( + &deploy_token.token_address, + &Decimals { + decimals: deploy_token.decimals, + origin_decimals: deploy_token.origin_decimals, + }, + ); + let required_deposit = env::storage_byte_cost() .saturating_mul((env::storage_usage().saturating_sub(storage_usage)).into()); @@ -1192,4 +1219,22 @@ impl Contract { Promise::new(account_id).transfer(amount); } } + + fn de_normalize_amount(amount: u128, decimals: Option) -> u128 { + if let Some(decimals) = decimals { + let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); + amount * 10 ^ diff_decimals + } else { + amount + } + } + + fn normalize_amount(amount: u128, decimals: Option) -> u128 { + if let Some(decimals) = decimals { + let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); + amount / 10 ^ diff_decimals + } else { + amount + } + } } diff --git a/near/omni-bridge/src/storage.rs b/near/omni-bridge/src/storage.rs index aa1db87a..cfaaf5ed 100644 --- a/near/omni-bridge/src/storage.rs +++ b/near/omni-bridge/src/storage.rs @@ -40,6 +40,12 @@ impl TransferMessageStorage { } } +#[derive(BorshDeserialize, BorshSerialize, Debug, Clone, Copy, PartialEq, Eq)] +pub struct Decimals { + pub decimals: u8, + pub origin_decimals: u8, +} + #[near_bindgen] impl Contract { #[payable] diff --git a/near/omni-prover/wormhole-omni-prover-proxy/src/parsed_vaa.rs b/near/omni-prover/wormhole-omni-prover-proxy/src/parsed_vaa.rs index 235c6a18..01f524a3 100644 --- a/near/omni-prover/wormhole-omni-prover-proxy/src/parsed_vaa.rs +++ b/near/omni-prover/wormhole-omni-prover-proxy/src/parsed_vaa.rs @@ -118,6 +118,8 @@ struct DeployTokenWh { payload_type: ProofKind, token: String, token_address: OmniAddress, + decimals: u8, + origin_decimals: u8, } #[derive(Debug, BorshDeserialize)] @@ -215,6 +217,8 @@ impl TryInto for ParsedVAA { Ok(DeployTokenMessage { token: parsed_payload.token.parse().map_err(stringify)?, token_address: parsed_payload.token_address.clone(), + decimals: parsed_payload.decimals, + origin_decimals: parsed_payload.origin_decimals, emitter_address: OmniAddress::new_from_slice( parsed_payload.token_address.get_chain(), &self.emitter_address, diff --git a/near/omni-types/src/evm/events.rs b/near/omni-types/src/evm/events.rs index 4cdc3542..9f5b250b 100644 --- a/near/omni-types/src/evm/events.rs +++ b/near/omni-types/src/evm/events.rs @@ -37,7 +37,8 @@ sol! { string token, string name, string symbol, - uint8 decimals + uint8 decimals, + uint8 originDecimals ); event LogMetadata( @@ -128,15 +129,17 @@ impl TryFromLog> for DeployTokenMessage { } Ok(DeployTokenMessage { - emitter_address: OmniAddress::new_from_evm_address( - chain_kind, - H160(event.address.into()), - )?, token: event.data.token.parse().map_err(stringify)?, token_address: OmniAddress::new_from_evm_address( chain_kind, H160(event.data.tokenAddress.into()), )?, + decimals: event.data.decimals, + origin_decimals: event.data.originDecimals, + emitter_address: OmniAddress::new_from_evm_address( + chain_kind, + H160(event.address.into()), + )?, }) } } diff --git a/near/omni-types/src/prover_result.rs b/near/omni-types/src/prover_result.rs index 71868d4e..9a40b1aa 100644 --- a/near/omni-types/src/prover_result.rs +++ b/near/omni-types/src/prover_result.rs @@ -29,6 +29,8 @@ pub struct FinTransferMessage { pub struct DeployTokenMessage { pub token: AccountId, pub token_address: OmniAddress, + pub decimals: u8, + pub origin_decimals: u8, pub emitter_address: OmniAddress, } diff --git a/solana/bridge_token_factory/programs/bridge_token_factory/src/constants.rs b/solana/bridge_token_factory/programs/bridge_token_factory/src/constants.rs index bb12b994..4c6cebbe 100644 --- a/solana/bridge_token_factory/programs/bridge_token_factory/src/constants.rs +++ b/solana/bridge_token_factory/programs/bridge_token_factory/src/constants.rs @@ -26,3 +26,6 @@ pub const USED_NONCES_ACCOUNT_SIZE: u32 = 8 + (USED_NONCES_PER_ACCOUNT + 7) / 8; #[constant] pub const SOLANA_OMNI_BRIDGE_CHAIN_ID: u8 = 2; + +#[constant] +pub const MAX_ALLOWED_DECIMALS: u8 = 9; \ No newline at end of file diff --git a/solana/bridge_token_factory/programs/bridge_token_factory/src/instructions/user/deploy_token.rs b/solana/bridge_token_factory/programs/bridge_token_factory/src/instructions/user/deploy_token.rs index b88d2034..9fbe8198 100644 --- a/solana/bridge_token_factory/programs/bridge_token_factory/src/instructions/user/deploy_token.rs +++ b/solana/bridge_token_factory/programs/bridge_token_factory/src/instructions/user/deploy_token.rs @@ -1,4 +1,4 @@ -use crate::constants::{AUTHORITY_SEED, WRAPPED_MINT_SEED}; +use crate::constants::{AUTHORITY_SEED, MAX_ALLOWED_DECIMALS, WRAPPED_MINT_SEED}; use crate::instructions::wormhole_cpi::*; use crate::state::message::SignedPayload; use crate::state::message::{ @@ -25,7 +25,7 @@ pub struct DeployToken<'info> { payer = wormhole.payer, seeds = [WRAPPED_MINT_SEED, data.payload.token.as_bytes().as_ref()], bump, - mint::decimals = data.payload.decimals, + mint::decimals = std::cmp::min(MAX_ALLOWED_DECIMALS, data.payload.decimals), mint::authority = authority, )] pub mint: Box>, @@ -49,9 +49,11 @@ pub struct DeployToken<'info> { } impl<'info> DeployToken<'info> { - pub fn initialize_token_metadata(&self, metadata: DeployTokenPayload) -> Result<()> { + pub fn initialize_token_metadata(&self, mut metadata: DeployTokenPayload) -> Result<()> { let bump = &[self.wormhole.config.bumps.authority]; let signer_seeds = &[&[AUTHORITY_SEED, bump][..]]; + let origin_decimals = metadata.decimals; + metadata.decimals = std::cmp::min(MAX_ALLOWED_DECIMALS, metadata.decimals); let cpi_accounts = CreateMetadataAccountsV3 { payer: self.wormhole.payer.to_account_info(), @@ -86,6 +88,8 @@ impl<'info> DeployToken<'info> { let payload = DeployTokenResponse { token: metadata.token, solana_mint: self.mint.key(), + decimals: metadata.decimals, + origin_decimals, } .serialize_for_near(())?; diff --git a/solana/bridge_token_factory/programs/bridge_token_factory/src/state/message/deploy_token.rs b/solana/bridge_token_factory/programs/bridge_token_factory/src/state/message/deploy_token.rs index 96b89b6b..110d230c 100644 --- a/solana/bridge_token_factory/programs/bridge_token_factory/src/state/message/deploy_token.rs +++ b/solana/bridge_token_factory/programs/bridge_token_factory/src/state/message/deploy_token.rs @@ -30,6 +30,8 @@ impl Payload for DeployTokenPayload { pub struct DeployTokenResponse { pub token: String, pub solana_mint: Pubkey, + pub decimals: u8, + pub origin_decimals: u8, } impl Payload for DeployTokenResponse { From 2e8df29dfb807783219c8b8e9102e03a4a18ee9a Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 19 Dec 2024 22:32:22 +0000 Subject: [PATCH 02/16] Fix naming --- evm/src/omni-bridge/contracts/BridgeTypes.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/omni-bridge/contracts/BridgeTypes.sol b/evm/src/omni-bridge/contracts/BridgeTypes.sol index 2d0e381b..ab63366f 100644 --- a/evm/src/omni-bridge/contracts/BridgeTypes.sol +++ b/evm/src/omni-bridge/contracts/BridgeTypes.sol @@ -45,7 +45,7 @@ library BridgeTypes { string name, string symbol, uint8 decimals, - uint8 originNonce + uint8 originDeciamls ); event LogMetadata( From 80602581078d32653ad061dbecfa35d4a552c5d2 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 19 Dec 2024 22:40:40 +0000 Subject: [PATCH 03/16] Fix typo --- evm/src/omni-bridge/contracts/BridgeTypes.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/omni-bridge/contracts/BridgeTypes.sol b/evm/src/omni-bridge/contracts/BridgeTypes.sol index ab63366f..7d4d144f 100644 --- a/evm/src/omni-bridge/contracts/BridgeTypes.sol +++ b/evm/src/omni-bridge/contracts/BridgeTypes.sol @@ -45,7 +45,7 @@ library BridgeTypes { string name, string symbol, uint8 decimals, - uint8 originDeciamls + uint8 originDecimals ); event LogMetadata( From 1c95ba13046a4dea92cfb60b76597b5e304244bf Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 19 Dec 2024 23:16:51 +0000 Subject: [PATCH 04/16] Fix clippy --- near/omni-bridge/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index 970f3bde..dbd16fcc 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -1223,7 +1223,7 @@ impl Contract { fn de_normalize_amount(amount: u128, decimals: Option) -> u128 { if let Some(decimals) = decimals { let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount * 10 ^ diff_decimals + amount * (10 ^ diff_decimals) } else { amount } @@ -1232,7 +1232,7 @@ impl Contract { fn normalize_amount(amount: u128, decimals: Option) -> u128 { if let Some(decimals) = decimals { let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount / 10 ^ diff_decimals + amount / (10 ^ diff_decimals) } else { amount } From e97ba96d3181f312f883fcff30f84809c3dc4534 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 2 Jan 2025 16:50:10 +0000 Subject: [PATCH 05/16] Store normalization dust for zero fee transfers --- near/omni-bridge/src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index dbd16fcc..0d4e1667 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -71,6 +71,7 @@ enum StorageKey { DeployedTokens, DestinationNonces, TokenDecimals, + NormalizationDust, } #[derive(AccessControlRole, Deserialize, Serialize, Copy, Clone)] @@ -166,6 +167,7 @@ pub struct Contract { pub token_id_to_address: LookupMap<(ChainKind, AccountId), OmniAddress>, pub token_address_to_id: LookupMap, pub token_decimals: LookupMap, + pub token_normalization_dust: LookupMap, pub deployed_tokens: LookupSet, pub token_deployer_accounts: LookupMap, pub mpc_signer: AccountId, @@ -251,6 +253,7 @@ impl Contract { token_id_to_address: LookupMap::new(StorageKey::TokenIdToAddress), token_address_to_id: LookupMap::new(StorageKey::TokenAddressToId), token_decimals: LookupMap::new(StorageKey::TokenDecimals), + token_normalization_dust: LookupMap::new(StorageKey::NormalizationDust), deployed_tokens: LookupSet::new(StorageKey::DeployedTokens), token_deployer_accounts: LookupMap::new(StorageKey::TokenDeployerAccounts), mpc_signer, @@ -443,7 +446,10 @@ impl Contract { ) { if let Ok(signature) = call_result { if fee.is_zero() { - self.remove_transfer_message(message_payload.transfer_id); + let message = self.remove_transfer_message(message_payload.transfer_id); + let normalization_dust = message.amount.0 - message_payload.amount.0; + self.token_normalization_dust + .insert(&self.get_token_id(&message.token), &normalization_dust); } env::log_str( @@ -920,6 +926,10 @@ impl Contract { pub fn get_current_destination_nonce(&self, chain_kind: ChainKind) -> Nonce { self.destination_nonces.get(&chain_kind).unwrap_or_default() } + + pub fn get_normalization_dust(&self, token: &AccountId) -> u128 { + self.token_normalization_dust.get(token).unwrap_or_default() + } } impl Contract { From a0422d9beadad69138b8186536799e25d8c18f62 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 2 Jan 2025 17:38:34 +0000 Subject: [PATCH 06/16] Fix tests --- evm/tests/BridgeToken.ts | 2 +- near/omni-tests/src/helpers.rs | 4 ++++ near/omni-tests/src/init_transfer.rs | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/evm/tests/BridgeToken.ts b/evm/tests/BridgeToken.ts index ca144597..f61752de 100644 --- a/evm/tests/BridgeToken.ts +++ b/evm/tests/BridgeToken.ts @@ -69,7 +69,7 @@ describe("BridgeToken", () => { const token = OmniBridgeInstance.attach(tokenProxyAddress) as BridgeToken expect(await token.name()).to.be.equal("Wrapped NEAR fungible token") expect(await token.symbol()).to.be.equal("wNEAR") - expect((await token.decimals()).toString()).to.be.equal("24") + expect((await token.decimals()).toString()).to.be.equal("18") }) it("can't create token if token already exists", async () => { diff --git a/near/omni-tests/src/helpers.rs b/near/omni-tests/src/helpers.rs index 6b33d05a..de17248e 100644 --- a/near/omni-tests/src/helpers.rs +++ b/near/omni-tests/src/helpers.rs @@ -111,11 +111,15 @@ pub mod tests { token: &AccountId, token_address: &OmniAddress, emitter_address: &OmniAddress, + decimals: u8, + origin_decimals: u8, ) -> BindTokenArgs { let deploy_token_message = DeployTokenMessage { token: token.clone(), token_address: token_address.clone(), emitter_address: emitter_address.clone(), + decimals, + origin_decimals, }; let prover_result = ProverResult::DeployToken(deploy_token_message); diff --git a/near/omni-tests/src/init_transfer.rs b/near/omni-tests/src/init_transfer.rs index 560c9ca9..4e0b13bb 100644 --- a/near/omni-tests/src/init_transfer.rs +++ b/near/omni-tests/src/init_transfer.rs @@ -149,6 +149,8 @@ mod tests { &token_contract.id(), ð_token_address(), ð_factory_address, + 24, + 24, )) .deposit(required_deposit_for_bind_token) .max_gas() From 1a91fa8f83efbbfad94b12186393325f56b0d95f Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 2 Jan 2025 17:46:17 +0000 Subject: [PATCH 07/16] Fix test --- evm/tests/BridgeToken.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/tests/BridgeToken.ts b/evm/tests/BridgeToken.ts index f0dc4161..69ddd6ed 100644 --- a/evm/tests/BridgeToken.ts +++ b/evm/tests/BridgeToken.ts @@ -362,7 +362,7 @@ describe("BridgeToken", () => { expect(await BridgeTokenV2Proxied.returnTestString()).to.equal("test") expect(await BridgeTokenV2Proxied.name()).to.equal("Wrapped NEAR fungible token") expect(await BridgeTokenV2Proxied.symbol()).to.equal("wNEAR") - expect((await BridgeTokenV2Proxied.decimals()).toString()).to.equal("24") + expect((await BridgeTokenV2Proxied.decimals()).toString()).to.equal("18") }) it("user can't upgrade token contract", async () => { From fefd2eb087f5186c53fcb725a7cff862632acca0 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 2 Jan 2025 18:30:41 +0000 Subject: [PATCH 08/16] Fix tests --- .../omni-bridge/contracts/test/TestWormhole.sol | 1 + evm/tests/BridgeToken.ts | 5 +++-- evm/tests/BridgeTokenWormhole.ts | 16 +++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/evm/src/omni-bridge/contracts/test/TestWormhole.sol b/evm/src/omni-bridge/contracts/test/TestWormhole.sol index dc3a2e59..211e086e 100644 --- a/evm/src/omni-bridge/contracts/test/TestWormhole.sol +++ b/evm/src/omni-bridge/contracts/test/TestWormhole.sol @@ -9,6 +9,7 @@ contract TestWormhole { bytes memory payload, uint8 consistencyLevel ) external payable returns (uint64) { + require(msg.value == this.messageFee(), "invalid fee"); emit MessagePublished(nonce, payload, consistencyLevel); return 0; } diff --git a/evm/tests/BridgeToken.ts b/evm/tests/BridgeToken.ts index 69ddd6ed..830392b7 100644 --- a/evm/tests/BridgeToken.ts +++ b/evm/tests/BridgeToken.ts @@ -11,6 +11,7 @@ const PauseMode = { PausedFinTransfer: 1 << 1, } const PauseAll = PauseMode.PausedInitTransfer | PauseMode.PausedFinTransfer +const PanicCodeArithmeticOperationOverflowed = "0x11" describe("BridgeToken", () => { const wrappedNearId = "wrap.testnet" @@ -290,7 +291,7 @@ describe("BridgeToken", () => { "testrecipient.near", message, ), - ).to.be.revertedWithCustomError(OmniBridge, "InvalidValue") + ).to.be.revertedWithPanic(PanicCodeArithmeticOperationOverflowed) }) it("can't init transfer when value is too high", async () => { @@ -305,7 +306,7 @@ describe("BridgeToken", () => { const message = "" await expect( - OmniBridge.initTransfer( + OmniBridge.connect(user1).initTransfer( tokenProxyAddress, payload.amount, fee, diff --git a/evm/tests/BridgeTokenWormhole.ts b/evm/tests/BridgeTokenWormhole.ts index 2300f042..002c969e 100644 --- a/evm/tests/BridgeTokenWormhole.ts +++ b/evm/tests/BridgeTokenWormhole.ts @@ -6,6 +6,8 @@ import { ethers, upgrades } from "hardhat" import type { BridgeToken, OmniBridgeWormhole, TestWormhole } from "../typechain-types" import { depositSignature, metadataSignature, testWallet } from "./helpers/signatures" +const WormholeFee = 10000 + class FinTransferWormholeMessage { static schema = { struct: { @@ -124,7 +126,7 @@ describe("BridgeTokenWormhole", () => { ): Promise<{ tokenProxyAddress: string; token: BridgeToken }> { const { signature, payload } = metadataSignature(tokenId) - await OmniBridgeWormhole.deployToken(signature, payload) + await OmniBridgeWormhole.deployToken(signature, payload, { value: WormholeFee }) const tokenProxyAddress = await OmniBridgeWormhole.nearToEthToken(tokenId) const token = OmniBridgeInstance.attach(tokenProxyAddress) as BridgeToken return { tokenProxyAddress, token } @@ -133,7 +135,7 @@ describe("BridgeTokenWormhole", () => { it("deploy token", async () => { const { signature, payload } = metadataSignature(wrappedNearId) - await expect(await OmniBridgeWormhole.deployToken(signature, payload)) + await expect(await OmniBridgeWormhole.deployToken(signature, payload, { value: WormholeFee })) .to.emit(TestWormhole, "MessagePublished") .withArgs(0, anyValue, consistencyLevel) }) @@ -154,7 +156,7 @@ describe("BridgeTokenWormhole", () => { feeRecipient: payload.feeRecipient, }) - await expect(OmniBridgeWormhole.finTransfer(signature, payload)) + await expect(OmniBridgeWormhole.finTransfer(signature, payload, { value: WormholeFee })) .to.emit(TestWormhole, "MessagePublished") .withArgs(1, messagePayload, consistencyLevel) @@ -167,7 +169,7 @@ describe("BridgeTokenWormhole", () => { const { token } = await createToken(wrappedNearId) const tokenProxyAddress = await token.getAddress() const { signature, payload } = depositSignature(tokenProxyAddress, await user1.getAddress()) - await OmniBridgeWormhole.finTransfer(signature, payload) + await OmniBridgeWormhole.finTransfer(signature, payload, { value: WormholeFee }) const recipient = "testrecipient.near" const fee = 0 @@ -198,7 +200,7 @@ describe("BridgeTokenWormhole", () => { recipient, message, { - value: 10000, + value: WormholeFee, }, ), ) @@ -212,7 +214,7 @@ describe("BridgeTokenWormhole", () => { const { token } = await createToken(wrappedNearId) const tokenProxyAddress = await token.getAddress() const { signature, payload } = depositSignature(tokenProxyAddress, await user1.getAddress()) - await OmniBridgeWormhole.finTransfer(signature, payload) + await OmniBridgeWormhole.finTransfer(signature, payload, { value: WormholeFee }) await expect( OmniBridgeWormhole.connect(user1).initTransfer( @@ -223,6 +225,6 @@ describe("BridgeTokenWormhole", () => { "testrecipient.near", "", ), - ).to.be.revertedWithCustomError(OmniBridgeWormhole, "InvalidValue") + ).to.be.revertedWith("invalid fee") }) }) From e8f4184bd9943bb38e17a97a77690c93240558c2 Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 2 Jan 2025 20:13:14 +0000 Subject: [PATCH 09/16] Fix dust increment --- near/omni-bridge/src/lib.rs | 18 ++++++++++++++---- near/omni-bridge/src/storage.rs | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index 54d47449..b9be4e64 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -448,8 +448,12 @@ impl Contract { if fee.is_zero() { let message = self.remove_transfer_message(message_payload.transfer_id); let normalization_dust = message.amount.0 - message_payload.amount.0; - self.token_normalization_dust - .insert(&self.get_token_id(&message.token), &normalization_dust); + let token_id = self.get_token_id(&message.token); + + self.token_normalization_dust.insert( + &token_id, + &(self.get_normalization_dust(&token_id).0 + normalization_dust), + ); } env::log_str( @@ -815,6 +819,9 @@ impl Contract { }, ); + self.token_normalization_dust + .insert(&deploy_token.token, &0); + let required_deposit = env::storage_byte_cost() .saturating_mul((env::storage_usage().saturating_sub(storage_usage)).into()); @@ -935,8 +942,11 @@ impl Contract { self.destination_nonces.get(&chain_kind).unwrap_or_default() } - pub fn get_normalization_dust(&self, token: &AccountId) -> u128 { - self.token_normalization_dust.get(token).unwrap_or_default() + pub fn get_normalization_dust(&self, token: &AccountId) -> U128 { + self.token_normalization_dust + .get(token) + .unwrap_or_default() + .into() } } diff --git a/near/omni-bridge/src/storage.rs b/near/omni-bridge/src/storage.rs index cfaaf5ed..a42aef5a 100644 --- a/near/omni-bridge/src/storage.rs +++ b/near/omni-bridge/src/storage.rs @@ -189,7 +189,7 @@ impl Contract { .len() as u64; env::storage_byte_cost() - .saturating_mul((2 * (Self::get_basic_storage() + key_len + value_len)).into()) + .saturating_mul((4 * (Self::get_basic_storage() + key_len + value_len)).into()) } pub fn required_balance_for_deploy_token(&self) -> NearToken { From f84e6e268a9e9cfd3cac00821bdf8552638416cc Mon Sep 17 00:00:00 2001 From: karim-en Date: Tue, 7 Jan 2025 15:38:17 +0000 Subject: [PATCH 10/16] Fix normalized amount in claim fee --- near/omni-bridge/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index b9be4e64..efe82a66 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -588,9 +588,16 @@ impl Contract { ); let message = self.remove_transfer_message(fin_transfer.transfer_id); + let token_address = self + .get_token_address( + message.get_destination_chain(), + self.get_token_id(&message.token), + ) + .unwrap_or_else(|| env::panic_str("ERR_FAILED_TO_GET_TOKEN_ADDRESS")); + let de_normalized_amount = Self::de_normalize_amount( fin_transfer.amount.0, - self.token_decimals.get(&message.token), + self.token_decimals.get(&token_address), ); let fee = message.amount.0 - de_normalized_amount; From 646e321990caf38f1d2a493b5636b3a7bbecb803 Mon Sep 17 00:00:00 2001 From: karim-en Date: Wed, 8 Jan 2025 17:39:56 +0000 Subject: [PATCH 11/16] Remove dust from storage --- near/omni-bridge/src/lib.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index efe82a66..29aec22b 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -71,7 +71,6 @@ enum StorageKey { DeployedTokens, DestinationNonces, TokenDecimals, - NormalizationDust, } #[derive(AccessControlRole, Deserialize, Serialize, Copy, Clone)] @@ -167,7 +166,6 @@ pub struct Contract { pub token_id_to_address: LookupMap<(ChainKind, AccountId), OmniAddress>, pub token_address_to_id: LookupMap, pub token_decimals: LookupMap, - pub token_normalization_dust: LookupMap, pub deployed_tokens: LookupSet, pub token_deployer_accounts: LookupMap, pub mpc_signer: AccountId, @@ -253,7 +251,6 @@ impl Contract { token_id_to_address: LookupMap::new(StorageKey::TokenIdToAddress), token_address_to_id: LookupMap::new(StorageKey::TokenAddressToId), token_decimals: LookupMap::new(StorageKey::TokenDecimals), - token_normalization_dust: LookupMap::new(StorageKey::NormalizationDust), deployed_tokens: LookupSet::new(StorageKey::DeployedTokens), token_deployer_accounts: LookupMap::new(StorageKey::TokenDeployerAccounts), mpc_signer, @@ -446,14 +443,7 @@ impl Contract { ) { if let Ok(signature) = call_result { if fee.is_zero() { - let message = self.remove_transfer_message(message_payload.transfer_id); - let normalization_dust = message.amount.0 - message_payload.amount.0; - let token_id = self.get_token_id(&message.token); - - self.token_normalization_dust.insert( - &token_id, - &(self.get_normalization_dust(&token_id).0 + normalization_dust), - ); + self.remove_transfer_message(message_payload.transfer_id); } env::log_str( @@ -826,9 +816,6 @@ impl Contract { }, ); - self.token_normalization_dust - .insert(&deploy_token.token, &0); - let required_deposit = env::storage_byte_cost() .saturating_mul((env::storage_usage().saturating_sub(storage_usage)).into()); @@ -948,13 +935,6 @@ impl Contract { pub fn get_current_destination_nonce(&self, chain_kind: ChainKind) -> Nonce { self.destination_nonces.get(&chain_kind).unwrap_or_default() } - - pub fn get_normalization_dust(&self, token: &AccountId) -> U128 { - self.token_normalization_dust - .get(token) - .unwrap_or_default() - .into() - } } impl Contract { From 572a98694aad9b53e8047dc3a6f352749bebdc63 Mon Sep 17 00:00:00 2001 From: karim-en Date: Wed, 8 Jan 2025 17:48:13 +0000 Subject: [PATCH 12/16] Panic if decimals not exist --- near/omni-bridge/src/lib.rs | 46 +++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index 29aec22b..d7cb5ebb 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -401,7 +401,10 @@ impl Contract { ) .unwrap_or_else(|| env::panic_str("ERR_FAILED_TO_GET_TOKEN_ADDRESS")); - let decimals = self.token_decimals.get(&token_address); + let decimals = self + .token_decimals + .get(&token_address) + .sdk_expect("ERR_TOKEN_DECIMALS_NOT_FOUND"); let amount_to_transfer = Self::normalize_amount( transfer_message.amount.0 - transfer_message.fee.fee.0, decimals, @@ -504,7 +507,10 @@ impl Contract { "Unknown factory" ); - let decimals = self.token_decimals.get(&init_transfer.token); + let decimals = self + .token_decimals + .get(&init_transfer.token) + .sdk_expect("ERR_TOKEN_DECIMALS_NOT_FOUND"); let destination_nonce = self.get_next_destination_nonce(init_transfer.recipient.get_chain()); @@ -587,7 +593,9 @@ impl Contract { let de_normalized_amount = Self::de_normalize_amount( fin_transfer.amount.0, - self.token_decimals.get(&token_address), + self.token_decimals + .get(&token_address) + .sdk_expect("ERR_TOKEN_DECIMALS_NOT_FOUND"), ); let fee = message.amount.0 - de_normalized_amount; @@ -732,6 +740,18 @@ impl Contract { .is_none(), "ERR_TOKEN_EXIST" ); + require!( + self.token_decimals + .insert( + token_address, + &Decimals { + decimals: metadata.decimals, + origin_decimals: metadata.decimals + } + ) + .is_none(), + "ERR_TOKEN_EXIST" + ); require!(self.deployed_tokens.insert(&token_id), "ERR_TOKEN_EXIST"); let required_deposit = env::storage_byte_cost() .saturating_mul((env::storage_usage().saturating_sub(storage_usage)).into()) @@ -1246,21 +1266,13 @@ impl Contract { } } - fn de_normalize_amount(amount: u128, decimals: Option) -> u128 { - if let Some(decimals) = decimals { - let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount * (10 ^ diff_decimals) - } else { - amount - } + fn de_normalize_amount(amount: u128, decimals: Decimals) -> u128 { + let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); + amount * (10 ^ diff_decimals) } - fn normalize_amount(amount: u128, decimals: Option) -> u128 { - if let Some(decimals) = decimals { - let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount / (10 ^ diff_decimals) - } else { - amount - } + fn normalize_amount(amount: u128, decimals: Decimals) -> u128 { + let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); + amount / (10 ^ diff_decimals) } } From cc62b6be22461e8e883f7f87b79166252c18d83a Mon Sep 17 00:00:00 2001 From: karim-en Date: Wed, 8 Jan 2025 22:17:01 +0000 Subject: [PATCH 13/16] fix normalize and denormalize --- near/omni-bridge/src/lib.rs | 15 +++-- near/omni-bridge/src/storage.rs | 2 +- near/omni-bridge/src/tests/lib_test.rs | 88 ++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index d7cb5ebb..1e609f65 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -929,6 +929,13 @@ impl Contract { &(token_address.get_chain(), token_id.clone()), &token_address, ); + self.token_decimals.insert( + &token_address, + &Decimals { + decimals: 0, + origin_decimals: 0, + }, + ); ext_token::ext(token_id) .with_static_gas(STORAGE_DEPOSIT_GAS) @@ -1267,12 +1274,12 @@ impl Contract { } fn de_normalize_amount(amount: u128, decimals: Decimals) -> u128 { - let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount * (10 ^ diff_decimals) + let diff_decimals: u32 = (decimals.origin_decimals - decimals.decimals).into(); + amount * (10_u128.pow(diff_decimals)) } fn normalize_amount(amount: u128, decimals: Decimals) -> u128 { - let diff_decimals: u128 = (decimals.origin_decimals - decimals.decimals).into(); - amount / (10 ^ diff_decimals) + let diff_decimals: u32 = (decimals.origin_decimals - decimals.decimals).into(); + amount / (10_u128.pow(diff_decimals)) } } diff --git a/near/omni-bridge/src/storage.rs b/near/omni-bridge/src/storage.rs index a42aef5a..72ca58b8 100644 --- a/near/omni-bridge/src/storage.rs +++ b/near/omni-bridge/src/storage.rs @@ -189,7 +189,7 @@ impl Contract { .len() as u64; env::storage_byte_cost() - .saturating_mul((4 * (Self::get_basic_storage() + key_len + value_len)).into()) + .saturating_mul((3 * (Self::get_basic_storage() + key_len + value_len)).into()) } pub fn required_balance_for_deploy_token(&self) -> NearToken { diff --git a/near/omni-bridge/src/tests/lib_test.rs b/near/omni-bridge/src/tests/lib_test.rs index cf1adc44..a22c57a6 100644 --- a/near/omni-bridge/src/tests/lib_test.rs +++ b/near/omni-bridge/src/tests/lib_test.rs @@ -1,6 +1,7 @@ use near_contract_standards::storage_management::StorageBalance; use omni_types::locker_args::StorageDepositAction; +use crate::storage::Decimals; use crate::Contract; use near_sdk::test_utils::VMContextBuilder; use near_sdk::RuntimeFeesConfig; @@ -486,6 +487,13 @@ fn test_fin_transfer_callback_near_success() { &native_token_address, &DEFAULT_FT_CONTRACT_ACCOUNT.parse().unwrap(), ); + contract.token_decimals.insert( + &OmniAddress::Near(AccountId::try_from(DEFAULT_FT_CONTRACT_ACCOUNT.to_string()).unwrap()), + &Decimals { + decimals: 24, + origin_decimals: 24, + }, + ); let storage_actions = vec![ StorageDepositAction { @@ -564,6 +572,14 @@ fn test_fin_transfer_callback_non_near_success() { let eth_recipient = OmniAddress::Eth(EvmAddress::from_str(DEFAULT_ETH_USER_ADDRESS).unwrap()); let prover_result = get_prover_result(Some(eth_recipient.clone())); + contract.token_decimals.insert( + &OmniAddress::Near(AccountId::try_from(DEFAULT_FT_CONTRACT_ACCOUNT.to_string()).unwrap()), + &Decimals { + decimals: 24, + origin_decimals: 24, + }, + ); + setup_test_env( predecessor.clone(), NearToken::from_near(1), @@ -654,3 +670,75 @@ fn test_is_transfer_finalised() { contract.finalised_transfers.insert(&transfer_id); assert!(contract.is_transfer_finalised(transfer_id)); } + +#[test] +fn test_normalize_amount() { + assert_eq!( + Contract::normalize_amount( + u128::MAX, + Decimals { + decimals: 18, + origin_decimals: 18 + } + ), + u128::MAX + ); + + assert_eq!( + Contract::normalize_amount( + u128::MAX, + Decimals { + decimals: 18, + origin_decimals: 24 + } + ), + u128::MAX / 1_000_000 + ); + + assert_eq!( + Contract::normalize_amount( + u128::MAX, + Decimals { + decimals: 9, + origin_decimals: 24 + } + ), + u128::MAX / 1_000_000_000_000_000 + ); +} + +#[test] +fn test_de_normalize_amount() { + assert_eq!( + Contract::de_normalize_amount( + u128::MAX, + Decimals { + decimals: 18, + origin_decimals: 18 + } + ), + u128::MAX + ); + + assert_eq!( + Contract::de_normalize_amount( + u64::MAX.into(), + Decimals { + decimals: 18, + origin_decimals: 24 + } + ), + u64::MAX as u128 * 1_000_000_u128 + ); + + assert_eq!( + Contract::de_normalize_amount( + u64::MAX.into(), + Decimals { + decimals: 9, + origin_decimals: 24 + } + ), + u64::MAX as u128 * 1_000_000_000_000_000_u128 + ); +} From 74e876b0648a416157ce39c333aab0acd17d2137 Mon Sep 17 00:00:00 2001 From: karim-en Date: Wed, 8 Jan 2025 22:18:40 +0000 Subject: [PATCH 14/16] Fix tests --- near/omni-tests/src/fin_transfer.rs | 39 ++++++++++++++++++++++++----- near/omni-tests/src/helpers.rs | 19 +++++++++++++- near/omni-tests/src/omni_token.rs | 36 ++++++++++++++++++++------ 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/near/omni-tests/src/fin_transfer.rs b/near/omni-tests/src/fin_transfer.rs index a94fd847..f3bb8bcd 100644 --- a/near/omni-tests/src/fin_transfer.rs +++ b/near/omni-tests/src/fin_transfer.rs @@ -1,14 +1,14 @@ #[cfg(test)] mod tests { use crate::helpers::tests::{ - account_n, eth_eoa_address, eth_factory_address, relayer_account_id, LOCKER_PATH, - MOCK_PROVER_PATH, MOCK_TOKEN_PATH, NEP141_DEPOSIT, + account_n, eth_eoa_address, eth_factory_address, eth_token_address, relayer_account_id, + LOCKER_PATH, MOCK_PROVER_PATH, MOCK_TOKEN_PATH, NEP141_DEPOSIT, }; use near_sdk::{borsh, json_types::U128, serde_json::json, AccountId}; use near_workspaces::types::NearToken; use omni_types::{ - locker_args::{FinTransferArgs, StorageDepositAction}, - prover_result::{InitTransferMessage, ProverResult}, + locker_args::{BindTokenArgs, FinTransferArgs, StorageDepositAction}, + prover_result::{DeployTokenMessage, InitTransferMessage, ProverResult}, Fee, OmniAddress, }; use rstest::rstest; @@ -73,7 +73,9 @@ mod tests { "Expected an error but got success" ), Err(result_error) => { - let error = expected_error.expect("Got an error when none was expected"); + let error = expected_error.expect(&format!( + "Got an error {result_error} when none was expected" + )); assert!( result_error.to_string().contains(error), "Wrong error. Got: {}, Expected: {}", @@ -166,6 +168,31 @@ mod tests { .await? .into_result()?; + // Bind token + let required_balance_for_bind_token: NearToken = locker_contract + .view("required_balance_for_bind_token") + .await? + .json()?; + + relayer_account + .call(locker_contract.id(), "bind_token") + .args_borsh(BindTokenArgs { + chain_kind: omni_types::ChainKind::Eth, + prover_args: borsh::to_vec(&ProverResult::DeployToken(DeployTokenMessage { + token: token_contract.id().clone(), + token_address: eth_token_address(), + decimals: 24, + origin_decimals: 24, + emitter_address: eth_factory_address(), + })) + .unwrap(), + }) + .deposit(required_balance_for_bind_token) + .max_gas() + .transact() + .await? + .into_result()?; + let required_deposit_for_fin_transfer = NEP141_DEPOSIT .saturating_mul(storage_deposit_accounts.len() as u128) .saturating_add(required_balance_for_fin_transfer); @@ -187,7 +214,7 @@ mod tests { storage_deposit_actions, prover_args: borsh::to_vec(&ProverResult::InitTransfer(InitTransferMessage { origin_nonce: 1, - token: OmniAddress::Near(token_contract.id().clone()), + token: eth_token_address(), recipient: OmniAddress::Near(account_n(1)), amount: U128(amount), fee: Fee { diff --git a/near/omni-tests/src/helpers.rs b/near/omni-tests/src/helpers.rs index de17248e..72d667f0 100644 --- a/near/omni-tests/src/helpers.rs +++ b/near/omni-tests/src/helpers.rs @@ -30,6 +30,22 @@ pub mod tests { .unwrap() } + pub fn arb_factory_address() -> OmniAddress { + "arb:0x252e87862A3A720287E7fd527cE6e8d0738427A2" + .parse() + .unwrap() + } + + pub fn base_factory_address() -> OmniAddress { + "base:0x252e87862A3A720287E7fd527cE6e8d0738427A2" + .parse() + .unwrap() + } + + pub fn sol_factory_address() -> OmniAddress { + "sol:11111111111111111111111111111111".parse().unwrap() + } + pub fn eth_eoa_address() -> OmniAddress { "eth:0xc5ed912ca6db7b41de4ef3632fa0a5641e42bf09" .parse() @@ -88,6 +104,7 @@ pub mod tests { pub fn get_test_deploy_token_args( token_address: &OmniAddress, + factory_contract_address: &OmniAddress, token_metadata: &BasicMetadata, ) -> DeployTokenArgs { let log_metadata_message = LogMetadataMessage { @@ -95,7 +112,7 @@ pub mod tests { name: token_metadata.name.clone(), symbol: token_metadata.symbol.clone(), decimals: token_metadata.decimals, - emitter_address: token_address.clone(), + emitter_address: factory_contract_address.clone(), }; let prover_result = ProverResult::LogMetadata(log_metadata_message); diff --git a/near/omni-tests/src/omni_token.rs b/near/omni-tests/src/omni_token.rs index 6ac564eb..2a24c778 100644 --- a/near/omni-tests/src/omni_token.rs +++ b/near/omni-tests/src/omni_token.rs @@ -1,9 +1,10 @@ #[cfg(test)] mod tests { use crate::helpers::tests::{ - account_n, arb_token_address, base_token_address, eth_eoa_address, eth_token_address, - get_test_deploy_token_args, sol_token_address, LOCKER_PATH, MOCK_PROVER_PATH, - NEP141_DEPOSIT, TOKEN_DEPLOYER_PATH, + account_n, arb_factory_address, arb_token_address, base_factory_address, + base_token_address, eth_eoa_address, eth_factory_address, eth_token_address, + get_test_deploy_token_args, sol_factory_address, sol_token_address, LOCKER_PATH, + MOCK_PROVER_PATH, NEP141_DEPOSIT, TOKEN_DEPLOYER_PATH, }; use anyhow; use near_sdk::borsh; @@ -23,6 +24,7 @@ mod tests { locker: near_workspaces::Contract, token_contract: near_workspaces::Contract, init_token_address: OmniAddress, + factory_contract_address: OmniAddress, token_metadata: BasicMetadata, } @@ -86,10 +88,18 @@ mod tests { .await? .into_result()?; + let factory_contract_address = match init_token_address.get_chain() { + ChainKind::Eth => eth_factory_address(), + ChainKind::Sol => sol_factory_address(), + ChainKind::Arb => arb_factory_address(), + ChainKind::Base => base_factory_address(), + _ => panic!("Unsupported chain"), + }; + locker .call("add_factory") .args_json(json!({ - "address": init_token_address, + "address": factory_contract_address, })) .max_gas() .transact() @@ -97,14 +107,21 @@ mod tests { .into_result()?; // Deploy token - let token_contract = - Self::deploy_token(&worker, &locker, &init_token_address, &token_metadata).await?; + let token_contract = Self::deploy_token( + &worker, + &locker, + &init_token_address, + &factory_contract_address, + &token_metadata, + ) + .await?; Ok(Self { worker, locker, token_contract, init_token_address, + factory_contract_address, token_metadata, }) } @@ -118,6 +135,7 @@ mod tests { worker: &near_workspaces::Worker, locker: &near_workspaces::Contract, init_token_address: &OmniAddress, + factoty_contract_address: &OmniAddress, token_metadata: &BasicMetadata, ) -> anyhow::Result { let token_deploy_initiator = worker @@ -150,6 +168,7 @@ mod tests { .call(locker.id(), "deploy_token") .args_borsh(get_test_deploy_token_args( init_token_address, + &factoty_contract_address, token_metadata, )) .deposit(required_storage) @@ -259,6 +278,7 @@ mod tests { &env.token_contract, &recipient, env.init_token_address, + env.factory_contract_address, amount, ) .await?; @@ -314,6 +334,7 @@ mod tests { &env.token_contract, &sender, env.init_token_address, + env.factory_contract_address, amount, ) .await?; @@ -369,6 +390,7 @@ mod tests { locker_contract: &near_workspaces::Contract, token_contract: &near_workspaces::Contract, recipient: &near_workspaces::Account, + token_address: OmniAddress, emitter_address: OmniAddress, amount: U128, ) -> anyhow::Result<()> { @@ -392,7 +414,7 @@ mod tests { storage_deposit_actions, prover_args: borsh::to_vec(&ProverResult::InitTransfer(InitTransferMessage { origin_nonce: 1, - token: OmniAddress::Near(token_contract.id().clone()), + token: token_address, recipient: OmniAddress::Near(recipient.id().clone()), amount, fee: Fee { From 5f5735c9b92d76919e885c24284d27524c9ac0fd Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 9 Jan 2025 17:47:17 +0000 Subject: [PATCH 15/16] Rename `de_normalize` to `denormalize` --- near/omni-bridge/src/lib.rs | 10 +++++----- near/omni-bridge/src/tests/lib_test.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/near/omni-bridge/src/lib.rs b/near/omni-bridge/src/lib.rs index 1e609f65..b53a81a8 100644 --- a/near/omni-bridge/src/lib.rs +++ b/near/omni-bridge/src/lib.rs @@ -517,10 +517,10 @@ impl Contract { let transfer_message = TransferMessage { origin_nonce: init_transfer.origin_nonce, token: init_transfer.token, - amount: Self::de_normalize_amount(init_transfer.amount.0, decimals).into(), + amount: Self::denormalize_amount(init_transfer.amount.0, decimals).into(), recipient: init_transfer.recipient, fee: Fee { - fee: Self::de_normalize_amount(init_transfer.fee.fee.0, decimals).into(), + fee: Self::denormalize_amount(init_transfer.fee.fee.0, decimals).into(), native_fee: init_transfer.fee.native_fee, }, sender: init_transfer.sender, @@ -591,13 +591,13 @@ impl Contract { ) .unwrap_or_else(|| env::panic_str("ERR_FAILED_TO_GET_TOKEN_ADDRESS")); - let de_normalized_amount = Self::de_normalize_amount( + let denormalized_amount = Self::denormalize_amount( fin_transfer.amount.0, self.token_decimals .get(&token_address) .sdk_expect("ERR_TOKEN_DECIMALS_NOT_FOUND"), ); - let fee = message.amount.0 - de_normalized_amount; + let fee = message.amount.0 - denormalized_amount; if message.fee.native_fee.0 != 0 { if message.get_origin_chain() == ChainKind::Near { @@ -1273,7 +1273,7 @@ impl Contract { } } - fn de_normalize_amount(amount: u128, decimals: Decimals) -> u128 { + fn denormalize_amount(amount: u128, decimals: Decimals) -> u128 { let diff_decimals: u32 = (decimals.origin_decimals - decimals.decimals).into(); amount * (10_u128.pow(diff_decimals)) } diff --git a/near/omni-bridge/src/tests/lib_test.rs b/near/omni-bridge/src/tests/lib_test.rs index a22c57a6..35b74a45 100644 --- a/near/omni-bridge/src/tests/lib_test.rs +++ b/near/omni-bridge/src/tests/lib_test.rs @@ -710,7 +710,7 @@ fn test_normalize_amount() { #[test] fn test_de_normalize_amount() { assert_eq!( - Contract::de_normalize_amount( + Contract::denormalize_amount( u128::MAX, Decimals { decimals: 18, @@ -721,7 +721,7 @@ fn test_de_normalize_amount() { ); assert_eq!( - Contract::de_normalize_amount( + Contract::denormalize_amount( u64::MAX.into(), Decimals { decimals: 18, @@ -732,7 +732,7 @@ fn test_de_normalize_amount() { ); assert_eq!( - Contract::de_normalize_amount( + Contract::denormalize_amount( u64::MAX.into(), Decimals { decimals: 9, From 0b8a11736dbab45323949dca86a232fdf02a254d Mon Sep 17 00:00:00 2001 From: karim-en Date: Thu, 9 Jan 2025 17:48:00 +0000 Subject: [PATCH 16/16] Fix typo --- near/omni-bridge/src/tests/lib_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/near/omni-bridge/src/tests/lib_test.rs b/near/omni-bridge/src/tests/lib_test.rs index 35b74a45..3e3e8a01 100644 --- a/near/omni-bridge/src/tests/lib_test.rs +++ b/near/omni-bridge/src/tests/lib_test.rs @@ -708,7 +708,7 @@ fn test_normalize_amount() { } #[test] -fn test_de_normalize_amount() { +fn test_denormalize_amount() { assert_eq!( Contract::denormalize_amount( u128::MAX,