sdk/js: normalize all sui addresses and types being compared
This commit is contained in:
parent
2402e2fbcf
commit
7608b2b740
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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");
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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: [
|
||||||
|
|
|
@ -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}`
|
||||||
);
|
);
|
||||||
|
|
|
@ -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}`
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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`,
|
||||||
|
|
|
@ -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)]);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue