Example of Token Cross-Chain (JS)
EVM to ENDLESS
`First===>: Estimated gas`
//Gas Estimation Method
const getGasPrice = async (chain: ChainData) => {
const provider = getProvider(chain.rpc_url)
const feeData = await provider.getFeeData()
return feeData.gasPrice?.toString() || '0'
}
const contract = await getContract(tokenAddress, IBridgePoolAbi, toChain.rpc_url)
const maxFeePerGasWei = await getGasPrice(toChain) //Get gas through 1559
const arg1 = {
msg_header: _msgHead,
msg_body: `0x${msg_body}`,
}
const amount = await contract.getLpFeeAndFinalAmount(
combainChain(chain).toString(),
sourceToken,
BigInt(toChainNumber(bridgeData.amount, toToken.decimals)).toString(),
) //Get the payment amount by calling the contract
useTokenStore.getState().updateReceiveAmount([...amount][1])
const gaslimit = await contract.processMsg.estimateGas(arg1, [], {
from: '0x0000000000000000000000000000000000000001',
}) //Get gasLimit
const estimatedGasCost = BigNumber(maxFeePerGasWei)
.times(gaslimit.toString())
.div(10 ** toChain.token_decimal)
.toFixed()
`Second===>: Cross-chain`
//Cross-chain method
const bridgeTo = async () => {
const gasFee = useBridgeStore.getState().gasFee
let addr_bridge_token = toChain.addr_bridge_token
const chain_type = getChainType(toChain.id)
const chain_id = toChain.id.split('-')[1]
const chain = new Uint8Array(9)
chain.set(numberToU8(chain_type), 0)
chain.set(numberToU64(Number(chain_id)), 1)
const config = new EndlessConfig({
network: EndlessNetwork,
})
const endless = new Endless(config)
let feeAuto = BigInt(BigNumber(toChainNumber(gasFee, fromChain.token_decimal)).toFixed() || 0)
const functionArguments = [
AccountAddress.fromBs58String(fromToken.address),
chain,
stringToBytes32(addr_bridge_token),
stringToBytes32(receiveAddress),
BigInt(toChainNumber(bridgeData.amount, fromToken.decimals)),
feeAuto,
]
const transferData: EndlessSignAndSubmitTransactionInput = {
payload: {
function: `${getBytes32Address(fromChain.id, fromChain.addr_bridge_token)}::execute::bridge_proposal`,
functionArguments: functionArguments,
typeArguments: [],
},
}
const transactionRes = await useEndlessStore.getState()?.jssdk?.signAndSubmitTransaction(transferData)
useTokenStore.getState().updateProgress(1)
if (transactionRes?.status === UserResponseStatus.APPROVED) {
const result = await endless.waitForTransaction({ transactionHash: transactionRes.args.hash })
if (result.success) {
return {
txhash: transactionRes.args.hash,
bridgeData: {},
}
} else {
throw transactionRes
}
} else {
throw transactionRes
}
}
2、ENDLESS to EVM
## EDS to ETH
`First===>: Estimated gas`
// This method can get the message body and message head required for cross-chain
const getBodyAndHead = (params: IBodyAndHead) => {
const { bridgeData, nonceMap, fromChain, toChain, fromToken, sourceToken, fromWho, toWho } = params
const gas = new BN(bridgeData.feeAuto)
const gasByte = gas.toArray('le', 16)
const nonce = new BN(BigNumber(nonceMap).plus(1).toString())
const nonceByte = nonce.toArray('le', 8)
const msgType = new BN(0)
const msgTypeByte = msgType.toArray('be', 1)
const from_chain_type = new BN(getChainType(fromChain.id))
const from_chain_typeByte = from_chain_type.toArray('be', 1)
const allAmountBN = new BN(BigInt(toChainNumber(bridgeData.amount, fromToken.decimals)).toString())
const allAmountByte = allAmountBN.toArray('be', 16)
const to_chain_type = new BN(getChainType(toChain.id))
const to_chain_typeByte = to_chain_type.toArray('be', 1)
const to_chain_id = new BN(toChain.id.split('-')[1])
const to_chain_idByte = to_chain_id.toArray('le', 8)
const from_chain_id = new BN(fromChain.id.split('-')[1])
const from_chain_idByte = from_chain_id.toArray('le', 8)
const head = msgTypeByte.concat(
Array.from(nonceByte),
Array.from(from_chain_typeByte),
Array.from(from_chain_idByte),
hexToArray(
getBytes32Address(
fromChain.id,
getChainType(fromChain.id) === ChainType.TRX
? base58ToHex(fromChain.addr_bridge_token)
: fromChain.addr_bridge_token,
),
),
Array.from(to_chain_typeByte),
Array.from(to_chain_idByte),
hexToArray(
getBytes32Address(
toChain.id,
getChainType(toChain.id) === ChainType.TRX ? base58ToHex(toChain.addr_bridge_token) : toChain.addr_bridge_token,
),
),
Array.from(gasByte),
)
const body = hexToArray(cusHex(sourceToken)).concat(
Array.from(allAmountByte),
hexToArray(cusHex(fromWho)),
hexToArray(cusHex(toWho)),
)
return { body, head }
}
const { body, head } = getBodyAndHead({
bridgeData: bridgeData,
nonceMap: res,
fromChain: fromChain,
toChain: toChain,
fromToken: fromToken,
sourceToken: sourceToken,
fromWho: fromWho,
toWho: toWho,
})
getEstimateGas(head, body)
// Get gas from to chain
const getEstimateGas = async (mesHead: number[], mesBody: number[]) => {
const txn = await endless.transaction.build.simple({
sender: ENDLESS_SIMULATE_SENDER,
data: {
function: `${ENDLESS_CONTRACT}::execute::bridge_finish_estimate_gas`,
functionArguments: [mesHead, mesBody, [], []],
},
})
const account = new Ed25519PublicKey(ENDLESS_SIMULATE_PUBLICKEY)
const transactionRes = await endless.transaction.simulate.simple({
signerPublicKey: account,
transaction: txn,
feePayerPublicKey: account,
})
const gasFee = BigNumber(transactionRes[0].gas_used || 0)
.times(transactionRes[0].gas_unit_price)
.div(10 ** 8)
.toFixed()
}
`Second===>: Cross-chain`
//Cross-chain method
const bridgeTo = async () => {
await approveErc20({
token: fromToken.address,
spender: fromChain.addr_bridge_token,
decimal: fromToken.decimals,
payAmount: bridgeData.amount,
rpc: fromChain.rpc_url,
nativeToken: fromChain.native_token,
approveAmount: bridgeData.amount,
})
let value = BigNumber(0)
value = value.plus(BigNumber(toChainNumber(gasFee, fromChain.token_decimal) || 0))
if (bridgeData.feeFrom) {
value = value.plus(bridgeData.feeFrom || 0)
}
if (fromToken.address.toLocaleLowerCase() === fromChain.native_token.toLocaleLowerCase()) {
value = value.plus(toChainNumber(bridgeData.amount, fromChain.token_decimal))
}
if (collFee) {
value = value.plus(collFee.toString())
}
// value is composed of gas + platform fee + amount + collect fee
const _bridgeData = [
getBytes32Address(fromChain.id, fromToken.address),
{
chain_type: getChainType(toChain.id),
chain_id: toChain.id.split('-')[1],
},
getBytes32Address(toChain.id, receiveAddress),
getBytes32Address(toChain.id, toChain.addr_bridge_token),
BigInt(toChainNumber(bridgeData.amount, fromToken.decimals)),
BigInt(BigNumber(toChainNumber(gasFee, fromChain.token_decimal)).toFixed()),
]
const params = {
from: address,
to: fromChain.addr_bridge_token,
value: numberToHexString(value.toString()),
data: new ethers.Interface(IBridgePoolAbi).encodeFunctionData('bridgeToken', _bridgeData),
}
await estimateGas({ params, rpc: fromChain.rpc_url })
const txhash = (await sendTransaction([params])) || ''
}
Last updated