diff --git a/sdk/js/CHANGELOG.md b/sdk/js/CHANGELOG.md index 67ebc6bc1..caba0822a 100644 --- a/sdk/js/CHANGELOG.md +++ b/sdk/js/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.9.0 + +### Changed + +Use FQTs in Aptos SDK + ## 0.8.0 ### Added diff --git a/sdk/js/package.json b/sdk/js/package.json index 7a983694a..431800644 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@certusone/wormhole-sdk", - "version": "0.8.0", + "version": "0.9.0", "description": "SDK for interacting with Wormhole", "homepage": "https://wormhole.com", "main": "./lib/cjs/index.js", diff --git a/sdk/js/src/token_bridge/__tests__/aptos-integration.ts b/sdk/js/src/token_bridge/__tests__/aptos-integration.ts index 1b09a7d9d..5ca11a7b0 100644 --- a/sdk/js/src/token_bridge/__tests__/aptos-integration.ts +++ b/sdk/js/src/token_bridge/__tests__/aptos-integration.ts @@ -291,29 +291,20 @@ describe("Aptos SDK tests", () => { } // check attestation on aptos - const aptosWrappedAddress = await getForeignAssetAptos( + const aptosWrappedType = await getForeignAssetAptos( client, aptosTokenBridge, CHAIN_ID_ETH, TEST_ERC20 ); - if (!aptosWrappedAddress) { + if (!aptosWrappedType) { throw new Error("Failed to create wrapped coin on Aptos"); } - const wrappedType = getAssetFullyQualifiedType( - aptosTokenBridge, - CHAIN_ID_ETH, - TEST_ERC20 - ); - if (!wrappedType) { - throw new Error("wrappedType is null"); - } - const info = await getOriginalAssetAptos( client, aptosTokenBridge, - wrappedType + aptosWrappedType ); expect(uint8ArrayToHex(info.assetAddress)).toEqual( tryNativeToHexString(TEST_ERC20, CHAIN_ID_ETH) @@ -323,7 +314,7 @@ describe("Aptos SDK tests", () => { await getIsWrappedAssetAptos( client, aptosTokenBridge, - aptosWrappedAddress + aptosWrappedType ) ); @@ -363,7 +354,7 @@ describe("Aptos SDK tests", () => { // redeem on aptos const balanceBeforeTransferAptos = ethers.BigNumber.from( - await getBalanceAptos(client, wrappedType, recipient.address()) + await getBalanceAptos(client, aptosWrappedType, recipient.address()) ); const redeemPayload = await redeemOnAptos( client, @@ -377,7 +368,7 @@ describe("Aptos SDK tests", () => { // check balances const balanceAfterTransferAptos = ethers.BigNumber.from( - await getBalanceAptos(client, wrappedType, recipient.address()) + await getBalanceAptos(client, aptosWrappedType, recipient.address()) ); expect( balanceAfterTransferAptos.sub(balanceBeforeTransferAptos).toString() diff --git a/sdk/js/src/token_bridge/getForeignAsset.ts b/sdk/js/src/token_bridge/getForeignAsset.ts index 90f0f10ab..24aa469f3 100644 --- a/sdk/js/src/token_bridge/getForeignAsset.ts +++ b/sdk/js/src/token_bridge/getForeignAsset.ts @@ -14,8 +14,8 @@ import { ChainName, CHAIN_ID_ALGORAND, coalesceChainId, - ensureHexPrefix, - getForeignAssetAddress, + getAssetFullyQualifiedType, + coalesceModuleAddress, } from "../utils"; import { Provider } from "near-api-js/lib/providers"; import { LCDClient as XplaLCDClient } from "@xpla/xpla.js"; @@ -192,12 +192,12 @@ export async function getForeignAssetNear( } /** - * Get native module address of asset given its origin info. + * Get qualified type of asset on Aptos given its origin info. * @param client Client used to transfer data to/from Aptos node * @param tokenBridgeAddress Address of token bridge * @param originChain Chain ID of chain asset is originally from * @param originAddress Asset address on origin chain - * @returns Asset module address on Aptos + * @returns Fully qualified type of asset on Aptos */ export async function getForeignAssetAptos( client: AptosClient, @@ -206,22 +206,22 @@ export async function getForeignAssetAptos( originAddress: string ): Promise { const originChainId = coalesceChainId(originChain); - const assetAddress = getForeignAssetAddress( + const assetFullyQualifiedType = getAssetFullyQualifiedType( tokenBridgeAddress, originChainId, originAddress ); - if (!assetAddress) { + if (!assetFullyQualifiedType) { return null; } try { // check if asset exists and throw if it doesn't await client.getAccountResource( - assetAddress, - `0x1::coin::CoinInfo<${ensureHexPrefix(assetAddress)}::coin::T>` + coalesceModuleAddress(assetFullyQualifiedType), + `0x1::coin::CoinInfo<${assetFullyQualifiedType}>` ); - return assetAddress; + return assetFullyQualifiedType; } catch (e) { return null; } diff --git a/sdk/js/src/token_bridge/getIsWrappedAsset.ts b/sdk/js/src/token_bridge/getIsWrappedAsset.ts index d688087fa..7c533cf25 100644 --- a/sdk/js/src/token_bridge/getIsWrappedAsset.ts +++ b/sdk/js/src/token_bridge/getIsWrappedAsset.ts @@ -6,7 +6,12 @@ import { AptosClient } from "aptos"; import { ethers } from "ethers"; import { Bridge__factory } from "../ethers-contracts"; import { importTokenWasm } from "../solana/wasm"; -import { CHAIN_ID_INJECTIVE, ensureHexPrefix, tryNativeToHexString } from "../utils"; +import { + CHAIN_ID_INJECTIVE, + ensureHexPrefix, + coalesceModuleAddress, + tryNativeToHexString, +} from "../utils"; import { safeBigIntToNumber } from "../utils/bigint"; import { getForeignAssetInjective } from "./getForeignAsset"; @@ -120,18 +125,21 @@ export function getIsWrappedAssetNear( * Determines whether or not given address is wrapped or native to Aptos. * @param client Client used to transfer data to/from Aptos node * @param tokenBridgeAddress Address of token bridge - * @param assetAddress Module address of asset + * @param assetFullyQualifiedType Fully qualified type of asset * @returns True if asset is wrapped */ export async function getIsWrappedAssetAptos( client: AptosClient, tokenBridgeAddress: string, - assetAddress: string, + assetFullyQualifiedType: string ): Promise { - assetAddress = ensureHexPrefix(assetAddress); + assetFullyQualifiedType = ensureHexPrefix(assetFullyQualifiedType); try { // get origin info from asset address - await client.getAccountResource(assetAddress, `${tokenBridgeAddress}::state::OriginInfo`); + await client.getAccountResource( + coalesceModuleAddress(assetFullyQualifiedType), + `${tokenBridgeAddress}::state::OriginInfo` + ); return true; } catch { return false; diff --git a/sdk/js/src/token_bridge/getOriginalAsset.ts b/sdk/js/src/token_bridge/getOriginalAsset.ts index ef943ec3c..3b2acb3fa 100644 --- a/sdk/js/src/token_bridge/getOriginalAsset.ts +++ b/sdk/js/src/token_bridge/getOriginalAsset.ts @@ -326,7 +326,7 @@ export async function getOriginalAssetAptos( fullyQualifiedType: string ): Promise { if (!isValidAptosType(fullyQualifiedType)) { - throw new Error("Need fully qualified address"); + throw new Error("Invalid qualified type"); } let originInfo: OriginInfo | undefined; diff --git a/sdk/js/src/utils/aptos.ts b/sdk/js/src/utils/aptos.ts index 6ab81bb3f..e27eb3454 100644 --- a/sdk/js/src/utils/aptos.ts +++ b/sdk/js/src/utils/aptos.ts @@ -109,7 +109,7 @@ export const getAssetFullyQualifiedType = ( if (originChain === CHAIN_ID_APTOS) { // originAddress should be of form address::module::type if (!isValidAptosType(originAddress)) { - console.error("Need fully qualified address for native asset"); + console.error("Invalid qualified type"); return null; } @@ -230,6 +230,15 @@ export async function getTypeFromExternalAddress( } } +/** + * Returns module address from given fully qualified type/module address. + * @param str FQT or module address + * @returns Module address + */ +export const coalesceModuleAddress = (str: string): string => { + return str.split("::")[0]; +}; + /** * Simulates given raw transaction and either returns the resulting transaction that was submitted * to the mempool, or throws if it fails.