Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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()
wainola marked this conversation as resolved.
Show resolved Hide resolved
);
}

/**
* 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 [];
wainola marked this conversation as resolved.
Show resolved Hide resolved
}

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