sdk/js: Aptos transfer with payload support
This commit is contained in:
parent
451f7d2c63
commit
04b7afeb62
|
@ -227,11 +227,19 @@ export const transferTokensWithPayload = (
|
|||
amount: string,
|
||||
recipientChain: ChainId | ChainName,
|
||||
recipient: Uint8Array,
|
||||
relayerFee: string,
|
||||
nonce: number,
|
||||
payload: string
|
||||
payload: Uint8Array
|
||||
): Types.EntryFunctionPayload => {
|
||||
throw new Error("Transfer with payload are not yet supported in the sdk");
|
||||
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
|
||||
if (!isValidAptosType(fullyQualifiedType)) {
|
||||
throw new Error("Invalid qualified type");
|
||||
}
|
||||
const recipientChainId = coalesceChainId(recipientChain);
|
||||
return {
|
||||
function: `${tokenBridgeAddress}::transfer_tokens::transfer_tokens_with_payload_entry`,
|
||||
type_arguments: [fullyQualifiedType],
|
||||
arguments: [amount, recipientChainId, recipient, nonce, payload],
|
||||
};
|
||||
};
|
||||
|
||||
// Created wrapped coin
|
||||
|
|
|
@ -32,6 +32,7 @@ import {
|
|||
getOriginalAssetAptos,
|
||||
getSignedVAAWithRetry,
|
||||
hexToUint8Array,
|
||||
parseTokenTransferVaa,
|
||||
redeemOnAptos,
|
||||
redeemOnEth,
|
||||
transferFromAptos,
|
||||
|
@ -376,6 +377,156 @@ describe("Aptos SDK tests", () => {
|
|||
balanceBeforeTransferEth.sub(balanceAfterTransferEth).toString()
|
||||
).toEqual(amount.toString());
|
||||
|
||||
// clean up
|
||||
provider.destroy();
|
||||
});
|
||||
test("Transfer native token with payload from Aptos to Ethereum", async () => {
|
||||
const APTOS_TOKEN_BRIDGE = CONTRACTS.DEVNET.aptos.token_bridge;
|
||||
const APTOS_CORE_BRIDGE = CONTRACTS.DEVNET.aptos.core;
|
||||
const COIN_TYPE = "0x1::aptos_coin::AptosCoin";
|
||||
|
||||
// setup aptos
|
||||
const client = new AptosClient(APTOS_NODE_URL);
|
||||
const sender = new AptosAccount();
|
||||
const faucet = new FaucetClient(APTOS_NODE_URL, APTOS_FAUCET_URL);
|
||||
await faucet.fundAccount(sender.address(), 100_000_000);
|
||||
|
||||
// attest native aptos token
|
||||
const attestPayload = attestFromAptos(
|
||||
APTOS_TOKEN_BRIDGE,
|
||||
CHAIN_ID_APTOS,
|
||||
COIN_TYPE
|
||||
);
|
||||
let tx = (await generateSignAndSubmitEntryFunction(
|
||||
client,
|
||||
sender,
|
||||
attestPayload
|
||||
)) as Types.UserTransaction;
|
||||
await client.waitForTransaction(tx.hash);
|
||||
|
||||
// get signed attest vaa
|
||||
let sequence = parseSequenceFromLogAptos(APTOS_CORE_BRIDGE, tx);
|
||||
expect(sequence).toBeTruthy();
|
||||
|
||||
const { vaaBytes: attestVAA } = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
CHAIN_ID_APTOS,
|
||||
APTOS_TOKEN_BRIDGE_EMITTER_ADDRESS,
|
||||
sequence!,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
},
|
||||
1000,
|
||||
5
|
||||
);
|
||||
expect(attestVAA).toBeTruthy();
|
||||
|
||||
// setup ethereum
|
||||
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
|
||||
const recipient = new ethers.Wallet(ETH_PRIVATE_KEY6, provider);
|
||||
const recipientAddress = await recipient.getAddress();
|
||||
const ethTokenBridge = CONTRACTS.DEVNET.ethereum.token_bridge;
|
||||
try {
|
||||
await createWrappedOnEth(ethTokenBridge, recipient, attestVAA);
|
||||
} catch (e) {
|
||||
// this could fail because the token is already attested (in an unclean env)
|
||||
}
|
||||
|
||||
// check attestation on ethereum
|
||||
const externalAddress = hexToUint8Array(
|
||||
await getExternalAddressFromType(COIN_TYPE)
|
||||
);
|
||||
const address = getForeignAssetEth(
|
||||
ethTokenBridge,
|
||||
provider,
|
||||
CHAIN_ID_APTOS,
|
||||
externalAddress
|
||||
);
|
||||
expect(address).toBeTruthy();
|
||||
expect(address).not.toBe(ethers.constants.AddressZero);
|
||||
|
||||
// transfer from aptos
|
||||
const balanceBeforeTransferAptos = ethers.BigNumber.from(
|
||||
await getBalanceAptos(client, COIN_TYPE, sender.address())
|
||||
);
|
||||
const payload = Buffer.from("All your base are belong to us");
|
||||
const transferPayload = transferFromAptos(
|
||||
APTOS_TOKEN_BRIDGE,
|
||||
COIN_TYPE,
|
||||
(10_000_000).toString(),
|
||||
CHAIN_ID_ETH,
|
||||
tryNativeToUint8Array(recipientAddress, CHAIN_ID_ETH),
|
||||
"0",
|
||||
payload
|
||||
);
|
||||
tx = (await generateSignAndSubmitEntryFunction(
|
||||
client,
|
||||
sender,
|
||||
transferPayload
|
||||
)) as Types.UserTransaction;
|
||||
await client.waitForTransaction(tx.hash);
|
||||
const balanceAfterTransferAptos = ethers.BigNumber.from(
|
||||
await getBalanceAptos(client, COIN_TYPE, sender.address())
|
||||
);
|
||||
expect(
|
||||
balanceBeforeTransferAptos
|
||||
.sub(balanceAfterTransferAptos)
|
||||
.gt((10_000_000).toString())
|
||||
).toBe(true);
|
||||
|
||||
// get signed transfer vaa
|
||||
sequence = parseSequenceFromLogAptos(APTOS_CORE_BRIDGE, tx);
|
||||
expect(sequence).toBeTruthy();
|
||||
|
||||
const { vaaBytes: transferVAA } = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
CHAIN_ID_APTOS,
|
||||
APTOS_TOKEN_BRIDGE_EMITTER_ADDRESS,
|
||||
sequence!,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
},
|
||||
1000,
|
||||
5
|
||||
);
|
||||
expect(transferVAA).toBeTruthy();
|
||||
const { tokenTransferPayload } = parseTokenTransferVaa(transferVAA);
|
||||
expect(tokenTransferPayload.toString()).toBe(payload.toString());
|
||||
|
||||
// get balance on eth
|
||||
const originAssetHex = tryNativeToUint8Array(COIN_TYPE, CHAIN_ID_APTOS);
|
||||
if (!originAssetHex) {
|
||||
throw new Error("originAssetHex is null");
|
||||
}
|
||||
|
||||
const foreignAsset = await getForeignAssetEth(
|
||||
ethTokenBridge,
|
||||
provider,
|
||||
CHAIN_ID_APTOS,
|
||||
originAssetHex
|
||||
);
|
||||
if (!foreignAsset) {
|
||||
throw new Error("foreignAsset is null");
|
||||
}
|
||||
|
||||
const balanceBeforeTransferEth = await getBalanceEth(
|
||||
foreignAsset,
|
||||
recipient
|
||||
);
|
||||
|
||||
// redeem on eth
|
||||
await redeemOnEth(ethTokenBridge, recipient, transferVAA);
|
||||
expect(
|
||||
await getIsTransferCompletedEth(ethTokenBridge, provider, transferVAA)
|
||||
).toBe(true);
|
||||
const balanceAfterTransferEth = await getBalanceEth(
|
||||
foreignAsset,
|
||||
recipient
|
||||
);
|
||||
expect(
|
||||
balanceAfterTransferEth.sub(balanceBeforeTransferEth).toNumber()
|
||||
).toEqual(10_000_000);
|
||||
|
||||
// clean up
|
||||
provider.destroy();
|
||||
});
|
||||
|
|
|
@ -885,7 +885,7 @@ export async function transferNearFromNear(
|
|||
* @param recipientChain Target chain
|
||||
* @param recipient Recipient's address on target chain
|
||||
* @param relayerFee Fee to pay relayer
|
||||
* @param payload Payload3 data, leave undefined for basic token transfers
|
||||
* @param payload Payload3 data, leave null for basic token transfers
|
||||
* @returns Transaction payload
|
||||
*/
|
||||
export function transferFromAptos(
|
||||
|
@ -895,7 +895,7 @@ export function transferFromAptos(
|
|||
recipientChain: ChainId | ChainName,
|
||||
recipient: Uint8Array,
|
||||
relayerFee: string = "0",
|
||||
payload: string = ""
|
||||
payload: Uint8Array | null = null
|
||||
): Types.EntryFunctionPayload {
|
||||
if (payload) {
|
||||
// Currently unsupported
|
||||
|
@ -905,7 +905,6 @@ export function transferFromAptos(
|
|||
amount,
|
||||
recipientChain,
|
||||
recipient,
|
||||
relayerFee,
|
||||
createNonce().readUInt32LE(0),
|
||||
payload
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue