sdk/js: normalize all sui addresses and types being compared

This commit is contained in:
heyitaki 2023-05-17 18:29:02 +00:00 committed by aki
parent 2402e2fbcf
commit 7608b2b740
11 changed files with 104 additions and 120 deletions

View File

@ -1,11 +0,0 @@
import { unnormalizeSuiAddress } from "./utils";
describe("Sui utils tests", () => {
test("Test unnormalizeSuiAddress", () => {
const initial =
"0x09bc8dd67bbbf59a43a9081d7166f9b41740c3a8ae868c4902d30eb247292ba4::coin::COIN";
const expected =
"0x9bc8dd67bbbf59a43a9081d7166f9b41740c3a8ae868c4902d30eb247292ba4::coin::COIN";
expect(unnormalizeSuiAddress(initial)).toBe(expected);
});
});

View File

@ -10,10 +10,10 @@ import {
SuiTransactionBlockResponse, SuiTransactionBlockResponse,
TransactionBlock, TransactionBlock,
} from "@mysten/sui.js"; } from "@mysten/sui.js";
import { DynamicFieldPage } from "@mysten/sui.js/dist/types/dynamic_fields";
import { ensureHexPrefix } from "../utils"; import { ensureHexPrefix } from "../utils";
import { SuiRpcValidationError } from "./error"; import { SuiRpcValidationError } from "./error";
import { SuiError } from "./types"; import { SuiError } from "./types";
import { DynamicFieldPage } from "@mysten/sui.js/dist/types/dynamic_fields";
const MAX_PURE_ARGUMENT_SIZE = 16 * 1024; const MAX_PURE_ARGUMENT_SIZE = 16 * 1024;
const UPGRADE_CAP_TYPE = "0x2::package::UpgradeCap"; const UPGRADE_CAP_TYPE = "0x2::package::UpgradeCap";
@ -46,16 +46,18 @@ export const getEmitterAddressAndSequenceFromResponseSui = (
response: SuiTransactionBlockResponse response: SuiTransactionBlockResponse
): { emitterAddress: string; sequence: string } => { ): { emitterAddress: string; sequence: string } => {
const wormholeMessageEventType = `${originalCoreBridgePackageId}::publish_message::WormholeMessage`; const wormholeMessageEventType = `${originalCoreBridgePackageId}::publish_message::WormholeMessage`;
const event = response.events?.find( const event = response.events?.find((e) =>
(e) => e.type === wormholeMessageEventType isSameType(e.type, wormholeMessageEventType)
); );
if (event === undefined) { if (event === undefined) {
throw new Error(`${wormholeMessageEventType} event type not found`); throw new Error(`${wormholeMessageEventType} event type not found`);
} }
const { sender, sequence } = event.parsedJson || {}; const { sender, sequence } = event.parsedJson || {};
if (sender === undefined || sequence === undefined) { if (sender === undefined || sequence === undefined) {
throw new Error("Can't find sender or sequence"); throw new Error("Can't find sender or sequence");
} }
return { emitterAddress: sender.substring(2), sequence }; return { emitterAddress: sender.substring(2), sequence };
}; };
@ -109,7 +111,7 @@ export const getOwnedObjectId = async (
type: string type: string
): Promise<string | null> => { ): Promise<string | null> => {
// Upgrade caps are a special case // Upgrade caps are a special case
if (normalizeSuiType(type) === normalizeSuiType(UPGRADE_CAP_TYPE)) { if (isSameType(type, UPGRADE_CAP_TYPE)) {
throw new Error( throw new Error(
"`getOwnedObjectId` should not be used to get the object ID of an `UpgradeCap`. Use `getUpgradeCapObjectId` instead." "`getOwnedObjectId` should not be used to get the object ID of an `UpgradeCap`. Use `getUpgradeCapObjectId` instead."
); );
@ -168,8 +170,7 @@ export const getOwnedObjectIdPaginated = async (
throw new SuiRpcValidationError(res); throw new SuiRpcValidationError(res);
} }
const object = res.data.find((d) => d.data?.type === type); const object = res.data.find((d) => isSameType(d.data?.type || "", type));
if (!object && res.hasNextPage) { if (!object && res.hasNextPage) {
return getOwnedObjectIdPaginated( return getOwnedObjectIdPaginated(
provider, provider,
@ -208,11 +209,13 @@ export async function getPackageId(
if (!currentPackage) { if (!currentPackage) {
throw new Error("CurrentPackage not found"); throw new Error("CurrentPackage not found");
} }
const fields = await getObjectFields(provider, currentPackage.objectId); const fields = await getObjectFields(provider, currentPackage.objectId);
const packageId = fields?.value?.fields?.package; const packageId = fields?.value?.fields?.package;
if (!packageId) { if (!packageId) {
throw new Error("Unable to get current package"); throw new Error("Unable to get current package");
} }
return packageId; return packageId;
} }
@ -225,7 +228,7 @@ export const getPackageIdFromType = (type: string): string | null => {
export const getTableKeyType = (tableType: string): string | null => { export const getTableKeyType = (tableType: string): string | null => {
if (!tableType) return null; if (!tableType) return null;
const match = tableType.match(/0x2::table::Table<(.*)>/); const match = trimSuiType(tableType).match(/0x2::table::Table<(.*)>/);
if (!match) return null; if (!match) return null;
const [keyType] = match[1].split(","); const [keyType] = match[1].split(",");
if (!isValidSuiType(keyType)) return null; if (!isValidSuiType(keyType)) return null;
@ -276,9 +279,7 @@ export const getTokenCoinType = async (
); );
} }
const fields = getFieldsFromObjectResponse(response); const fields = getFieldsFromObjectResponse(response);
return fields?.value return fields?.value ? trimSuiType(ensureHexPrefix(fields.value)) : null;
? unnormalizeSuiAddress(ensureHexPrefix(fields.value))
: null;
}; };
export const getTokenFromTokenRegistry = async ( export const getTokenFromTokenRegistry = async (
@ -343,7 +344,7 @@ export const getUpgradeCapObjectId = async (
): Promise<string | null> => { ): Promise<string | null> => {
const res = await provider.getOwnedObjects({ const res = await provider.getOwnedObjects({
owner, owner,
filter: { StructType: UPGRADE_CAP_TYPE }, filter: { StructType: padSuiType(UPGRADE_CAP_TYPE) },
options: { options: {
showContent: true, showContent: true,
}, },
@ -356,7 +357,8 @@ export const getUpgradeCapObjectId = async (
(o) => (o) =>
o.data?.objectId && o.data?.objectId &&
o.data?.content?.dataType === "moveObject" && o.data?.content?.dataType === "moveObject" &&
o.data?.content?.fields?.package === packageId normalizeSuiAddress(o.data?.content?.fields?.package) ===
normalizeSuiAddress(packageId)
); );
if (objects.length === 1) { if (objects.length === 1) {
// We've found the object we're looking for // We've found the object we're looking for
@ -392,7 +394,7 @@ export const getWrappedCoinType = (coinPackageId: string): string => {
export const isSameType = (a: string, b: string) => { export const isSameType = (a: string, b: string) => {
try { try {
return normalizeSuiType(a) === normalizeSuiType(b); return trimSuiType(a) === trimSuiType(b);
} catch (e) { } catch (e) {
return false; return false;
} }
@ -423,7 +425,13 @@ export const isValidSuiType = (type: string): boolean => {
return isValidSuiAddress(tokens[0]) && !!tokens[1] && !!tokens[2]; return isValidSuiAddress(tokens[0]) && !!tokens[1] && !!tokens[2];
}; };
export const normalizeSuiType = (type: string): string => { /**
* Unlike `trimSuiType`, this method does not modify nested types, it just pads
* the top-level type.
* @param type
* @returns
*/
export const padSuiType = (type: string): string => {
const tokens = type.split("::"); const tokens = type.split("::");
if (tokens.length < 3 || !isValidSuiAddress(tokens[0])) { if (tokens.length < 3 || !isValidSuiAddress(tokens[0])) {
throw new Error(`Invalid Sui type: ${type}`); throw new Error(`Invalid Sui type: ${type}`);
@ -433,8 +441,8 @@ export const normalizeSuiType = (type: string): string => {
}; };
/** /**
* This method removes leading zeroes for types, as we found some getDynamicFieldObject * This method removes leading zeroes for types in order to normalize them
* value types to be stripped of leading zeroes * since some types returned from the RPC have leading zeroes and others don't.
*/ */
export const unnormalizeSuiAddress = (type: string): string => export const trimSuiType = (type: string): string =>
type.replace(/^(0x)(0*)/, "0x"); type.replace(/(0x)(0*)/g, "0x");

View File

@ -424,7 +424,7 @@ describe("Sui SDK tests", () => {
) )
).toBe(true); ).toBe(true);
}); });
test.only("Transfer non-SUI Sui token to Ethereum and back", async () => { test("Transfer non-SUI Sui token to Ethereum and back", async () => {
// Get COIN_8 coin type // Get COIN_8 coin type
const res = await suiProvider.getOwnedObjects({ const res = await suiProvider.getOwnedObjects({
owner: suiAddress, owner: suiAddress,

View File

@ -15,21 +15,21 @@ import { MsgExecuteContract } from "@terra-money/terra.js";
import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js"; import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js";
import { import {
Algodv2, Algodv2,
OnApplicationComplete,
SuggestedParams,
bigIntToBytes, bigIntToBytes,
decodeAddress, decodeAddress,
getApplicationAddress, getApplicationAddress,
makeApplicationCallTxnFromObject, makeApplicationCallTxnFromObject,
makePaymentTxnWithSuggestedParamsFromObject, makePaymentTxnWithSuggestedParamsFromObject,
OnApplicationComplete,
SuggestedParams,
} from "algosdk"; } from "algosdk";
import { Types } from "aptos"; import { Types } from "aptos";
import BN from "bn.js"; import BN from "bn.js";
import { ethers, PayableOverrides } from "ethers"; import { PayableOverrides, ethers } from "ethers";
import { FunctionCallOptions } from "near-api-js/lib/account"; import { FunctionCallOptions } from "near-api-js/lib/account";
import { Provider } from "near-api-js/lib/providers"; import { Provider } from "near-api-js/lib/providers";
import { getIsWrappedAssetNear } from "."; import { getIsWrappedAssetNear } from ".";
import { getMessageFee, optin, TransactionSignerPair } from "../algorand"; import { TransactionSignerPair, getMessageFee, optin } from "../algorand";
import { attestToken as attestTokenAptos } from "../aptos"; import { attestToken as attestTokenAptos } from "../aptos";
import { isNativeDenomXpla } from "../cosmwasm"; import { isNativeDenomXpla } from "../cosmwasm";
import { Bridge__factory } from "../ethers-contracts"; import { Bridge__factory } from "../ethers-contracts";
@ -38,8 +38,8 @@ import { createAttestTokenInstruction } from "../solana/tokenBridge";
import { getPackageId } from "../sui/utils"; import { getPackageId } from "../sui/utils";
import { isNativeDenom } from "../terra"; import { isNativeDenom } from "../terra";
import { import {
callFunctionNear,
ChainId, ChainId,
callFunctionNear,
hashAccount, hashAccount,
textToHexString, textToHexString,
textToUint8Array, textToUint8Array,
@ -324,14 +324,11 @@ export async function attestFromSui(
if (metadata === null || metadata.id === null) { if (metadata === null || metadata.id === null) {
throw new Error(`Coin metadata ID for type ${coinType} not found`); throw new Error(`Coin metadata ID for type ${coinType} not found`);
} }
const coreBridgePackageId = await getPackageId(
provider, const [coreBridgePackageId, tokenBridgePackageId] = await Promise.all([
coreBridgeStateObjectId getPackageId(provider, coreBridgeStateObjectId),
); getPackageId(provider, tokenBridgeStateObjectId),
const tokenBridgePackageId = await getPackageId( ]);
provider,
tokenBridgeStateObjectId
);
const tx = new TransactionBlock(); const tx = new TransactionBlock();
const [feeCoin] = tx.splitCoins(tx.gas, [tx.pure(feeAmount)]); const [feeCoin] = tx.splitCoins(tx.gas, [tx.pure(feeAmount)]);
const [messageTicket] = tx.moveCall({ const [messageTicket] = tx.moveCall({

View File

@ -15,7 +15,7 @@ import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js";
import { Algodv2 } from "algosdk"; import { Algodv2 } from "algosdk";
import { Types } from "aptos"; import { Types } from "aptos";
import BN from "bn.js"; import BN from "bn.js";
import { ethers, Overrides } from "ethers"; import { Overrides, ethers } from "ethers";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { FunctionCallOptions } from "near-api-js/lib/account"; import { FunctionCallOptions } from "near-api-js/lib/account";
import { Provider } from "near-api-js/lib/providers"; import { Provider } from "near-api-js/lib/providers";
@ -196,20 +196,10 @@ export async function createWrappedOnSui(
wrappedAssetSetupType: string, wrappedAssetSetupType: string,
attestVAA: Uint8Array attestVAA: Uint8Array
): Promise<TransactionBlock> { ): Promise<TransactionBlock> {
// WrappedAssetSetup looks like const [coreBridgePackageId, tokenBridgePackageId] = await Promise.all([
// 0x92d81f28c167d90f84638c654b412fe7fa8e55bdfac7f638bdcf70306289be86::create_wrapped::WrappedAssetSetup<0xa40e0511f7d6531dd2dfac0512c7fd4a874b76f5994985fb17ee04501a2bb050::coin::COIN, 0x4eb7c5bca3759ab3064b46044edb5668c9066be8a543b28b58375f041f876a80::version_control::V__0_1_1> getPackageId(provider, coreBridgeStateObjectId),
getPackageId(provider, tokenBridgeStateObjectId),
// ugh ]);
const versionType = wrappedAssetSetupType.split(", ")[1].replace(">", "");
const coreBridgePackageId = await getPackageId(
provider,
coreBridgeStateObjectId
);
const tokenBridgePackageId = await getPackageId(
provider,
tokenBridgeStateObjectId
);
// Get coin metadata // Get coin metadata
const coinType = getWrappedCoinType(coinPackageId); const coinType = getWrappedCoinType(coinPackageId);
@ -221,6 +211,8 @@ export async function createWrappedOnSui(
); );
} }
// WrappedAssetSetup looks like
// 0x92d81f28c167d90f84638c654b412fe7fa8e55bdfac7f638bdcf70306289be86::create_wrapped::WrappedAssetSetup<0xa40e0511f7d6531dd2dfac0512c7fd4a874b76f5994985fb17ee04501a2bb050::coin::COIN, 0x4eb7c5bca3759ab3064b46044edb5668c9066be8a543b28b58375f041f876a80::version_control::V__0_1_1>
const wrappedAssetSetupObjectId = await getOwnedObjectId( const wrappedAssetSetupObjectId = await getOwnedObjectId(
provider, provider,
signerAddress, signerAddress,
@ -258,6 +250,7 @@ export async function createWrappedOnSui(
}); });
// Construct complete registration payload // Construct complete registration payload
const versionType = wrappedAssetSetupType.split(", ")[1].replace(">", ""); // ugh
tx.moveCall({ tx.moveCall({
target: `${tokenBridgePackageId}::create_wrapped::complete_registration`, target: `${tokenBridgePackageId}::create_wrapped::complete_registration`,
arguments: [ arguments: [

View File

@ -9,12 +9,12 @@ import { ethers } from "ethers";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { Provider } from "near-api-js/lib/providers"; import { Provider } from "near-api-js/lib/providers";
import { redeemOnTerra } from "."; import { redeemOnTerra } from ".";
import { ensureHexPrefix, TERRA_REDEEMED_CHECK_WALLET_ADDRESS } from ".."; import { TERRA_REDEEMED_CHECK_WALLET_ADDRESS, ensureHexPrefix } from "..";
import { import {
BITS_PER_KEY, BITS_PER_KEY,
calcLogicSigAccount,
MAX_BITS, MAX_BITS,
_parseVAAAlgorand, _parseVAAAlgorand,
calcLogicSigAccount,
} from "../algorand"; } from "../algorand";
import { TokenBridgeState } from "../aptos/types"; import { TokenBridgeState } from "../aptos/types";
import { getSignedVAAHash } from "../bridge"; import { getSignedVAAHash } from "../bridge";
@ -23,7 +23,7 @@ import { getClaim } from "../solana/wormhole";
import { getObjectFields, getTableKeyType } from "../sui/utils"; import { getObjectFields, getTableKeyType } from "../sui/utils";
import { safeBigIntToNumber } from "../utils/bigint"; import { safeBigIntToNumber } from "../utils/bigint";
import { callFunctionNear } from "../utils/near"; import { callFunctionNear } from "../utils/near";
import { parseVaa, SignedVaa } from "../vaa/wormhole"; import { SignedVaa, parseVaa } from "../vaa/wormhole";
export async function getIsTransferCompletedEth( export async function getIsTransferCompletedEth(
tokenBridgeAddress: string, tokenBridgeAddress: string,
@ -280,15 +280,18 @@ export async function getIsTransferCompletedSui(
if (!tokenBridgeStateFields) { if (!tokenBridgeStateFields) {
throw new Error("Unable to fetch object fields from token bridge state"); throw new Error("Unable to fetch object fields from token bridge state");
} }
const hashes = tokenBridgeStateFields.consumed_vaas?.fields?.hashes; const hashes = tokenBridgeStateFields.consumed_vaas?.fields?.hashes;
const tableObjectId = hashes?.fields?.items?.fields?.id?.id; const tableObjectId = hashes?.fields?.items?.fields?.id?.id;
if (!tableObjectId) { if (!tableObjectId) {
throw new Error("Unable to fetch consumed VAAs table"); throw new Error("Unable to fetch consumed VAAs table");
} }
const keyType = getTableKeyType(hashes?.fields?.items?.type); const keyType = getTableKeyType(hashes?.fields?.items?.type);
if (!keyType) { if (!keyType) {
throw new Error("Unable to get key type"); throw new Error("Unable to get key type");
} }
const hash = getSignedVAAHash(transferVAA); const hash = getSignedVAAHash(transferVAA);
const response = await provider.getDynamicFieldObject({ const response = await provider.getDynamicFieldObject({
parentId: tableObjectId, parentId: tableObjectId,
@ -302,9 +305,11 @@ export async function getIsTransferCompletedSui(
if (!response.error) { if (!response.error) {
return true; return true;
} }
if (response.error.code === "dynamicFieldNotFound") { if (response.error.code === "dynamicFieldNotFound") {
return false; return false;
} }
throw new Error( throw new Error(
`Unexpected getDynamicFieldObject response ${response.error}` `Unexpected getDynamicFieldObject response ${response.error}`
); );

View File

@ -120,11 +120,12 @@ export async function getIsWrappedAssetSui(
tokenBridgeStateObjectId: string, tokenBridgeStateObjectId: string,
type: string type: string
): Promise<boolean> { ): Promise<boolean> {
// // An easy way to determine if given asset isn't a wrapped asset is to ensure // An easy way to determine if given asset isn't a wrapped asset is to ensure
// // module name and struct name are coin and COIN respectively. // module name and struct name are coin and COIN respectively.
// if (!type.endsWith("::coin::COIN")) { if (!type.endsWith("::coin::COIN")) {
// return false; return false;
// } }
const response = await getTokenFromTokenRegistry( const response = await getTokenFromTokenRegistry(
provider, provider,
tokenBridgeStateObjectId, tokenBridgeStateObjectId,
@ -133,9 +134,11 @@ export async function getIsWrappedAssetSui(
if (!response.error) { if (!response.error) {
return response.data?.type?.includes("WrappedAsset") || false; return response.data?.type?.includes("WrappedAsset") || false;
} }
if (response.error.code === "dynamicFieldNotFound") { if (response.error.code === "dynamicFieldNotFound") {
return false; return false;
} }
throw new Error( throw new Error(
`Unexpected getDynamicFieldObject response ${response.error}` `Unexpected getDynamicFieldObject response ${response.error}`
); );

View File

@ -23,24 +23,24 @@ import {
getFieldsFromObjectResponse, getFieldsFromObjectResponse,
getTokenFromTokenRegistry, getTokenFromTokenRegistry,
isValidSuiType, isValidSuiType,
unnormalizeSuiAddress, trimSuiType,
} from "../sui"; } from "../sui";
import { buildNativeId } from "../terra"; import { buildNativeId } from "../terra";
import { import {
assertChain,
callFunctionNear,
ChainId,
ChainName,
CHAIN_ID_ALGORAND, CHAIN_ID_ALGORAND,
CHAIN_ID_APTOS, CHAIN_ID_APTOS,
CHAIN_ID_NEAR, CHAIN_ID_NEAR,
CHAIN_ID_SOLANA, CHAIN_ID_SOLANA,
CHAIN_ID_SUI, CHAIN_ID_SUI,
CHAIN_ID_TERRA, CHAIN_ID_TERRA,
coalesceChainId, ChainId,
coalesceCosmWasmChainId, ChainName,
CosmWasmChainId, CosmWasmChainId,
CosmWasmChainName, CosmWasmChainName,
assertChain,
callFunctionNear,
coalesceChainId,
coalesceCosmWasmChainId,
hexToUint8Array, hexToUint8Array,
isValidAptosType, isValidAptosType,
} from "../utils"; } from "../utils";
@ -347,12 +347,14 @@ export async function getOriginalAssetSui(
); );
} }
if ( // Normalize types
fields.value.type.includes(`wrapped_asset::WrappedAsset<${coinType}>`) || const type = trimSuiType(fields.value.type);
fields.value.type.includes( coinType = trimSuiType(coinType);
`wrapped_asset::WrappedAsset<${unnormalizeSuiAddress(coinType)}>`
) // Check if wrapped or native asset. We check inclusion instead of equality
) { // because it saves us from making an additional RPC call to fetch the
// package ID.
if (type.includes(`wrapped_asset::WrappedAsset<${coinType}>`)) {
return { return {
isWrapped: true, isWrapped: true,
chainId: Number(fields.value.fields.info.fields.token_chain) as ChainId, chainId: Number(fields.value.fields.info.fields.token_chain) as ChainId,
@ -360,12 +362,7 @@ export async function getOriginalAssetSui(
fields.value.fields.info.fields.token_address.fields.value.fields.data fields.value.fields.info.fields.token_address.fields.value.fields.data
), ),
}; };
} else if ( } else if (type.includes(`native_asset::NativeAsset<${coinType}>`)) {
fields.value.type.includes(`native_asset::NativeAsset<${coinType}>`) ||
fields.value.type.includes(
`native_asset::NativeAsset<${unnormalizeSuiAddress(coinType)}>`
)
) {
return { return {
isWrapped: false, isWrapped: false,
chainId: CHAIN_ID_SUI, chainId: CHAIN_ID_SUI,

View File

@ -379,14 +379,11 @@ export async function redeemOnSui(
if (!coinType) { if (!coinType) {
throw new Error("Unable to fetch token coinType"); throw new Error("Unable to fetch token coinType");
} }
const coreBridgePackageId = await getPackageId(
provider, const [coreBridgePackageId, tokenBridgePackageId] = await Promise.all([
coreBridgeStateObjectId getPackageId(provider, coreBridgeStateObjectId),
); getPackageId(provider, tokenBridgeStateObjectId),
const tokenBridgePackageId = await getPackageId( ]);
provider,
tokenBridgeStateObjectId
);
const tx = new TransactionBlock(); const tx = new TransactionBlock();
const [verifiedVAA] = tx.moveCall({ const [verifiedVAA] = tx.moveCall({
target: `${coreBridgePackageId}::vaa::parse_and_verify`, target: `${coreBridgePackageId}::vaa::parse_and_verify`,

View File

@ -6,11 +6,11 @@ import {
} from "@mysten/sui.js"; } from "@mysten/sui.js";
import { import {
ACCOUNT_SIZE, ACCOUNT_SIZE,
NATIVE_MINT,
TOKEN_PROGRAM_ID,
createCloseAccountInstruction, createCloseAccountInstruction,
createInitializeAccountInstruction, createInitializeAccountInstruction,
getMinimumBalanceForRentExemptAccount, getMinimumBalanceForRentExemptAccount,
NATIVE_MINT,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token"; } from "@solana/spl-token";
import { import {
Commitment, Commitment,
@ -18,33 +18,33 @@ import {
Keypair, Keypair,
PublicKey, PublicKey,
PublicKeyInitData, PublicKeyInitData,
SystemProgram,
Transaction as SolanaTransaction, Transaction as SolanaTransaction,
SystemProgram,
} from "@solana/web3.js"; } from "@solana/web3.js";
import { MsgExecuteContract } from "@terra-money/terra.js"; import { MsgExecuteContract } from "@terra-money/terra.js";
import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js"; import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js";
import { import {
Algodv2, Algodv2,
Transaction as AlgorandTransaction,
OnApplicationComplete,
SuggestedParams,
bigIntToBytes, bigIntToBytes,
getApplicationAddress, getApplicationAddress,
makeApplicationCallTxnFromObject, makeApplicationCallTxnFromObject,
makeAssetTransferTxnWithSuggestedParamsFromObject, makeAssetTransferTxnWithSuggestedParamsFromObject,
makePaymentTxnWithSuggestedParamsFromObject, makePaymentTxnWithSuggestedParamsFromObject,
OnApplicationComplete,
SuggestedParams,
Transaction as AlgorandTransaction,
} from "algosdk"; } from "algosdk";
import { Types } from "aptos"; import { Types } from "aptos";
import BN from "bn.js"; import BN from "bn.js";
import { ethers, Overrides, PayableOverrides } from "ethers"; import { Overrides, PayableOverrides, ethers } from "ethers";
import { FunctionCallOptions } from "near-api-js/lib/account"; import { FunctionCallOptions } from "near-api-js/lib/account";
import { Provider } from "near-api-js/lib/providers"; import { Provider } from "near-api-js/lib/providers";
import { getIsWrappedAssetNear } from ".."; import { getIsWrappedAssetNear } from "..";
import { import {
TransactionSignerPair,
assetOptinCheck, assetOptinCheck,
getMessageFee, getMessageFee,
optin, optin,
TransactionSignerPair,
} from "../algorand"; } from "../algorand";
import { import {
transferTokens as transferTokensAptos, transferTokens as transferTokensAptos,
@ -67,10 +67,10 @@ import { getPackageId, isSameType } from "../sui";
import { SuiCoinObject } from "../sui/types"; import { SuiCoinObject } from "../sui/types";
import { isNativeDenom } from "../terra"; import { isNativeDenom } from "../terra";
import { import {
callFunctionNear, CHAIN_ID_SOLANA,
ChainId, ChainId,
ChainName, ChainName,
CHAIN_ID_SOLANA, callFunctionNear,
coalesceChainId, coalesceChainId,
createNonce, createNonce,
hexToUint8Array, hexToUint8Array,
@ -938,6 +938,7 @@ export async function transferFromSui(
if (payload !== null) { if (payload !== null) {
throw new Error("Sui transfer with payload not implemented"); throw new Error("Sui transfer with payload not implemented");
} }
const [primaryCoin, ...mergeCoins] = coins.filter((coin) => const [primaryCoin, ...mergeCoins] = coins.filter((coin) =>
isSameType(coin.coinType, coinType) isSameType(coin.coinType, coinType)
); );
@ -946,14 +947,11 @@ export async function transferFromSui(
`Coins array doesn't contain any coins of type ${coinType}` `Coins array doesn't contain any coins of type ${coinType}`
); );
} }
const coreBridgePackageId = await getPackageId(
provider, const [coreBridgePackageId, tokenBridgePackageId] = await Promise.all([
coreBridgeStateObjectId getPackageId(provider, coreBridgeStateObjectId),
); getPackageId(provider, tokenBridgeStateObjectId),
const tokenBridgePackageId = await getPackageId( ]);
provider,
tokenBridgeStateObjectId
);
const tx = new TransactionBlock(); const tx = new TransactionBlock();
const [transferCoin] = (() => { const [transferCoin] = (() => {
if (coinType === SUI_TYPE_ARG) { if (coinType === SUI_TYPE_ARG) {
@ -966,6 +964,7 @@ export async function transferFromSui(
mergeCoins.map((coin) => tx.object(coin.coinObjectId)) mergeCoins.map((coin) => tx.object(coin.coinObjectId))
); );
} }
return tx.splitCoins(primaryCoinInput, [tx.pure(amount)]); return tx.splitCoins(primaryCoinInput, [tx.pure(amount)]);
} }
})(); })();

View File

@ -3,7 +3,7 @@ import {
SUI_CLOCK_OBJECT_ID, SUI_CLOCK_OBJECT_ID,
TransactionBlock, TransactionBlock,
} from "@mysten/sui.js"; } from "@mysten/sui.js";
import { ethers, Overrides } from "ethers"; import { Overrides, ethers } from "ethers";
import { import {
createWrappedOnAlgorand, createWrappedOnAlgorand,
createWrappedOnAptos, createWrappedOnAptos,
@ -46,14 +46,10 @@ export async function updateWrappedOnSui(
coinPackageId: string, coinPackageId: string,
attestVAA: Uint8Array attestVAA: Uint8Array
): Promise<TransactionBlock> { ): Promise<TransactionBlock> {
const coreBridgePackageId = await getPackageId( const [coreBridgePackageId, tokenBridgePackageId] = await Promise.all([
provider, getPackageId(provider, coreBridgeStateObjectId),
coreBridgeStateObjectId getPackageId(provider, tokenBridgeStateObjectId),
); ]);
const tokenBridgePackageId = await getPackageId(
provider,
tokenBridgeStateObjectId
);
// Get coin metadata // Get coin metadata
const coinType = getWrappedCoinType(coinPackageId); const coinType = getWrappedCoinType(coinPackageId);