sdk/js: reconstruct TokenId obect in getForeignAssetAptos to reduce number of RPC calls

This commit is contained in:
heyitaki 2023-02-09 01:57:49 +00:00 committed by Evan Gray
parent e0bebed306
commit 1deee6f7a1
2 changed files with 64 additions and 45 deletions

View File

@ -507,6 +507,17 @@ describe("Aptos NFT SDK tests", () => {
); );
expect(tokenId1.token_data_id.creator).toBe(tokenId2.token_data_id.creator); expect(tokenId1.token_data_id.creator).toBe(tokenId2.token_data_id.creator);
expect(tokenId1.token_data_id.name).not.toBe(tokenId2.token_data_id.name); expect(tokenId1.token_data_id.name).not.toBe(tokenId2.token_data_id.name);
// check if token that does not exist correctly returns null foreign asset address
expect(
await getForeignAssetAptos(
aptosClient,
APTOS_NFT_BRIDGE_ADDRESS,
CHAIN_ID_ETH,
tryNativeToUint8Array(ethNfts.address, CHAIN_ID_ETH),
BigInt(2)
)
).toBe(null);
}); });
}); });

View File

@ -1,12 +1,18 @@
import { BN } from "@project-serum/anchor"; import { BN } from "@project-serum/anchor";
import { PublicKeyInitData } from "@solana/web3.js"; import { PublicKeyInitData } from "@solana/web3.js";
import { LCDClient } from "@terra-money/terra.js"; import { LCDClient } from "@terra-money/terra.js";
import { AptosClient, HexString, TokenTypes, Types } from "aptos"; import {
ApiError,
AptosClient,
HexString,
TokenClient,
TokenTypes,
} from "aptos";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { isBytes } from "ethers/lib/utils"; import { isBytes } from "ethers/lib/utils";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { CHAIN_ID_SOLANA } from ".."; import { CHAIN_ID_SOLANA } from "..";
import { CreateTokenDataEvent, NftBridgeState } from "../aptos/types"; import { CreateTokenDataEvent } from "../aptos/types";
import { NFTBridge__factory } from "../ethers-contracts"; import { NFTBridge__factory } from "../ethers-contracts";
import { deriveWrappedMintKey } from "../solana/nftBridge"; import { deriveWrappedMintKey } from "../solana/nftBridge";
import { import {
@ -16,6 +22,7 @@ import {
coalesceChainId, coalesceChainId,
deriveResourceAccountAddress, deriveResourceAccountAddress,
ensureHexPrefix, ensureHexPrefix,
getTokenIdFromTokenHash,
hexToUint8Array, hexToUint8Array,
} from "../utils"; } from "../utils";
@ -135,24 +142,7 @@ export async function getForeignAssetAptos(
): Promise<TokenTypes.TokenId | null> { ): Promise<TokenTypes.TokenId | null> {
const originChainId = coalesceChainId(originChain); const originChainId = coalesceChainId(originChain);
if (originChainId === CHAIN_ID_APTOS) { if (originChainId === CHAIN_ID_APTOS) {
const state = ( return getTokenIdFromTokenHash(client, nftBridgeAddress, originAddress);
await client.getAccountResource(
nftBridgeAddress,
`${nftBridgeAddress}::state::State`
)
).data as NftBridgeState;
const handle = state.native_infos.handle;
const { token_data_id, property_version } = (await client.getTableItem(
handle,
{
key_type: `${nftBridgeAddress}::token_hash::TokenHash`,
value_type: `0x3::token::TokenId`,
key: {
hash: HexString.fromUint8Array(originAddress).hex(),
},
}
)) as TokenTypes.TokenId & { __headers: unknown };
return { token_data_id, property_version };
} }
const creatorAddress = await deriveResourceAccountAddress( const creatorAddress = await deriveResourceAccountAddress(
@ -175,33 +165,51 @@ export async function getForeignAssetAptos(
const tokenIdAsUint8Array = new Uint8Array(tokenId); const tokenIdAsUint8Array = new Uint8Array(tokenId);
// Each creator account should contain a single collection that contains the // Each creator account should contain a single collection that contains the
// token creation event with the token id that we're looking for. // corresponding token creation events. Return if we find it in the first
// page, otherwise reconstruct the token id from the first event.
const PAGE_SIZE = 25; const PAGE_SIZE = 25;
let curr = 0; const events = (await client.getEventsByEventHandle(
let numEvents = PAGE_SIZE; creatorAddress,
let event: Types.Event | undefined = undefined; "0x3::token::Collections",
while (numEvents === PAGE_SIZE && !event) { "create_token_data_events",
const events = await client.getEventsByEventHandle( { limit: PAGE_SIZE }
creatorAddress, )) as CreateTokenDataEvent[];
"0x3::token::Collections", const event = events.find(
"create_token_data_events", (e) =>
{ limit: PAGE_SIZE, start: curr } ensureHexPrefix((e as CreateTokenDataEvent).data.id.name) ===
); HexString.fromUint8Array(tokenIdAsUint8Array).hex()
event = events.find( );
(e) => if (event) {
ensureHexPrefix((e as CreateTokenDataEvent).data.id.name) === return {
HexString.fromUint8Array(tokenIdAsUint8Array).hex() token_data_id: event.data.id,
); property_version: "0", // property version always "0" for wrapped tokens
numEvents = events.length; };
curr += numEvents;
} }
if (!event) { // Skip pagination, reconstruct token id, and check to see if it exists
throw new Error("Invalid token ID"); try {
} const tokenIdObj = {
token_data_id: {
...events[0].data.id,
name: HexString.fromUint8Array(tokenIdAsUint8Array).noPrefix(),
},
property_version: "0",
};
await new TokenClient(client).getTokenData(
tokenIdObj.token_data_id.creator,
tokenIdObj.token_data_id.collection,
tokenIdObj.token_data_id.name
);
return tokenIdObj;
} catch (e) {
if (
e instanceof ApiError &&
e.status === 404 &&
e.errorCode === "table_item_not_found"
) {
return null;
}
return { throw e;
token_data_id: event.data.id, }
property_version: "0",
};
} }