Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

feat(evm): Expanding SDK to support Native transfer with optional con… #545

Merged
merged 10 commits into from
Sep 26, 2024
8 changes: 4 additions & 4 deletions examples/evm-to-evm-fungible-transfer/src/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
"0x0000000000000000000000000000000000000000000000000000000000001200";
const SEPOLIA_RPC_URL =
Expand All @@ -40,7 +40,7 @@ export async function erc20Transfer(): Promise<void> {

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(1e6),
Expand All @@ -57,15 +57,15 @@ export async function erc20Transfer(): Promise<void> {
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 })}`
);
}

const transferTx = await transfer.getTransferTransaction();
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)}`
);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/config/localConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const localConfig: SygmaConfig = {
caipId: '',
chainId: 1337,
name: 'Ethereum 1',
nativeTokenAdapter: '',
type: Network.EVM,
bridge: '0x6CdE2Cd82a4F8B74693Ff5e194c19CA08c2d1c68',
handlers: [
Expand Down Expand Up @@ -76,6 +77,7 @@ export const localConfig: SygmaConfig = {
caipId: '',
chainId: 1338,
name: 'evm2',
nativeTokenAdapter: '',
type: Network.EVM,
bridge: '0x6CdE2Cd82a4F8B74693Ff5e194c19CA08c2d1c68',
handlers: [
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export type FeeHandler = {

export interface EthereumConfig extends BaseConfig<Network.EVM> {
handlers: Array<Handler>;
nativeTokenAdapter: string;
feeRouter: string;
feeHandlers: Array<FeeHandler>;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
},
"dependencies": {
"@buildwithsygma/core": "workspace:^",
"@buildwithsygma/sygma-contracts": "^2.8.0",
"@buildwithsygma/sygma-contracts": "^2.10.1",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/bytes": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
Expand Down
13 changes: 6 additions & 7 deletions packages/evm/src/evmAssetTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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 { getTransactionOverrides } from './utils/depositFn.js';
import { createTransactionRequest } from './utils/transaction.js';

/**
Expand Down Expand Up @@ -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);
}

/**
Expand Down
64 changes: 60 additions & 4 deletions packages/evm/src/fungibleAssetTransfer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { EvmResource } from '@buildwithsygma/core';
import type { EthereumConfig, 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, utils } from 'ethers';
import type { ethers, PopulatedTransaction } from 'ethers';
Expand All @@ -13,7 +17,8 @@ import type {
TransactionRequest,
} from './types.js';
import { approve, getERC20Allowance } from './utils/approveAndCheckFns.js';
import { createFungibleDepositData } from './utils/assetTransferHelpers.js';
import { createAssetDepositData } from './utils/assetTransferHelpers.js';
import { getNativeTokenDepositTransaction } from './utils/nativeTokenDepositHelpers.js';
import { createTransactionRequest } from './utils/transaction.js';

/**
Expand Down Expand Up @@ -60,13 +65,22 @@ 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
* @returns {string}
*/
protected getDepositData(): string {
return createFungibleDepositData({
return createAssetDepositData({
destination: this.destination,
recipientAddress: this.recipientAddress,
amount: this.adjustedAmount,
Expand Down Expand Up @@ -130,6 +144,10 @@ class FungibleAssetTransfer extends AssetTransfer {
public async getApprovalTransactions(
overrides?: ethers.Overrides,
): Promise<Array<TransactionRequest>> {
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);
Expand Down Expand Up @@ -163,6 +181,44 @@ class FungibleAssetTransfer extends AssetTransfer {

return approvals.map(approval => createTransactionRequest(approval));
}

protected async getNativeTokenDepositTransaction(
overrides?: ethers.Overrides,
): Promise<TransactionRequest> {
const domainConfig = this.config.getDomainConfig(this.source) as EthereumConfig;
const provider = new Web3Provider(this.sourceNetworkProvider);
const nativeTokenAdapter = NativeTokenAdapter__factory.connect(
domainConfig.nativeTokenAdapter,
provider,
);

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(),
destinationNetworkType: this.destination.type,
parachainId: this.destination.parachainId,
recipientAddress: this.recipientAddress,
optionalMessage: this.optionalMessage,
optionalGas: this.optionalGas,
depositData: this.getDepositData(),
},
nativeTokenAdapter,
payableOverrides,
);
}

public async getTransferTransaction(overrides?: ethers.Overrides): Promise<TransactionRequest> {
if (this.isNativeTransfer()) {
return await this.getNativeTokenDepositTransaction(overrides);
}

return super.getTransferTransaction(overrides);
}
}

/**
Expand Down
11 changes: 5 additions & 6 deletions packages/evm/src/genericMessageTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ 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 { executeDeposit } from './utils/index.js';
import { createTransactionRequest } from './utils/transaction.js';

/**
Expand Down Expand Up @@ -143,16 +143,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
Expand Down
4 changes: 2 additions & 2 deletions packages/evm/src/nonFungibleAssetTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions packages/evm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
8 changes: 4 additions & 4 deletions packages/evm/src/utils/__test__/assetTransferHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { arrayify } from '@ethersproject/bytes';
import { utils } from 'ethers';

import {
createFungibleDepositData,
createAssetDepositData,
createSubstrateMultiLocationObject,
serializeEvmAddress,
serializeSubstrateAddress,
Expand All @@ -16,7 +16,7 @@ describe('createERCDepositData', () => {
const expectedDepositData =
'0x000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000141234567890123456789012345678901234567890';

const depositData = createFungibleDepositData({
const depositData = createAssetDepositData({
recipientAddress,
amount,
destination: {
Expand All @@ -37,7 +37,7 @@ describe('createERCDepositData', () => {
const expectedDepositData =
'0x00000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000027010200511f0100fac48520983815e2022ded67ca8d27b73d51b1b022284c48b4eccbb7a328d80f';

const depositData = createFungibleDepositData({
const depositData = createAssetDepositData({
recipientAddress,
amount,
destination: {
Expand All @@ -59,7 +59,7 @@ describe('createERCDepositData', () => {
const expectedDepositData =
'0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000002a746231717366797a6c3932707637776b79616a3074666a6474777663736a383430703030346a676c7670';

const depositData = createFungibleDepositData({
const depositData = createAssetDepositData({
recipientAddress,
amount: tokenAmount,
destination: {
Expand Down
Loading