From 71a8379dfa2c164e73c118a95acf32a4cb6e66c5 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 19 Sep 2024 12:13:03 +0200 Subject: [PATCH 1/9] feat(evm): Expanding SDK to support Native transfer with optional contract call --- .../src/transfer.ts | 8 +-- packages/evm/src/evmAssetTransfer.ts | 13 ++--- packages/evm/src/fungibleAssetTransfer.ts | 56 ++++++++++++++++++- packages/evm/src/genericMessageTransfer.ts | 12 ++-- packages/evm/src/utils/depositFn.ts | 51 ++++------------- 5 files changed, 80 insertions(+), 60 deletions(-) diff --git a/examples/evm-to-evm-fungible-transfer/src/transfer.ts b/examples/evm-to-evm-fungible-transfer/src/transfer.ts index bf7706ae0..7dbcaa72c 100644 --- a/examples/evm-to-evm-fungible-transfer/src/transfer.ts +++ b/examples/evm-to-evm-fungible-transfer/src/transfer.ts @@ -18,7 +18,7 @@ if (!privateKey) { const SEPOLIA_CHAIN_ID = 11155111; const AMOY_CHAIN_ID = 84532; const RESOURCE_ID = - "0x0000000000000000000000000000000000000000000000000000000000001200"; + "0x1000000000000000000000000000000000000000000000000000000000000000"; const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL || "https://eth-sepolia.g.alchemy.com/v2/MeCKDrpxLkGOn4LMlBa3cKy1EzzOzwzG"; @@ -43,7 +43,7 @@ export async function erc20Transfer(): Promise { destination: AMOY_CHAIN_ID, sourceNetworkProvider: web3Provider as unknown as Eip1193Provider, resource: RESOURCE_ID, - amount: BigInt(1) * BigInt(1e6), + amount: BigInt(1) * BigInt(1e17), recipientAddress: destinationAddress, sourceAddress: sourceAddress, optionalGas: BigInt(500000), @@ -57,7 +57,7 @@ export async function erc20Transfer(): Promise { const response = await wallet.sendTransaction(approval); await response.wait(); console.log( - `Approved, transaction: ${getTxExplorerUrl({ txHash: response.hash, chainId: SEPOLIA_CHAIN_ID })}`, + `Approved, transaction: ${getTxExplorerUrl({ txHash: response.hash, chainId: SEPOLIA_CHAIN_ID })}` ); } @@ -65,7 +65,7 @@ export async function erc20Transfer(): Promise { const response = await wallet.sendTransaction(transferTx); await response.wait(); console.log( - `Depositted, transaction: ${getSygmaScanLink(response.hash, process.env.SYGMA_ENV)}`, + `Depositted, transaction: ${getSygmaScanLink(response.hash, process.env.SYGMA_ENV)}` ); } diff --git a/packages/evm/src/evmAssetTransfer.ts b/packages/evm/src/evmAssetTransfer.ts index 6dbbab6d2..33c571080 100644 --- a/packages/evm/src/evmAssetTransfer.ts +++ b/packages/evm/src/evmAssetTransfer.ts @@ -7,8 +7,8 @@ import { constants, utils } from 'ethers'; import { EvmTransfer } from './evmTransfer.js'; import type { EvmAssetTransferParams, EvmFee, TransactionRequest } from './types.js'; -import { executeDeposit } from './utils/depositFn.js'; import { createTransactionRequest } from './utils/transaction.js'; +import { getTransactionOverrides } from './utils/depositFn.js'; /** * Asset transfers in EVM @@ -72,16 +72,15 @@ export abstract class AssetTransfer extends EvmTransfer implements IAssetTransfe const hasBalance = await this.hasEnoughBalance(fee); if (!hasBalance) throw new Error('Insufficient token balance'); - const transferTx = await executeDeposit( - this.destination.id.toString(), + const transferTransaction = await bridge.populateTransaction.deposit( + this.destinationDomain.id.toString(), this.resource.resourceId, this.getDepositData(), - fee, - bridge, - overrides, + '0x', + getTransactionOverrides(fee, overrides), ); - return createTransactionRequest(transferTx); + return createTransactionRequest(transferTransaction); } /** diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index e08ad5855..027c1d422 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -1,8 +1,19 @@ import type { EvmResource } from '@buildwithsygma/core'; import { Config, FeeHandlerType, ResourceType, SecurityModel } from '@buildwithsygma/core'; -import { Bridge__factory, ERC20__factory } from '@buildwithsygma/sygma-contracts'; +import { + Bridge__factory, + ERC20__factory, + NativeTokenAdapter__factory, +} from '@buildwithsygma/sygma-contracts'; import { Web3Provider } from '@ethersproject/providers'; -import { BigNumber, constants, type PopulatedTransaction, utils } from 'ethers'; +import { + BigNumber, + constants, + ethers, + PayableOverrides, + type PopulatedTransaction, + utils, +} from 'ethers'; import { AssetTransfer } from './evmAssetTransfer.js'; import type { @@ -14,6 +25,7 @@ import type { import { approve, getERC20Allowance } from './utils/approveAndCheckFns.js'; import { createFungibleDepositData } from './utils/assetTransferHelpers.js'; import { createTransactionRequest } from './utils/transaction.js'; +import { getTransactionOverrides } from './utils/depositFn.js'; /** * @internal @@ -59,6 +71,15 @@ class FungibleAssetTransfer extends AssetTransfer { this.optionalMessage = transfer.optionalMessage; } + protected isNativeTransfer(): boolean { + const { symbol, type } = this.resource; + const { nativeTokenSymbol } = this.config.getDomainConfig(this.sourceDomain); + + return ( + type === ResourceType.FUNGIBLE && symbol?.toLowerCase() === nativeTokenSymbol.toLowerCase() + ); + } + /** * Returns encoded deposit * data @@ -127,6 +148,10 @@ class FungibleAssetTransfer extends AssetTransfer { * @returns {Promise>} */ public async getApprovalTransactions(): Promise> { + if (this.isNativeTransfer()) { + return []; + } + const provider = new Web3Provider(this.sourceNetworkProvider); const sourceDomainConfig = this.config.getDomainConfig(this.source); const bridge = Bridge__factory.connect(sourceDomainConfig.bridge, provider); @@ -160,6 +185,33 @@ class FungibleAssetTransfer extends AssetTransfer { return approvals.map(approval => createTransactionRequest(approval)); } + + protected async getNativeDepositTransaction( + overrides?: ethers.Overrides, + ): Promise { + const domainConfig = this.config.getDomainConfig(this.source); + const provider = new Web3Provider(this.sourceNetworkProvider); + const bridge = Bridge__factory.connect(domainConfig.bridge, provider); + const handlerAddress = await bridge._resourceIDToHandlerAddress(this.resource.resourceId); + const nativeTokenAdapter = await NativeTokenAdapter__factory.connect(handlerAddress, provider); + const fee = await this.getFee(); + + const transferTransaction = await nativeTokenAdapter.populateTransaction.deposit( + this.destination.id.toString(), + this.recipientAddress, + getTransactionOverrides(fee, overrides), + ); + + return createTransactionRequest(transferTransaction); + } + + public async getTransferTransaction(overrides?: PayableOverrides): Promise { + if (this.isNativeTransfer()) { + return await this.getNativeDepositTransaction(overrides); + } + + return super.getTransferTransaction(overrides); + } } /** diff --git a/packages/evm/src/genericMessageTransfer.ts b/packages/evm/src/genericMessageTransfer.ts index 4ec67b6d6..13f0a7e05 100644 --- a/packages/evm/src/genericMessageTransfer.ts +++ b/packages/evm/src/genericMessageTransfer.ts @@ -15,8 +15,9 @@ import { EvmTransfer } from './evmTransfer.js'; import { getFeeInformation } from './fee/getFeeInformation.js'; import type { GenericMessageTransferParams, TransactionRequest } from './types.js'; import { createGenericCallDepositData } from './utils/genericTransferHelpers.js'; -import { executeDeposit } from './utils/index.js'; + import { createTransactionRequest } from './utils/transaction.js'; +import { getTransactionOverrides } from './utils/depositFn.js'; /** * @internal @@ -143,16 +144,15 @@ class GenericMessageTransfer< const feeData = await this.getFee(); const depositData = this.getDepositData(); - const transaction = await executeDeposit( + const transferTransaction = await bridgeInstance.populateTransaction.deposit( this.destination.id.toString(), this.resource.resourceId, depositData, - feeData, - bridgeInstance, - overrides, + '0x', + getTransactionOverrides(feeData, overrides), ); - return createTransactionRequest(transaction); + return createTransactionRequest(transferTransaction); } /** * Get prepared additional deposit data diff --git a/packages/evm/src/utils/depositFn.ts b/packages/evm/src/utils/depositFn.ts index a1dd054a4..2a0660805 100644 --- a/packages/evm/src/utils/depositFn.ts +++ b/packages/evm/src/utils/depositFn.ts @@ -1,53 +1,22 @@ import { FeeHandlerType } from '@buildwithsygma/core'; -import type { Bridge } from '@buildwithsygma/sygma-contracts'; -import type { PopulatedTransaction, ethers } from 'ethers'; +import type { ethers } from 'ethers'; import { BigNumber } from 'ethers'; import type { EvmFee } from '../types.js'; export const ASSET_TRANSFER_GAS_LIMIT: BigNumber = BigNumber.from(300000); -/** - * Executes a deposit operation using the specified parameters and returns a populated transaction. - * - * - * @category Bridge deposit - * @param {string} domainId - The unique identifier for destination network. - * @param {string} resourceId - The resource ID associated with the token. - * @param {string} depositData - The deposit data required for the operation. - * @param {FeeDataResult} feeData - The fee data result for the deposit operation. - * @param {Bridge} bridgeInstance - The bridge instance used to perform the deposit operation. - * @returns {Promise} Unsigned transaction - */ -export const executeDeposit = async ( - domainId: string, - resourceId: string, - depositData: string, - feeData: EvmFee, - bridgeInstance: Bridge, - overrides?: ethers.PayableOverrides, -): Promise => { - const transactionSettings = { - /** - * @remarks - * "twap" and "basic" both deduct in native currency - */ - value: feeData.type == FeeHandlerType.PERCENTAGE ? 0 : feeData.fee, +export function getTransactionOverrides( + fee: EvmFee, + overrides?: ethers.Overrides, +): ethers.Overrides { + const sygmaOverrides = { gasLimit: ASSET_TRANSFER_GAS_LIMIT, + value: fee.type === FeeHandlerType.PERCENTAGE ? 0 : fee.fee, }; - const payableOverrides = { - ...transactionSettings, + return { + ...sygmaOverrides, ...overrides, }; - - const depositTransaction = await bridgeInstance.populateTransaction.deposit( - domainId, - resourceId, - depositData, - '0x', - payableOverrides, - ); - - return depositTransaction; -}; +} From 67ea8a02cec171053ca647a03a5cd0f6d97ea93c Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 19 Sep 2024 12:56:14 +0200 Subject: [PATCH 2/9] nativeToken adapter address and deposit --- packages/core/src/config/localConfig.ts | 2 ++ packages/core/src/types.ts | 1 + packages/evm/src/fungibleAssetTransfer.ts | 13 ++++++++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/core/src/config/localConfig.ts b/packages/core/src/config/localConfig.ts index e75f07a19..e233e6d94 100644 --- a/packages/core/src/config/localConfig.ts +++ b/packages/core/src/config/localConfig.ts @@ -8,6 +8,7 @@ export const localConfig: SygmaConfig = { caipId: '', chainId: 1337, name: 'Ethereum 1', + nativeTokenAdapter: '', type: Network.EVM, bridge: '0x6CdE2Cd82a4F8B74693Ff5e194c19CA08c2d1c68', handlers: [ @@ -76,6 +77,7 @@ export const localConfig: SygmaConfig = { caipId: '', chainId: 1338, name: 'evm2', + nativeTokenAdapter: '', type: Network.EVM, bridge: '0x6CdE2Cd82a4F8B74693Ff5e194c19CA08c2d1c68', handlers: [ diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 0f05deb04..dfd1d4c7c 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -132,6 +132,7 @@ export type FeeHandler = { export interface EthereumConfig extends BaseConfig { handlers: Array; + nativeTokenAdapter: string; feeRouter: string; feeHandlers: Array; } diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index 027c1d422..c1f459da5 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -1,4 +1,4 @@ -import type { EvmResource } from '@buildwithsygma/core'; +import type { EthereumConfig, EvmResource } from '@buildwithsygma/core'; import { Config, FeeHandlerType, ResourceType, SecurityModel } from '@buildwithsygma/core'; import { Bridge__factory, @@ -189,12 +189,15 @@ class FungibleAssetTransfer extends AssetTransfer { protected async getNativeDepositTransaction( overrides?: ethers.Overrides, ): Promise { - const domainConfig = this.config.getDomainConfig(this.source); + const domainConfig = this.config.getDomainConfig(this.source) as EthereumConfig; const provider = new Web3Provider(this.sourceNetworkProvider); - const bridge = Bridge__factory.connect(domainConfig.bridge, provider); - const handlerAddress = await bridge._resourceIDToHandlerAddress(this.resource.resourceId); - const nativeTokenAdapter = await NativeTokenAdapter__factory.connect(handlerAddress, provider); + const nativeTokenAdapter = await NativeTokenAdapter__factory.connect( + domainConfig.nativeTokenAdapter, + provider, + ); + const fee = await this.getFee(); + fee.fee += this.transferAmount; const transferTransaction = await nativeTokenAdapter.populateTransaction.deposit( this.destination.id.toString(), From 17c23a6292f5c85b6c8aff19006c63594a9f97fe Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 19 Sep 2024 17:00:57 +0200 Subject: [PATCH 3/9] rename methods to correct names and fixed tests and lint --- packages/evm/package.json | 2 +- packages/evm/src/evmAssetTransfer.ts | 2 +- packages/evm/src/fungibleAssetTransfer.ts | 18 +-- packages/evm/src/genericMessageTransfer.ts | 3 +- packages/evm/src/nonFungibleAssetTransfer.ts | 4 +- .../__test__/assetTransferHelpers.test.ts | 8 +- .../evm/src/utils/__test__/depositFns.test.ts | 142 +----------------- .../evm/src/utils/assetTransferHelpers.ts | 4 +- packages/evm/src/utils/depositFn.ts | 2 +- yarn.lock | 4 +- 10 files changed, 28 insertions(+), 161 deletions(-) diff --git a/packages/evm/package.json b/packages/evm/package.json index e4be39292..ad99f337e 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -57,7 +57,7 @@ }, "dependencies": { "@buildwithsygma/core": "workspace:^", - "@buildwithsygma/sygma-contracts": "^2.8.0", + "@buildwithsygma/sygma-contracts": "^2.9.0", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", "@ethersproject/contracts": "^5.7.0", diff --git a/packages/evm/src/evmAssetTransfer.ts b/packages/evm/src/evmAssetTransfer.ts index 33c571080..a6d13ab77 100644 --- a/packages/evm/src/evmAssetTransfer.ts +++ b/packages/evm/src/evmAssetTransfer.ts @@ -7,8 +7,8 @@ import { constants, utils } from 'ethers'; import { EvmTransfer } from './evmTransfer.js'; import type { EvmAssetTransferParams, EvmFee, TransactionRequest } from './types.js'; -import { createTransactionRequest } from './utils/transaction.js'; import { getTransactionOverrides } from './utils/depositFn.js'; +import { createTransactionRequest } from './utils/transaction.js'; /** * Asset transfers in EVM diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index c1f459da5..f2164941c 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -6,14 +6,8 @@ import { NativeTokenAdapter__factory, } from '@buildwithsygma/sygma-contracts'; import { Web3Provider } from '@ethersproject/providers'; -import { - BigNumber, - constants, - ethers, - PayableOverrides, - type PopulatedTransaction, - utils, -} from 'ethers'; +import { BigNumber, constants, utils } from 'ethers'; +import type { ethers, PayableOverrides, PopulatedTransaction } from 'ethers'; import { AssetTransfer } from './evmAssetTransfer.js'; import type { @@ -23,9 +17,9 @@ import type { TransactionRequest, } from './types.js'; import { approve, getERC20Allowance } from './utils/approveAndCheckFns.js'; -import { createFungibleDepositData } from './utils/assetTransferHelpers.js'; -import { createTransactionRequest } from './utils/transaction.js'; +import { createAssetDepositData } from './utils/assetTransferHelpers.js'; import { getTransactionOverrides } from './utils/depositFn.js'; +import { createTransactionRequest } from './utils/transaction.js'; /** * @internal @@ -86,7 +80,7 @@ class FungibleAssetTransfer extends AssetTransfer { * @returns {string} */ protected getDepositData(): string { - return createFungibleDepositData({ + return createAssetDepositData({ destination: this.destination, recipientAddress: this.recipientAddress, amount: this.adjustedAmount, @@ -191,7 +185,7 @@ class FungibleAssetTransfer extends AssetTransfer { ): Promise { const domainConfig = this.config.getDomainConfig(this.source) as EthereumConfig; const provider = new Web3Provider(this.sourceNetworkProvider); - const nativeTokenAdapter = await NativeTokenAdapter__factory.connect( + const nativeTokenAdapter = NativeTokenAdapter__factory.connect( domainConfig.nativeTokenAdapter, provider, ); diff --git a/packages/evm/src/genericMessageTransfer.ts b/packages/evm/src/genericMessageTransfer.ts index 13f0a7e05..ad6c49ccf 100644 --- a/packages/evm/src/genericMessageTransfer.ts +++ b/packages/evm/src/genericMessageTransfer.ts @@ -14,10 +14,9 @@ import { constants } from 'ethers'; import { EvmTransfer } from './evmTransfer.js'; import { getFeeInformation } from './fee/getFeeInformation.js'; import type { GenericMessageTransferParams, TransactionRequest } from './types.js'; +import { getTransactionOverrides } from './utils/depositFn.js'; import { createGenericCallDepositData } from './utils/genericTransferHelpers.js'; - import { createTransactionRequest } from './utils/transaction.js'; -import { getTransactionOverrides } from './utils/depositFn.js'; /** * @internal diff --git a/packages/evm/src/nonFungibleAssetTransfer.ts b/packages/evm/src/nonFungibleAssetTransfer.ts index 5f74155f2..5da8adb6e 100644 --- a/packages/evm/src/nonFungibleAssetTransfer.ts +++ b/packages/evm/src/nonFungibleAssetTransfer.ts @@ -9,7 +9,7 @@ import { providers } from 'ethers'; import { AssetTransfer } from './evmAssetTransfer.js'; import type { EvmFee, NonFungibleTransferParams, TransactionRequest } from './types.js'; -import { createFungibleDepositData } from './utils/assetTransferHelpers.js'; +import { createAssetDepositData } from './utils/assetTransferHelpers.js'; import { approve, isApproved } from './utils/index.js'; import { createTransactionRequest } from './utils/transaction.js'; @@ -31,7 +31,7 @@ class NonFungibleAssetTransfer extends AssetTransfer { * @returns {string} */ protected getDepositData(): string { - return createFungibleDepositData({ + return createAssetDepositData({ destination: this.destination, recipientAddress: this.recipientAddress, tokenId: this.tokenId, diff --git a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts index e1b8f5574..fbe6b9946 100644 --- a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts +++ b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts @@ -3,7 +3,7 @@ import { arrayify } from '@ethersproject/bytes'; import { utils } from 'ethers'; import { - createFungibleDepositData, + createAssetDepositData, createSubstrateMultiLocationObject, serializeEvmAddress, serializeSubstrateAddress, @@ -16,7 +16,7 @@ describe('createERCDepositData', () => { const expectedDepositData = '0x000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000141234567890123456789012345678901234567890'; - const depositData = createFungibleDepositData({ + const depositData = createAssetDepositData({ recipientAddress, amount, destination: { @@ -37,7 +37,7 @@ describe('createERCDepositData', () => { const expectedDepositData = '0x00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000027010200511f0100fac48520983815e2022ded67ca8d27b73d51b1b022284c48b4eccbb7a328d80f'; - const depositData = createFungibleDepositData({ + const depositData = createAssetDepositData({ recipientAddress, amount, destination: { @@ -59,7 +59,7 @@ describe('createERCDepositData', () => { const expectedDepositData = '0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000002a746231717366797a6c3932707637776b79616a3074666a6474777663736a383430703030346a676c7670'; - const depositData = createFungibleDepositData({ + const depositData = createAssetDepositData({ recipientAddress, amount: tokenAmount, destination: { diff --git a/packages/evm/src/utils/__test__/depositFns.test.ts b/packages/evm/src/utils/__test__/depositFns.test.ts index dae0b70d1..420490f3f 100644 --- a/packages/evm/src/utils/__test__/depositFns.test.ts +++ b/packages/evm/src/utils/__test__/depositFns.test.ts @@ -1,144 +1,18 @@ import { FeeHandlerType } from '@buildwithsygma/core'; -import type { Bridge, ERC721MinterBurnerPauser } from '@buildwithsygma/sygma-contracts'; -import { type ContractReceipt, type PopulatedTransaction } from 'ethers'; import type { EvmFee } from '../../types.js'; -import * as EVM from '../depositFn.js'; - -jest.mock( - '@buildwithsygma/sygma-contracts', - () => - ({ - ...jest.requireActual('@buildwithsygma/sygma-contracts'), - Bridge__factory: { - connect: jest.fn() as unknown as Bridge, - }, - ERC721MinterBurnerPauser__factory: { - connect: jest.fn() as unknown as ERC721MinterBurnerPauser, - }, - }) as unknown, -); +import { getTransactionOverrides } from '../depositFn.js'; // Define a test suite -describe('deposit functions', () => { - let domainId: string; - let resourceId: string; - let depositData: string; - let feeData: EvmFee; - - beforeEach(() => { - domainId = 'domainId'; - resourceId = 'resourceId'; - depositData = 'depositData'; - feeData = { +describe('getTransactionOverrides', () => { + it('should assign correct values', () => { + const evmFee: EvmFee = { + fee: 1n, type: FeeHandlerType.BASIC, - fee: BigInt('100'), - tokenAddress: '0x00', - handlerAddress: '0x9867', + handlerAddress: '', }; - jest.clearAllMocks(); - }); - describe('executeDeposit', () => { - it('should successfully execute deposit', async () => { - const bridgeInstance = { - populateTransaction: { - deposit: jest.fn().mockResolvedValueOnce({ - wait: jest.fn().mockResolvedValueOnce({} as ContractReceipt), - } as unknown as PopulatedTransaction), - }, - }; - - const result = await EVM.executeDeposit( - domainId, - resourceId, - depositData, - feeData, - bridgeInstance as unknown as Bridge, - ); - - expect(result).toBeDefined(); - expect(bridgeInstance.populateTransaction.deposit).toHaveBeenCalledTimes(1); - }); - - it('should successfully call deposit method on contract without overrides', async () => { - const bridgeInstance = { - populateTransaction: { - deposit: jest.fn().mockResolvedValueOnce({ - wait: jest.fn().mockResolvedValueOnce({} as ContractReceipt), - } as unknown as PopulatedTransaction), - }, - }; - - const result = await EVM.executeDeposit( - domainId, - resourceId, - depositData, - feeData, - bridgeInstance as unknown as Bridge, - ); - - expect(result).toBeDefined(); - expect(bridgeInstance.populateTransaction.deposit).toHaveBeenCalledTimes(1); - expect(bridgeInstance.populateTransaction.deposit).toHaveBeenCalledWith( - 'domainId', - 'resourceId', - 'depositData', - '0x', - { value: feeData.fee, gasLimit: EVM.ASSET_TRANSFER_GAS_LIMIT }, - ); - }); - - it('should successfully call deposit method on contract without overrides and with dynamic (oracle) fee', async () => { - feeData = { - type: FeeHandlerType.PERCENTAGE, - fee: BigInt('100'), - tokenAddress: '0x00', - handlerAddress: '0x123', - }; - const bridgeInstance = { - populateTransaction: { - deposit: jest.fn().mockResolvedValueOnce({ - wait: jest.fn().mockResolvedValueOnce({} as ContractReceipt), - } as unknown as PopulatedTransaction), - }, - }; - - const result = await EVM.executeDeposit( - domainId, - resourceId, - depositData, - feeData, - bridgeInstance as unknown as Bridge, - ); - - expect(result).toBeDefined(); - expect(bridgeInstance.populateTransaction.deposit).toHaveBeenCalledTimes(1); - expect(bridgeInstance.populateTransaction.deposit).toHaveBeenCalledWith( - 'domainId', - 'resourceId', - 'depositData', - '0x', - { gasLimit: EVM.ASSET_TRANSFER_GAS_LIMIT, value: 0 }, - ); - }); - - it('should handle error on execute deposit', async () => { - const bridgeInstance = { - populateTransaction: { - deposit: jest.fn().mockRejectedValueOnce(new Error('Deposit failed')), - }, - }; - - await expect( - EVM.executeDeposit( - domainId, - resourceId, - depositData, - feeData, - bridgeInstance as unknown as Bridge, - ), - ).rejects.toThrowError('Deposit failed'); - }); + const overrides = getTransactionOverrides(evmFee); + expect(overrides.value).toEqual(evmFee.fee); }); }); diff --git a/packages/evm/src/utils/assetTransferHelpers.ts b/packages/evm/src/utils/assetTransferHelpers.ts index 5a071fe21..668c2acbf 100644 --- a/packages/evm/src/utils/assetTransferHelpers.ts +++ b/packages/evm/src/utils/assetTransferHelpers.ts @@ -11,7 +11,7 @@ import type { FungibleTransferOptionalMessage } from '../types.js'; const ACTIONS_ARRAY_ABI = 'tuple(uint256 nativeValue, address callTo, address approveTo, address tokenSend, address tokenReceive, bytes data)[]'; -interface FungbileDepositParams { +interface AssetDepositParams { destination: Domain; recipientAddress: string; amount?: bigint; @@ -66,7 +66,7 @@ export function serializeSubstrateAddress( return registry.createType('MultiLocation', JSON.parse(multilocationObject)).toU8a(); } -export function createFungibleDepositData(depositParams: FungbileDepositParams): string { +export function createAssetDepositData(depositParams: AssetDepositParams): string { const { recipientAddress, destination, amount, tokenId, optionalGas, optionalMessage } = depositParams; let recipientAddressSerialized: Uint8Array; diff --git a/packages/evm/src/utils/depositFn.ts b/packages/evm/src/utils/depositFn.ts index 2a0660805..68b6f2bb4 100644 --- a/packages/evm/src/utils/depositFn.ts +++ b/packages/evm/src/utils/depositFn.ts @@ -9,7 +9,7 @@ export const ASSET_TRANSFER_GAS_LIMIT: BigNumber = BigNumber.from(300000); export function getTransactionOverrides( fee: EvmFee, overrides?: ethers.Overrides, -): ethers.Overrides { +): ethers.PayableOverrides { const sygmaOverrides = { gasLimit: ASSET_TRANSFER_GAS_LIMIT, value: fee.type === FeeHandlerType.PERCENTAGE ? 0 : fee.fee, diff --git a/yarn.lock b/yarn.lock index c746398f7..31823d246 100644 --- a/yarn.lock +++ b/yarn.lock @@ -537,7 +537,7 @@ __metadata: resolution: "@buildwithsygma/evm@workspace:packages/evm" dependencies: "@buildwithsygma/core": "workspace:^" - "@buildwithsygma/sygma-contracts": "npm:^2.8.0" + "@buildwithsygma/sygma-contracts": "npm:^2.9.0" "@ethersproject/abi": "npm:^5.7.0" "@ethersproject/bytes": "npm:^5.7.0" "@ethersproject/contracts": "npm:^5.7.0" @@ -626,7 +626,7 @@ __metadata: languageName: node linkType: hard -"@buildwithsygma/sygma-contracts@npm:^2.8.0": +"@buildwithsygma/sygma-contracts@npm:^2.9.0": version: 2.9.0 resolution: "@buildwithsygma/sygma-contracts@npm:2.9.0" dependencies: From 29f9b312da8cfb5089dc404b2dd4371f6faadc85 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 19 Sep 2024 17:10:11 +0200 Subject: [PATCH 4/9] remove unused import --- packages/evm/src/fungibleAssetTransfer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index ed722241f..c96630ea5 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -7,7 +7,7 @@ import { } from '@buildwithsygma/sygma-contracts'; import { Web3Provider } from '@ethersproject/providers'; import { BigNumber, constants, utils } from 'ethers'; -import type { ethers, PayableOverrides, PopulatedTransaction } from 'ethers'; +import type { ethers, PopulatedTransaction } from 'ethers'; import { AssetTransfer } from './evmAssetTransfer.js'; import type { From 04d99546ef2e500963e5f4fae70214caf5b559e7 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Tue, 24 Sep 2024 16:50:20 +0200 Subject: [PATCH 5/9] feat: native token handler + message handler - added native token handler changes --- .../src/transfer.ts | 4 +- packages/evm/package.json | 2 +- packages/evm/src/fungibleAssetTransfer.ts | 25 ++-- packages/evm/src/nonFungibleAssetTransfer.ts | 1 + packages/evm/src/types.ts | 9 ++ .../__test__/assetTransferHelpers.test.ts | 4 + .../evm/src/utils/assetTransferHelpers.ts | 96 ++++++++------ .../src/utils/nativeTokenDepositHelpers.ts | 125 ++++++++++++++++++ yarn.lock | 18 ++- 9 files changed, 230 insertions(+), 54 deletions(-) create mode 100644 packages/evm/src/utils/nativeTokenDepositHelpers.ts diff --git a/examples/evm-to-evm-fungible-transfer/src/transfer.ts b/examples/evm-to-evm-fungible-transfer/src/transfer.ts index 7dbcaa72c..37e887f80 100644 --- a/examples/evm-to-evm-fungible-transfer/src/transfer.ts +++ b/examples/evm-to-evm-fungible-transfer/src/transfer.ts @@ -16,7 +16,7 @@ if (!privateKey) { } const SEPOLIA_CHAIN_ID = 11155111; -const AMOY_CHAIN_ID = 84532; +const BASE_SEPOLIA_CHAIN_ID = 84532; const RESOURCE_ID = "0x1000000000000000000000000000000000000000000000000000000000000000"; const SEPOLIA_RPC_URL = @@ -40,7 +40,7 @@ export async function erc20Transfer(): Promise { const params: FungibleTransferParams = { source: SEPOLIA_CHAIN_ID, - destination: AMOY_CHAIN_ID, + destination: BASE_SEPOLIA_CHAIN_ID, sourceNetworkProvider: web3Provider as unknown as Eip1193Provider, resource: RESOURCE_ID, amount: BigInt(1) * BigInt(1e17), diff --git a/packages/evm/package.json b/packages/evm/package.json index d5326704a..3df0bac86 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -57,7 +57,7 @@ }, "dependencies": { "@buildwithsygma/core": "workspace:^", - "@buildwithsygma/sygma-contracts": "^2.9.0", + "@buildwithsygma/sygma-contracts": "^2.10.1", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", "@ethersproject/contracts": "^5.7.0", diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index c96630ea5..8489ef6e4 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -18,7 +18,7 @@ import type { } from './types.js'; import { approve, getERC20Allowance } from './utils/approveAndCheckFns.js'; import { createAssetDepositData } from './utils/assetTransferHelpers.js'; -import { getTransactionOverrides } from './utils/depositFn.js'; +import { getNativeTokenDepositTransaction } from './utils/nativeTokenDepositHelpers.js'; import { createTransactionRequest } from './utils/transaction.js'; /** @@ -86,6 +86,7 @@ class FungibleAssetTransfer extends AssetTransfer { amount: this.adjustedAmount, optionalGas: this.optionalGas, optionalMessage: this.optionalMessage, + isNativeToken: this.isNativeTransfer(), }); } @@ -182,7 +183,7 @@ class FungibleAssetTransfer extends AssetTransfer { return approvals.map(approval => createTransactionRequest(approval)); } - protected async getNativeDepositTransaction( + protected async getNativeTokenDepositTransaction( overrides?: ethers.Overrides, ): Promise { const domainConfig = this.config.getDomainConfig(this.source) as EthereumConfig; @@ -195,18 +196,24 @@ class FungibleAssetTransfer extends AssetTransfer { const fee = await this.getFee(); fee.fee += this.transferAmount; - const transferTransaction = await nativeTokenAdapter.populateTransaction.deposit( - this.destination.id.toString(), - this.recipientAddress, - getTransactionOverrides(fee, overrides), + return await getNativeTokenDepositTransaction( + { + destinationNetworkId: this.destination.id.toString(), + destinationNetworkType: this.destination.type, + parachainId: this.destination.parachainId, + recipientAddress: this.recipientAddress, + optionalMessage: this.optionalMessage, + optionalGas: this.optionalGas, + depositData: this.getDepositData(), + }, + nativeTokenAdapter, + overrides, ); - - return createTransactionRequest(transferTransaction); } public async getTransferTransaction(overrides?: ethers.Overrides): Promise { if (this.isNativeTransfer()) { - return await this.getNativeDepositTransaction(overrides); + return await this.getNativeTokenDepositTransaction(overrides); } return super.getTransferTransaction(overrides); diff --git a/packages/evm/src/nonFungibleAssetTransfer.ts b/packages/evm/src/nonFungibleAssetTransfer.ts index 52b1dfd89..3b66d37e5 100644 --- a/packages/evm/src/nonFungibleAssetTransfer.ts +++ b/packages/evm/src/nonFungibleAssetTransfer.ts @@ -35,6 +35,7 @@ class NonFungibleAssetTransfer extends AssetTransfer { destination: this.destination, recipientAddress: this.recipientAddress, tokenId: this.tokenId, + isNativeToken: false, }); } diff --git a/packages/evm/src/types.ts b/packages/evm/src/types.ts index 10858b69a..443a3d91e 100644 --- a/packages/evm/src/types.ts +++ b/packages/evm/src/types.ts @@ -102,3 +102,12 @@ export interface GenericMessageTransferParams< destinationContractAddress: string; maxFee: bigint; } + +export type NativeTokenDepositArgsWithoutMessage = [string, string]; +export type NativeTokenDepositArgsWithGeneralMessage = [string, string]; +export type NativeTokenDepositArgsWithEVMMessage = [string, string, bigint, string]; +export type NativeTokenDepositMethods = + | 'deposit' + | 'depositToEVM' + | 'depositGeneral' + | 'depositToEVMWithMessage'; diff --git a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts index fbe6b9946..c9752d943 100644 --- a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts +++ b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts @@ -26,6 +26,8 @@ describe('createERCDepositData', () => { chainId: 1, id: 1, }, + isNativeToken: false, + q, }); expect(depositData).toEqual(expectedDepositData); @@ -48,6 +50,7 @@ describe('createERCDepositData', () => { id: 1, parachainId: 2004, }, + isNativeToken: false, }); expect(depositData).toEqual(expectedDepositData); @@ -69,6 +72,7 @@ describe('createERCDepositData', () => { chainId: 1, id: 1, }, + isNativeToken: false, }); expect(depositData).toEqual(expectedDepositData); }); diff --git a/packages/evm/src/utils/assetTransferHelpers.ts b/packages/evm/src/utils/assetTransferHelpers.ts index 668c2acbf..9d45e932c 100644 --- a/packages/evm/src/utils/assetTransferHelpers.ts +++ b/packages/evm/src/utils/assetTransferHelpers.ts @@ -18,6 +18,7 @@ interface AssetDepositParams { tokenId?: string; optionalGas?: bigint; optionalMessage?: FungibleTransferOptionalMessage; + isNativeToken: boolean; } export function serializeEvmAddress(evmAddress: `0x${string}`): Uint8Array { @@ -66,33 +67,66 @@ export function serializeSubstrateAddress( return registry.createType('MultiLocation', JSON.parse(multilocationObject)).toU8a(); } -export function createAssetDepositData(depositParams: AssetDepositParams): string { - const { recipientAddress, destination, amount, tokenId, optionalGas, optionalMessage } = - depositParams; - let recipientAddressSerialized: Uint8Array; - - switch (destination.type) { +export function serializeDestinationAddress( + address: string, + type: Network, + parachainId?: number, +): Uint8Array { + switch (type) { case Network.EVM: { - recipientAddressSerialized = serializeEvmAddress(recipientAddress as `0x${string}`); - break; + return serializeEvmAddress(address as `0x${string}`); } case Network.SUBSTRATE: { - recipientAddressSerialized = serializeSubstrateAddress( - recipientAddress, - destination.parachainId, - ); - break; + return serializeSubstrateAddress(address, parachainId); } case Network.BITCOIN: { - recipientAddressSerialized = utils.arrayify( - `${utils.hexlify(utils.toUtf8Bytes(recipientAddress))}`, - ); - break; + return utils.arrayify(`${utils.hexlify(utils.toUtf8Bytes(address))}`); } default: { throw new Error('Unsupported destination network type.'); } } +} + +export function encodeOptionalMessage(optionalMessage: FungibleTransferOptionalMessage): string { + const { transactionId, actions, receiver } = optionalMessage; + const abiCoder = new AbiCoder(); + + const optionalMessageEncoded = abiCoder.encode( + ['bytes32', ACTIONS_ARRAY_ABI, 'address'], + [ + transactionId, + actions.map(action => [ + action.nativeValue, + action.callTo, + action.approveTo, + action.tokenSend, + action.tokenReceive, + action.data, + ]), + receiver, + ], + ); + + return optionalMessageEncoded; +} + +export function createAssetDepositData(depositParams: AssetDepositParams): string { + const { + isNativeToken, + recipientAddress, + destination, + amount, + tokenId, + optionalGas, + optionalMessage, + } = depositParams; + + const recipientAddressSerialized: Uint8Array = serializeDestinationAddress( + recipientAddress, + destination.type, + destination.parachainId, + ); const val = amount !== undefined ? amount : tokenId !== undefined ? tokenId : null; if (val === null) throw new Error('Token Amount Or ID is required.'); @@ -102,32 +136,20 @@ export function createAssetDepositData(depositParams: AssetDepositParams): strin const zeroPaddedAmount = hexZeroPad(tokenAmountOrIdInHex, HEX_PADDING); const addressLenInHex = BigNumber.from(recipientAddressSerialized.length).toHexString(); const zeroPaddedAddrLen = hexZeroPad(addressLenInHex, HEX_PADDING); - let depositData = concat([zeroPaddedAmount, zeroPaddedAddrLen, recipientAddressSerialized]); + + let depositData; + if (isNativeToken) { + depositData = concat([zeroPaddedAddrLen, recipientAddressSerialized]); + } else { + depositData = concat([zeroPaddedAmount, zeroPaddedAddrLen, recipientAddressSerialized]); + } if (optionalMessage !== undefined && optionalGas !== undefined) { const optionalGasInHex = BigNumber.from(optionalGas).toHexString(); const zeroPaddedOptionalGas = hexZeroPad(optionalGasInHex, HEX_PADDING); depositData = concat([depositData, zeroPaddedOptionalGas]); - const { transactionId, actions, receiver } = optionalMessage; - const abiCoder = new AbiCoder(); - - const optionalMessageEncoded = abiCoder.encode( - ['bytes32', ACTIONS_ARRAY_ABI, 'address'], - [ - transactionId, - actions.map(action => [ - action.nativeValue, - action.callTo, - action.approveTo, - action.tokenSend, - action.tokenReceive, - action.data, - ]), - receiver, - ], - ); - + const optionalMessageEncoded = encodeOptionalMessage(optionalMessage); const optionalMessageSeriailzed = arrayify(optionalMessageEncoded); const optionalMsgLenInHex = BigNumber.from(optionalMessageSeriailzed.length).toHexString(); const zeroPaddedOptionalMsgLen = hexZeroPad(optionalMsgLenInHex, HEX_PADDING); diff --git a/packages/evm/src/utils/nativeTokenDepositHelpers.ts b/packages/evm/src/utils/nativeTokenDepositHelpers.ts new file mode 100644 index 000000000..baf91807a --- /dev/null +++ b/packages/evm/src/utils/nativeTokenDepositHelpers.ts @@ -0,0 +1,125 @@ +import type { ParachainId } from '@buildwithsygma/core'; +import { Network } from '@buildwithsygma/core'; +import type { NativeTokenAdapter } from '@buildwithsygma/sygma-contracts'; +import { hexlify } from '@ethersproject/bytes'; +import type { ethers } from 'ethers'; + +import type { + FungibleTransferOptionalMessage, + NativeTokenDepositArgsWithEVMMessage, + NativeTokenDepositArgsWithGeneralMessage, + NativeTokenDepositArgsWithoutMessage, + NativeTokenDepositMethods, + TransactionRequest, +} from '../types.js'; + +import { serializeDestinationAddress, encodeOptionalMessage } from './assetTransferHelpers.js'; +import { createTransactionRequest } from './transaction.js'; + +export function getNativeTokenDepositMethod( + destinationNetworkType: Network, + optionalMessage?: FungibleTransferOptionalMessage, +): NativeTokenDepositMethods { + if (!optionalMessage) { + if (destinationNetworkType === Network.EVM) { + return 'depositToEVM'; + } + return 'deposit'; + } else { + if (destinationNetworkType === Network.EVM) { + return 'depositToEVMWithMessage'; + } + } + + throw new Error('Unsupported deposit method.'); +} + +interface NativeDepositParams { + method: NativeTokenDepositMethods; + recipientAddress: string; + destinationNetworkType: Network; + destinationNetworkId: string; + parachainId?: ParachainId; + optionalMessage?: FungibleTransferOptionalMessage; + optionalGas?: bigint; + depositData: string; +} + +export function getNativeTokenDepositContractArgs( + args: NativeDepositParams, +): + | NativeTokenDepositArgsWithoutMessage + | NativeTokenDepositArgsWithEVMMessage + | NativeTokenDepositArgsWithGeneralMessage { + const { + method, + destinationNetworkId, + recipientAddress, + destinationNetworkType, + parachainId, + optionalMessage, + optionalGas, + depositData, + } = args; + + switch (method) { + case 'deposit': + case 'depositToEVM': + return [ + destinationNetworkId, + hexlify(serializeDestinationAddress(recipientAddress, destinationNetworkType, parachainId)), + ]; + case 'depositToEVMWithMessage': + return [ + destinationNetworkId, + recipientAddress, + optionalGas!, + encodeOptionalMessage(optionalMessage!), + ]; + case 'depositGeneral': + return [destinationNetworkId, depositData]; + } +} + +export async function getNativeTokenDepositTransaction( + depositParams: Omit, + nativeTokenAdapter: NativeTokenAdapter, + overrides?: ethers.Overrides, +): Promise { + const method = getNativeTokenDepositMethod( + depositParams.destinationNetworkType, + depositParams.optionalMessage, + ); + + const args = getNativeTokenDepositContractArgs({ + method, + ...depositParams, + }); + + switch (method) { + case 'deposit': + case 'depositToEVM': + return createTransactionRequest( + await nativeTokenAdapter.populateTransaction[method]( + ...(args as NativeTokenDepositArgsWithoutMessage), + overrides, + ), + ); + case 'depositToEVMWithMessage': + return createTransactionRequest( + await nativeTokenAdapter.populateTransaction[method]( + ...(args as NativeTokenDepositArgsWithEVMMessage), + overrides, + ), + ); + case 'depositGeneral': + return createTransactionRequest( + await nativeTokenAdapter.populateTransaction[method]( + ...(args as NativeTokenDepositArgsWithGeneralMessage), + overrides, + ), + ); + default: + throw new Error('Unsupported method'); + } +} diff --git a/yarn.lock b/yarn.lock index 31823d246..ec1469380 100644 --- a/yarn.lock +++ b/yarn.lock @@ -537,7 +537,7 @@ __metadata: resolution: "@buildwithsygma/evm@workspace:packages/evm" dependencies: "@buildwithsygma/core": "workspace:^" - "@buildwithsygma/sygma-contracts": "npm:^2.9.0" + "@buildwithsygma/sygma-contracts": "npm:^2.10.1" "@ethersproject/abi": "npm:^5.7.0" "@ethersproject/bytes": "npm:^5.7.0" "@ethersproject/contracts": "npm:^5.7.0" @@ -626,15 +626,16 @@ __metadata: languageName: node linkType: hard -"@buildwithsygma/sygma-contracts@npm:^2.9.0": - version: 2.9.0 - resolution: "@buildwithsygma/sygma-contracts@npm:2.9.0" +"@buildwithsygma/sygma-contracts@npm:^2.10.1": + version: 2.10.1 + resolution: "@buildwithsygma/sygma-contracts@npm:2.10.1" dependencies: "@openzeppelin/contracts": "npm:4.5.0" "@uniswap/v3-periphery": "npm:^1.4.4" + solmate: "npm:^6.2.0" peerDependencies: ethers: ">= 5.0.0" - checksum: 0f98a64da674e1264caaf429665a23b7db63365d7a8c5a38d8e23f0b728faecd6bfd3a0c43616bd4aa43133229324f14d4c3d0e2e24225d223574d5e94af9263 + checksum: c6cddf6a427a4d3ab1321fbc21f9e47a64661823ffdb55db230ce9874878125735aad260d3aef454f7681f2d2f7d446882f82f1cf3e7f69209e183b69f375c4a languageName: node linkType: hard @@ -10557,6 +10558,13 @@ __metadata: languageName: node linkType: hard +"solmate@npm:^6.2.0": + version: 6.7.0 + resolution: "solmate@npm:6.7.0" + checksum: 7c51286ac486de2cace00fd136a210d01e2dc28403373583ce5acd49178f1cf4421d3f3a945f28af36e7fcedcea194238b2b5eb53be78a04b9e04f32ea8d286f + languageName: node + linkType: hard + "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" From ea1009653be24f654fd6153a57a352f216554ff1 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Tue, 24 Sep 2024 16:57:05 +0200 Subject: [PATCH 6/9] fix: remove typo --- packages/evm/src/utils/__test__/assetTransferHelpers.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts index c9752d943..fcb64124f 100644 --- a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts +++ b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts @@ -27,7 +27,6 @@ describe('createERCDepositData', () => { id: 1, }, isNativeToken: false, - q, }); expect(depositData).toEqual(expectedDepositData); From 04940acabf391fb3f0df717f6c0434535fb29718 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Wed, 25 Sep 2024 12:15:54 +0200 Subject: [PATCH 7/9] fix: deposit issue --- packages/evm/src/fungibleAssetTransfer.ts | 5 +++-- packages/evm/src/nonFungibleAssetTransfer.ts | 1 - .../__test__/assetTransferHelpers.test.ts | 3 --- .../evm/src/utils/assetTransferHelpers.ts | 19 +++---------------- .../src/utils/nativeTokenDepositHelpers.ts | 4 ++-- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/packages/evm/src/fungibleAssetTransfer.ts b/packages/evm/src/fungibleAssetTransfer.ts index 8489ef6e4..b27f0dd41 100644 --- a/packages/evm/src/fungibleAssetTransfer.ts +++ b/packages/evm/src/fungibleAssetTransfer.ts @@ -86,7 +86,6 @@ class FungibleAssetTransfer extends AssetTransfer { amount: this.adjustedAmount, optionalGas: this.optionalGas, optionalMessage: this.optionalMessage, - isNativeToken: this.isNativeTransfer(), }); } @@ -196,6 +195,8 @@ class FungibleAssetTransfer extends AssetTransfer { const fee = await this.getFee(); fee.fee += this.transferAmount; + const payableOverrides: ethers.PayableOverrides = { ...overrides, value: fee.fee }; + return await getNativeTokenDepositTransaction( { destinationNetworkId: this.destination.id.toString(), @@ -207,7 +208,7 @@ class FungibleAssetTransfer extends AssetTransfer { depositData: this.getDepositData(), }, nativeTokenAdapter, - overrides, + payableOverrides, ); } diff --git a/packages/evm/src/nonFungibleAssetTransfer.ts b/packages/evm/src/nonFungibleAssetTransfer.ts index 3b66d37e5..52b1dfd89 100644 --- a/packages/evm/src/nonFungibleAssetTransfer.ts +++ b/packages/evm/src/nonFungibleAssetTransfer.ts @@ -35,7 +35,6 @@ class NonFungibleAssetTransfer extends AssetTransfer { destination: this.destination, recipientAddress: this.recipientAddress, tokenId: this.tokenId, - isNativeToken: false, }); } diff --git a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts index fcb64124f..fbe6b9946 100644 --- a/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts +++ b/packages/evm/src/utils/__test__/assetTransferHelpers.test.ts @@ -26,7 +26,6 @@ describe('createERCDepositData', () => { chainId: 1, id: 1, }, - isNativeToken: false, }); expect(depositData).toEqual(expectedDepositData); @@ -49,7 +48,6 @@ describe('createERCDepositData', () => { id: 1, parachainId: 2004, }, - isNativeToken: false, }); expect(depositData).toEqual(expectedDepositData); @@ -71,7 +69,6 @@ describe('createERCDepositData', () => { chainId: 1, id: 1, }, - isNativeToken: false, }); expect(depositData).toEqual(expectedDepositData); }); diff --git a/packages/evm/src/utils/assetTransferHelpers.ts b/packages/evm/src/utils/assetTransferHelpers.ts index 9d45e932c..3ba96ed4d 100644 --- a/packages/evm/src/utils/assetTransferHelpers.ts +++ b/packages/evm/src/utils/assetTransferHelpers.ts @@ -18,7 +18,6 @@ interface AssetDepositParams { tokenId?: string; optionalGas?: bigint; optionalMessage?: FungibleTransferOptionalMessage; - isNativeToken: boolean; } export function serializeEvmAddress(evmAddress: `0x${string}`): Uint8Array { @@ -112,15 +111,8 @@ export function encodeOptionalMessage(optionalMessage: FungibleTransferOptionalM } export function createAssetDepositData(depositParams: AssetDepositParams): string { - const { - isNativeToken, - recipientAddress, - destination, - amount, - tokenId, - optionalGas, - optionalMessage, - } = depositParams; + const { recipientAddress, destination, amount, tokenId, optionalGas, optionalMessage } = + depositParams; const recipientAddressSerialized: Uint8Array = serializeDestinationAddress( recipientAddress, @@ -137,12 +129,7 @@ export function createAssetDepositData(depositParams: AssetDepositParams): strin const addressLenInHex = BigNumber.from(recipientAddressSerialized.length).toHexString(); const zeroPaddedAddrLen = hexZeroPad(addressLenInHex, HEX_PADDING); - let depositData; - if (isNativeToken) { - depositData = concat([zeroPaddedAddrLen, recipientAddressSerialized]); - } else { - depositData = concat([zeroPaddedAmount, zeroPaddedAddrLen, recipientAddressSerialized]); - } + let depositData = concat([zeroPaddedAmount, zeroPaddedAddrLen, recipientAddressSerialized]); if (optionalMessage !== undefined && optionalGas !== undefined) { const optionalGasInHex = BigNumber.from(optionalGas).toHexString(); diff --git a/packages/evm/src/utils/nativeTokenDepositHelpers.ts b/packages/evm/src/utils/nativeTokenDepositHelpers.ts index baf91807a..e6193a7b9 100644 --- a/packages/evm/src/utils/nativeTokenDepositHelpers.ts +++ b/packages/evm/src/utils/nativeTokenDepositHelpers.ts @@ -77,14 +77,14 @@ export function getNativeTokenDepositContractArgs( encodeOptionalMessage(optionalMessage!), ]; case 'depositGeneral': - return [destinationNetworkId, depositData]; + return [destinationNetworkId, `0x${depositData.substring(66)}`]; } } export async function getNativeTokenDepositTransaction( depositParams: Omit, nativeTokenAdapter: NativeTokenAdapter, - overrides?: ethers.Overrides, + overrides?: ethers.PayableOverrides, ): Promise { const method = getNativeTokenDepositMethod( depositParams.destinationNetworkType, From acb1ac4d0e1595d93253faae51f2263912842e93 Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 26 Sep 2024 11:13:46 +0200 Subject: [PATCH 8/9] revert changes --- examples/evm-to-evm-fungible-transfer/src/transfer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/evm-to-evm-fungible-transfer/src/transfer.ts b/examples/evm-to-evm-fungible-transfer/src/transfer.ts index 37e887f80..15360aa29 100644 --- a/examples/evm-to-evm-fungible-transfer/src/transfer.ts +++ b/examples/evm-to-evm-fungible-transfer/src/transfer.ts @@ -18,7 +18,7 @@ if (!privateKey) { const SEPOLIA_CHAIN_ID = 11155111; const BASE_SEPOLIA_CHAIN_ID = 84532; const RESOURCE_ID = - "0x1000000000000000000000000000000000000000000000000000000000000000"; + "0x0000000000000000000000000000000000000000000000000000000000001200"; const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL || "https://eth-sepolia.g.alchemy.com/v2/MeCKDrpxLkGOn4LMlBa3cKy1EzzOzwzG"; @@ -43,7 +43,7 @@ export async function erc20Transfer(): Promise { destination: BASE_SEPOLIA_CHAIN_ID, sourceNetworkProvider: web3Provider as unknown as Eip1193Provider, resource: RESOURCE_ID, - amount: BigInt(1) * BigInt(1e17), + amount: BigInt(1) * BigInt(1e6), recipientAddress: destinationAddress, sourceAddress: sourceAddress, optionalGas: BigInt(500000), From c0e2e6d1706a71285bd92ea72804c3c956a3dc5e Mon Sep 17 00:00:00 2001 From: Saad Ahmed Siddiqui Date: Thu, 26 Sep 2024 11:23:05 +0200 Subject: [PATCH 9/9] fix: return type of `getNativeTokenDepositMethod` --- packages/evm/src/utils/nativeTokenDepositHelpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/evm/src/utils/nativeTokenDepositHelpers.ts b/packages/evm/src/utils/nativeTokenDepositHelpers.ts index e6193a7b9..5d9acde68 100644 --- a/packages/evm/src/utils/nativeTokenDepositHelpers.ts +++ b/packages/evm/src/utils/nativeTokenDepositHelpers.ts @@ -29,9 +29,9 @@ export function getNativeTokenDepositMethod( if (destinationNetworkType === Network.EVM) { return 'depositToEVMWithMessage'; } - } - throw new Error('Unsupported deposit method.'); + return 'depositGeneral'; + } } interface NativeDepositParams {