UNPKG

@dontuseit/swap-sdk

Version:
1,840 lines (1,833 loc) 414 kB
// src/api.ts import fetch2 from "cross-fetch"; // src/addresses.ts var addresses_default = { "MAYAN_FORWARDER_CONTRACT": "0x337685fdaB40D39bd02028545a4FfA7D287cC3E2", "MAYAN_PROGRAM_ID": "FC4eXxkyrMPTjiYUpp4EAnkmwMbQyZ6NDCh1kfLn6vsf", "AUCTION_PROGRAM_ID": "8QJmxZcEzwuYmCPy6XqgN2sHcYCcFq6AEfBMJZZuLo5a", "MCTP_PROGRAM_ID": "dkpZqrxHFrhziEMQ931GLtfy11nFkCsfMftH9u6QwBU", "FAST_MCTP_PROGRAM_ID": "Gx9rivpS3YR8pBFwMuP6omYqVxunpLvLkNn7ubNyuZZ5", "SWIFT_PROGRAM_ID": "BLZRi6frs4X4DNLw56V4EXai1b6QVESN1BhHBTYM9VcY", "SWIFT_V2_PROGRAM_ID": "mayan34VedncxdK2XobtvWFDXQASUTBXhUVzt2kKgny", "FEE_MANAGER_PROGRAM_ID": "5VtQHnhs2pfVEr68qQsbTRwKh4JV5GTu9mBHgHFxpHeQ", "WORMHOLE_PROGRAM_ID": "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth", "WORMHOLE_PROGRAM_ID_FOGO": "worm2mrQkG1B1KTz37erMfWN8anHkSK24nzca7UD8BB", "WORMHOLE_SHIM_POST_MESSAGE_PROGRAM_ID": "EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX", "CCTP_CORE_PROGRAM_ID": "CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd", "CCTPV2_CORE_PROGRAM_ID": "CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC", "CCTP_TOKEN_PROGRAM_ID": "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3", "CCTPV2_TOKEN_PROGRAM_ID": "CCTPV2vPZJS2u2BBsUoscuikbYjnpFmbFsvVuJdgUMQe", "TOKEN_PROGRAM_ID": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "TOKEN_2022_PROGRAM_ID": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", "ASSOCIATED_TOKEN_PROGRAM_ID": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "SPL_UTILS_PROGRAM_ID": "B96dV3Luxzo6SokJx3xt8i5y8Mb7HRR6Eec8hCjJDT69", "LOOKUP_TABLE_SOLANA": "Ff3yi1meWQQ19VPZMzGg6H8JQQeRudiV7QtVtyzJyoht", "LOOKUP_TABLE_FOGO": "ZnLmtY5qckPcBQfdD4uKh9GtiQTrzQfQXEX86U3aLq7", "SUI_MCTP_STATE": "0xb787fe0f7530b4fd2162fa0cc92f4f6c5a97c54b4c5c55eb04ab29f4b803ac9c", "SUI_MCTP_FEE_MANAGER_STATE": "0xa1b4a96ce93d36dd0bbce0adc39533a07d2f32928918c80cd6fe7868320978f2", "SUI_SWIFT_STATE": "0x7ac01a7c14c53098a41593c7623823bb677b5201fb3ee35b75b47cfc6c6c6f40", "SUI_SWIFT_FEE_MANAGER_STATE": "0xe42174b6d742f40bd2b67b967542b21e6d7433f2d277a80bb59866ac73ff3f52", "SUI_CCTP_CORE_PACKAGE_ID": "0x08d87d37ba49e785dde270a83f8e979605b03dc552b5548f26fdf2f49bf7ed1b", "SUI_CCTP_CORE_STATE": "0xf68268c3d9b1df3215f2439400c1c4ea08ac4ef4bb7d6f3ca6a2a239e17510af", "SUI_CCTP_TOKEN_PACKAGE_ID": "0x2aa6c5d56376c371f88a6cc42e852824994993cb9bab8d3e6450cbe3cb32b94e", "SUI_CCTP_TOKEN_STATE": "0x45993eecc0382f37419864992c12faee2238f5cfe22b98ad3bf455baf65c8a2f", "SUI_WORMHOLE_PACKAGE_ID": "0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a", "SUI_WORMHOLE_STATE": "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c", "SUI_LOGGER_PACKAGE_ID": "0x05680e9030c147b413a489f7891273acc221d49bd061c433e5771bc170fc37ac", "EXPLORER_URL": "https://explorer-api.mayan.finance/v3", "PRICE_URL": "https://price-api.mayan.finance/v3", "RELAYER_URL": "https://relayer-api.mayan.finance/v3", "SWIFT_RELAYER_URL": "https://swift-relayer-api.mayan.finance/v3", "GAS_ESTIMATE_URL": "https://gas-estimate.mayan.finance/v2", "HC_ARBITRUM_BRIDGE": "0x2df1c51e09aecf9cacb7bc98cb1742757f163df7", "HC_ARBITRUM_DEPOSIT_PROCESSOR": "0xdDd77e62C848C3334f1148d4F1457FC59ede4E4B", "ARBITRUM_USDC_CONTRACT": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", "PAYLOAD_WRITER_PROGRAM_ID": "DwMLtdtJqJQkHzNcrdTBuWHJByJfgpKBnvFvzyKdy3cU", "CPI_PROXY_PROGRAM_ID": "D8C8iW6zmoKg5TRr8nQ7h14TMWqQX8FiBdj2ju5MF3wa" }; // src/utils.ts import { ethers, zeroPadValue, parseUnits, formatUnits, TypedDataEncoder, ZeroAddress } from "ethers"; import { Keypair, PublicKey, SystemProgram } from "@solana/web3.js"; import { Buffer } from "buffer"; // src/evm/ERC20Artifact.ts var ERC20Artifact_default = { "_format": "hh-sol-artifact-1", "contractName": "ERC20Permit", "sourceName": "contracts/token/ERC20/extensions/ERC20Permit.sol", "abi": [ { "inputs": [], "name": "ECDSAInvalidSignature", "type": "error" }, { "inputs": [ { "internalType": "uint256", "name": "length", "type": "uint256" } ], "name": "ECDSAInvalidSignatureLength", "type": "error" }, { "inputs": [ { "internalType": "bytes32", "name": "s", "type": "bytes32" } ], "name": "ECDSAInvalidSignatureS", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "allowance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" } ], "name": "ERC20InsufficientAllowance", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "uint256", "name": "balance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" } ], "name": "ERC20InsufficientBalance", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "approver", "type": "address" } ], "name": "ERC20InvalidApprover", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "receiver", "type": "address" } ], "name": "ERC20InvalidReceiver", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" } ], "name": "ERC20InvalidSender", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" } ], "name": "ERC20InvalidSpender", "type": "error" }, { "inputs": [ { "internalType": "uint256", "name": "deadline", "type": "uint256" } ], "name": "ERC2612ExpiredSignature", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "signer", "type": "address" }, { "internalType": "address", "name": "owner", "type": "address" } ], "name": "ERC2612InvalidSigner", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "currentNonce", "type": "uint256" } ], "name": "InvalidAccountNonce", "type": "error" }, { "inputs": [], "name": "InvalidShortString", "type": "error" }, { "inputs": [ { "internalType": "string", "name": "str", "type": "string" } ], "name": "StringTooLong", "type": "error" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [], "name": "EIP712DomainChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "inputs": [], "name": "DOMAIN_SEPARATOR", "outputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "approve", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [ { "internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "eip712Domain", "outputs": [ { "internalType": "bytes1", "name": "fields", "type": "bytes1" }, { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "string", "name": "version", "type": "string" }, { "internalType": "uint256", "name": "chainId", "type": "uint256" }, { "internalType": "address", "name": "verifyingContract", "type": "address" }, { "internalType": "bytes32", "name": "salt", "type": "bytes32" }, { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" } ], "name": "nonces", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "uint256", "name": "deadline", "type": "uint256" }, { "internalType": "uint8", "name": "v", "type": "uint8" }, { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" } ], "name": "permit", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" } ], "bytecode": "0x", "deployedBytecode": "0x", "linkReferences": {}, "deployedLinkReferences": {} }; // src/utils.ts import * as sha3 from "js-sha3"; var sha3_2562 = sha3.sha3_256; var isValidAptosType = (str) => /^(0x)?[0-9a-fA-F]+::\w+::\w+$/.test(str); function nativeAddressToHexString(address, wChainId) { if (wChainId === chains.solana || wChainId === chains.fogo) { return zeroPadValue(new PublicKey(address).toBytes(), 32); } else if (wChainId === chains.ethereum || wChainId === chains.bsc || wChainId === chains.polygon || wChainId === chains.avalanche || wChainId === chains.arbitrum || wChainId === chains.optimism || wChainId === chains.base || wChainId === chains.unichain || wChainId === chains.linea || wChainId === chains.sonic || wChainId === chains.hyperevm || wChainId === chains.monad) { return zeroPadValue(address, 32); } else if (wChainId === chains.aptos && isValidAptosType(address)) { return `0x${sha3_2562(address)}`; } else if (wChainId === chains.sui || wChainId === chains.ton) { let addressStr = address.startsWith("0x") ? address.substring(2) : address; if (Buffer.from(addressStr, "hex").length !== 32) { throw new Error(`Invalid address: ` + address); } return zeroPadValue(address, 32); } else { console.log(`Unsupported chain id: ${wChainId}`, address); throw new Error("Unsupported token chain"); } } function hexToUint8Array(input) { return new Uint8Array( Buffer.from( input.startsWith("0x") ? input.substring(2) : input, "hex" ) ); } function getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve = false, programId = new PublicKey(addresses_default.TOKEN_PROGRAM_ID), associatedTokenProgramId = new PublicKey(addresses_default.ASSOCIATED_TOKEN_PROGRAM_ID)) { if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) { throw new Error("TokenOwnerOffCurveError"); } const [address] = PublicKey.findProgramAddressSync( [owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], associatedTokenProgramId ); return address; } function isValidNumericInput(value) { return (typeof value === "string" || typeof value === "number") && value !== "" && value !== null && !isNaN(Number(value)) && Number.isFinite(Number(value)); } function getAmountOfFractionalAmount(amount, decimals) { if (amount === null || amount === void 0) { throw new Error("getAmountOfFractionalAmount: Amount is null or undefined"); } if (typeof amount !== "string" && typeof amount !== "number") { throw new Error("getAmountOfFractionalAmount: Amount is not a string or number"); } if (typeof amount === "string" && amount.length === 0) { throw new Error("getAmountOfFractionalAmount: Amount is empty"); } if (!Number.isFinite(Number(amount))) { throw new Error("getAmountOfFractionalAmount: Amount is not a number"); } if (!isValidNumericInput(decimals)) { throw new Error("getAmountOfFractionalAmount: decimals is not a number"); } const cutFactor = Math.min(8, Number(decimals)); const numStr = Number(amount).toFixed(cutFactor + 1); const reg = new RegExp(`^-?\\d+(?:\\.\\d{0,${cutFactor}})?`); const matchResult = numStr.match(reg); if (!matchResult) { throw new Error("getAmountOfFractionalAmount: fixedAmount is null"); } const fixedAmount = matchResult[0]; return parseUnits(fixedAmount, Number(decimals)); } function getDisplayAmount(inputAmount, decimals) { return Number(formatUnits(inputAmount, decimals)); } var chains = { solana: 1, ethereum: 2, bsc: 4, polygon: 5, avalanche: 6, arbitrum: 23, optimism: 24, base: 30, aptos: 22, sui: 21, ton: 13, unichain: 44, linea: 38, hypercore: 65e3, sonic: 52, hyperevm: 47, fogo: 51, monad: 48 }; function getWormholeChainIdByName(chain) { const result = chains[chain]; if (!result) { throw new Error(`Chain Id not found for chain: ${chain}`); } return result; } var evmChainIdMap = { [1]: 2, [56]: 4, [137]: 5, [43114]: 6, [42161]: 23, [10]: 24, [8453]: 30, [130]: 44, [59144]: 38, [146]: 52, [999]: 47, [143]: 48 }; function getEvmChainIdByName(chain) { const wormholeChainId = chains[chain]; const evmIds = Object.keys(evmChainIdMap); for (const evmId of evmIds) { if (evmChainIdMap[evmId] === wormholeChainId) { return Number(evmId); } } throw new Error(`Unsupported chain: ${chain}`); } function getWormholeChainIdById(chainId) { return evmChainIdMap[chainId]; } var sdkVersion = [13, 0, 0]; function getSdkVersion() { return sdkVersion.join("_"); } function checkSdkVersionSupport(minimumVersion) { if (sdkVersion[0] < minimumVersion[0]) { return false; } if (sdkVersion[0] > minimumVersion[0]) { return true; } if (sdkVersion[1] < minimumVersion[1]) { return false; } if (sdkVersion[1] > minimumVersion[1]) { return true; } if (sdkVersion[2] >= minimumVersion[2]) { return true; } return false; } function getGasDecimal(chain) { if (chain === "solana" || chain === "sui" || chain === "ton") { return 9; } return 18; } function getGasDecimalsInSolana(chain) { if (chain === "solana") { return 9; } return 8; } var MAX_U64 = BigInt(2) ** BigInt(64) - BigInt(1); function getSafeU64Blob(value) { if (value < BigInt(0) || value > MAX_U64) { throw new Error(`Invalid u64: ${value}`); } const buf = Buffer.alloc(8); buf.writeBigUInt64LE(value); return buf; } var ZeroPermit = { value: BigInt(0), deadline: 0, v: 0, r: `0x${SystemProgram.programId.toBuffer().toString("hex")}`, s: `0x${SystemProgram.programId.toBuffer().toString("hex")}` }; function wait(time) { return new Promise((resolve) => { setTimeout(() => { resolve(); }, time); }); } function getQuoteSuitableReferrerAddress(quote, referrerAddresses) { if (!quote || !referrerAddresses) { return null; } if (quote.type === "WH") { return referrerAddresses?.solana || null; } if (quote.type === "MCTP") { if (quote.toChain === "solana") { return referrerAddresses?.solana || null; } if (quote.toChain === "sui") { return referrerAddresses?.sui || null; } return referrerAddresses?.evm || null; } if (quote.type === "SWIFT") { if (quote.swiftVersion === "V2") { if (quote.fromChain === "solana" || quote.fromChain === "fogo") { return referrerAddresses?.solana || null; } if (quote.fromChain === "sui") { return referrerAddresses?.sui || null; } return referrerAddresses?.evm || null; } else { if (quote.toChain === "solana") { return referrerAddresses?.solana || null; } if (quote.toChain === "sui") { throw new Error("Swift V1 does not support SUI"); } return referrerAddresses?.evm || null; } } if (quote.type === "FAST_MCTP") { if (quote.toChain === "solana") { return referrerAddresses?.solana || null; } if (quote.toChain !== "sui") { return referrerAddresses?.evm || null; } } if (quote.type === "MONO_CHAIN") { if (quote.fromChain === "solana") { return referrerAddresses?.solana || null; } else if (quote.fromChain === "sui") { return referrerAddresses?.sui || null; } return referrerAddresses?.evm || null; } return null; } var MCTP_PAYLOAD_TYPE_DEFAULT = 1; var MCTP_PAYLOAD_TYPE_CUSTOM_PAYLOAD = 2; var MCTP_INIT_ORDER_PAYLOAD_ID = 1; var FAST_MCTP_PAYLOAD_TYPE_DEFAULT = 1; var FAST_MCTP_PAYLOAD_TYPE_CUSTOM_PAYLOAD = 2; var FAST_MCTP_PAYLOAD_TYPE_ORDER = 3; var SWIFT_PAYLOAD_TYPE_DEFAULT = 1; var SWIFT_PAYLOAD_TYPE_CUSTOM_PAYLOAD = 2; async function getPermitDomain(token, provider) { const contract = new ethers.Contract( token.contract, ERC20Artifact_default.abi, provider ); let domainSeparator; let name; try { let [_domainSeparator, _name] = await Promise.all([ contract.DOMAIN_SEPARATOR(), contract.name() ]); domainSeparator = _domainSeparator; name = _name; } catch (err) { throw { mayanError: { permitIssue: true } }; } const domain = { name, version: "1", chainId: token.chainId, verifyingContract: token.contract }; for (let i = 1; i < 11; i++) { domain.version = String(i); const hash = TypedDataEncoder.hashDomain(domain); if (hash.toLowerCase() === domainSeparator.toLowerCase()) { return domain; } } const salt = ethers.zeroPadValue(ethers.toBeHex(token.chainId), 32); const LEGACY_DOMAIN_TYPEHASH = ethers.keccak256( ethers.toUtf8Bytes( "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)" ) ); if (token.realOriginChainId && token.realOriginContractAddress && token.wChainId !== token.realOriginChainId) { const whChainId2Bytes = new Uint8Array(2); whChainId2Bytes[0] = token.realOriginChainId >> 8 & 255; whChainId2Bytes[1] = token.realOriginChainId & 255; const packed = new Uint8Array(2 + 32); packed.set(whChainId2Bytes, 0); packed.set( ethers.getBytes(ethers.zeroPadValue(token.realOriginContractAddress, 32)), 2 ); const salt2 = ethers.keccak256(packed); const DOMAIN_TYPEHASH = ethers.keccak256( ethers.toUtf8Bytes( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)" ) ); for (let i = 0; i < 11; i++) { const hash = ethers.keccak256( new ethers.AbiCoder().encode( ["bytes32", "bytes32", "bytes32", "uint256", "address", "bytes32"], [ DOMAIN_TYPEHASH, ethers.keccak256(ethers.toUtf8Bytes(name)), ethers.keccak256(ethers.toUtf8Bytes(String(i))), token.chainId, token.contract, salt2 ] ) ); if (hash.toLowerCase() === domainSeparator.toLowerCase()) { domain.version = String(i); domain.salt = salt2; return domain; } } } for (let i = 0; i < 11; i++) { const hash = ethers.keccak256( new ethers.AbiCoder().encode( ["bytes32", "bytes32", "bytes32", "address", "bytes32"], [ LEGACY_DOMAIN_TYPEHASH, ethers.keccak256(ethers.toUtf8Bytes(name)), ethers.keccak256(ethers.toUtf8Bytes(String(i))), token.contract, salt ] ) ); if (hash.toLowerCase() === domainSeparator.toLowerCase()) { delete domain.chainId; domain.version = String(i); domain.salt = salt; return domain; } } throw { mayanError: { permitIssue: true } }; } var PermitTypes = { Permit: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" } ] }; async function getPermitParams(token, walletAddress, spender, amount, provider, deadline) { if (token.standard !== "erc20" && token.standard !== "hypertoken") { throw new Error("Token is not ERC20"); } if (!token.supportsPermit) { throw new Error("Token does not support permit"); } const contract = new ethers.Contract(token.contract, ERC20Artifact_default.abi, provider); const [domain, nonce] = await Promise.all([getPermitDomain(token, provider), contract.nonces(walletAddress)]); return { domain, types: PermitTypes, value: { owner: walletAddress, spender, nonce: String(nonce), value: String(amount), deadline: String(deadline) } }; } async function getHyperCoreUSDCDepositPermitParams(quote, userArbitrumAddress, arbProvider) { if (!quote.hyperCoreParams) { throw new Error("Quote does not have hyperCoreParams"); } if (quote.toChain !== "hypercore") { throw new Error("Quote toChain is not hypercore"); } if (quote.toToken.contract.toLowerCase() !== addresses_default.ARBITRUM_USDC_CONTRACT.toLowerCase()) { throw new Error("Quote toToken is not USDC on Arbitrum"); } const USDC_ARB_TOKEN = { name: "USDC", standard: "erc20", symbol: "USDC", mint: "CR4xnGrhsu1fWNPoX4KbTUUtqGMF3mzRLfj4S6YEs1Yo", verified: true, contract: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", chainId: 42161, wChainId: 23, decimals: 6, logoURI: "http://assets.coingecko.com/coins/images/6319/small/usdc.png?1696506694", coingeckoId: "usd-coin", realOriginContractAddress: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", realOriginChainId: 23, supportsPermit: true, verifiedAddress: "0xaf88d065e77c8cc2239327c5edb3a432268e5831" }; const [permitParams, isAllowed] = await Promise.all([ getPermitParams( USDC_ARB_TOKEN, userArbitrumAddress, addresses_default.HC_ARBITRUM_BRIDGE, BigInt(quote.hyperCoreParams.depositAmountUSDC64), arbProvider, BigInt(quote.deadline64) ), checkHyperCoreDeposit(userArbitrumAddress, quote.toToken.contract) ]); if (!isAllowed) { throw new Error("Because of concurrency, deposit is not possible at the moment, please try again later"); } return permitParams; } function getHyperCoreUSDCDepositCustomPayload(quote, destinationAddress, usdcPermitSignature) { const payload = Buffer.alloc(109); const destAddressBuf = Buffer.from(hexToUint8Array(destinationAddress)); if (destAddressBuf.length !== 20) { throw new Error("Invalid destination address length, expected 20 bytes"); } const permitSignatureBuf = Buffer.from( hexToUint8Array(usdcPermitSignature) ); if (permitSignatureBuf.length !== 65) { throw new Error("Invalid USDC permit signature length, expected 65 bytes"); } if (!quote.redeemRelayerFee64 || !quote.hyperCoreParams) { throw new Error("Invalid quote for HyperCore USDC deposit custom payload"); } payload.writeBigUInt64BE(BigInt(quote.redeemRelayerFee64), 0); payload.set(destAddressBuf, 8); payload.writeBigUInt64BE(BigInt(quote.hyperCoreParams.depositAmountUSDC64), 28); payload.writeBigUInt64BE(BigInt(quote.deadline64), 36); payload.set(permitSignatureBuf, 44); return payload; } function getSwiftToTokenHexString(quote) { if (quote.toChain === "sui") { if (!quote.toToken.verifiedAddress) { throw new Error("To token verified address is required for SUI"); } return nativeAddressToHexString(quote.toToken.verifiedAddress, getWormholeChainIdByName("sui")); } else if (quote.toChain === "ton") { if (quote.toToken.contract === ZeroAddress) { return nativeAddressToHexString(SystemProgram.programId.toString(), getWormholeChainIdByName("solana")); } else { if (!quote.toToken.verifiedAddress) { throw new Error("To token verified address is required for Ton chain"); } return quote.toToken.verifiedAddress; } } else { if (quote.toToken.contract === ZeroAddress) { return nativeAddressToHexString(SystemProgram.programId.toString(), getWormholeChainIdByName("solana")); } else { return nativeAddressToHexString(quote.toToken.contract, getWormholeChainIdByName(quote.toChain)); } } } function getNormalizeFactor(toChain, quoteType) { if (toChain === "ton") { if (quoteType !== "SWIFT") { throw new Error("Unsupported quote type for Tonchain destination"); } return Infinity; } return 8; } function createSwiftRandomKey(quote) { try { const idBuf = Buffer.from(quote.quoteId.startsWith("0x") ? quote.quoteId.substring(2) : quote.quoteId, "hex"); if (idBuf.length < 32) { const randomBuf = Keypair.generate().publicKey.toBytes(); return Buffer.concat([idBuf, randomBuf.slice(0, 32 - idBuf.length)]); } return idBuf.subarray(0, 32); } catch (err) { } return Keypair.generate().publicKey.toBuffer(); } // src/api.ts function toQueryString(params) { return Object.entries(params).filter(([_, value]) => value !== void 0 && value !== null && !Array.isArray(value)).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&"); } async function check5xxError(res) { if (res.status.toString().startsWith("5")) { let error = new Error("Internal server error"); try { const err = await res.json(); if ((err?.code || err?.statusCode) && (err?.message || err?.msg)) { error = { code: err?.code || err?.statusCode, message: err?.message || err?.msg }; } } catch (err) { error = new Error("Internal server error"); } throw error; } } async function fetchAllTokenList(tokenStandards) { const query = tokenStandards ? `?standard=${tokenStandards.join(",")}` : ""; const res = await fetch2(`${addresses_default.PRICE_URL}/tokens${query}`, { method: "GET", redirect: "follow" }); await check5xxError(res); if (res.status === 200) { const result = await res.json(); return result; } throw new Error("Cannot fetch Mayan tokens!"); } async function fetchTokenList(chain, nonPortal = false, tokenStandards) { const queryParams = { chain, nonPortal, standard: tokenStandards ? tokenStandards?.join(",") : void 0 }; const res = await fetch2(`${addresses_default.PRICE_URL}/tokens?${toQueryString(queryParams)}`); await check5xxError(res); if (res.status === 200) { const result = await res.json(); return result[chain]; } throw new Error("Cannot fetch Mayan tokens!"); } function generateFetchQuoteUrl(params, quoteOptions = { wormhole: true, swift: true, mctp: true, shuttle: true, gasless: false, onlyDirect: false, fastMctp: true, fullList: false, payload: void 0, monoChain: true }) { const { gasDrop, referrerBps } = params; let slippageBps = params.slippageBps; if (slippageBps !== "auto" && !Number.isFinite(slippageBps)) { if (params.slippage === void 0 || params.slippage === null || !Number.isFinite(params.slippage)) { throw new Error("Either slippageBps or slippage must be provided"); } slippageBps = params.slippage * 100; } const _quoteOptions = { wormhole: quoteOptions.wormhole !== false, // default to true swift: quoteOptions.swift !== false, // default to true mctp: quoteOptions.mctp !== false, // default to true shuttle: quoteOptions.shuttle === true, // default to false fastMctp: quoteOptions.fastMctp !== false, // default to true gasless: quoteOptions.gasless === true, // default to false onlyDirect: quoteOptions.onlyDirect === true, // default to false fullList: quoteOptions.fullList === true, // default to false payload: typeof quoteOptions.payload === "string" ? quoteOptions.payload : void 0, monoChain: quoteOptions.monoChain !== false // default to true }; const queryParams = { ..._quoteOptions, solanaProgram: addresses_default.MAYAN_PROGRAM_ID, forwarderAddress: addresses_default.MAYAN_FORWARDER_CONTRACT, amountIn: !params.amountIn64 && Number.isFinite(params.amount) ? params.amount : void 0, amountIn64: params.amountIn64, fromToken: params.fromToken, fromChain: params.fromChain, toToken: params.toToken, toChain: params.toChain, slippageBps, referrer: params.referrer, referrerBps: Number.isFinite(referrerBps) ? referrerBps : void 0, gasDrop: Number.isFinite(gasDrop) ? gasDrop : void 0, destinationAddress: params.destinationAddress ?? void 0, sdkVersion: getSdkVersion() }; const baseUrl = `${addresses_default.PRICE_URL}/quote?`; const queryString = toQueryString(queryParams); return baseUrl + queryString; } async function fetchQuote(params, quoteOptions = { swift: true, mctp: true, gasless: false, onlyDirect: false }) { const url = generateFetchQuoteUrl(params, quoteOptions); const res = await fetch2(url, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw { code: result?.code || 0, message: result?.msg || result?.message || "Route not found", data: result?.data }; } if (!checkSdkVersionSupport(result.minimumSdkVersion)) { throw { code: 9999, message: "Swap SDK is outdated!" }; } return result.quotes; } async function getCurrentChainTime(chain) { const res = await fetch2(`${addresses_default.PRICE_URL}/clock/${chain}`, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result.clock; } async function getSuggestedRelayer() { const res = await fetch2(`${addresses_default.RELAYER_URL}/active-relayers?solanaProgram=${addresses_default.MAYAN_PROGRAM_ID}`, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result.suggested; } async function getSwapSolana(params) { const query = toQueryString({ ...params, sdkVersion: getSdkVersion() }); const res = await fetch2(`${addresses_default.PRICE_URL}/get-swap/solana?${query}`, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result; } async function getSwapSui(params) { const requestBody = JSON.stringify({ ...params, sdkVersion: getSdkVersion() }); const requestUrl = `${addresses_default.PRICE_URL}/get-swap/sui`; const res = await fetch2(requestUrl, { method: "POST", redirect: "follow", body: requestBody, headers: { "Content-Type": "application/json" } }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result; } async function getSwapEvm(params) { const query = toQueryString({ ...params, sdkVersion: getSdkVersion() }); const res = await fetch2(`${addresses_default.PRICE_URL}/get-swap/evm?${query}`, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result; } async function submitSwiftEvmSwap(params, signature) { const res = await fetch2(`${addresses_default.EXPLORER_URL}/submit/evm`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...params, signature }, (_key, value) => { if (typeof value === "bigint") { return value.toString(); } return value; }) }); await check5xxError(res); } async function submitSwiftSolanaSwap(signedTx, chainName) { const res = await fetch2(`${addresses_default.EXPLORER_URL}/submit/v2/svm`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ signedTx, chainName }) }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result; } async function checkHyperCoreDeposit(destinationAddress, tokenAddress) { const query = toQueryString({ destWallet: destinationAddress, destToken: tokenAddress, sdkVersion: getSdkVersion() }); const res = await fetch2(`${addresses_default.EXPLORER_URL}/hypercore/is-allowed?${query}`, { method: "GET", redirect: "follow" }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result.allowed === true; } async function getEstimateGasEvm(params) { const res = await fetch2(`${addresses_default.GAS_ESTIMATE_URL}/evm`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...params, sdkVersion: getSdkVersion() }) }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return { estimatedGas: BigInt(result.estimatedGas), gasPrice: BigInt(result.gasPrice) }; } async function getSvmDurableNonce(chainName, swapperAddress) { const res = await fetch2(`${addresses_default.SWIFT_RELAYER_URL}/nonces/assign`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ chainName, swapperAddress, sdkVersion: getSdkVersion() }) }); await check5xxError(res); const result = await res.json(); if (res.status !== 200 && res.status !== 201) { throw result; } return result; } // src/evm/evmSwap.ts import { Contract as Contract6, toBeHex as toBeHex6, ZeroAddress as ZeroAddress10 } from "ethers"; import { PublicKey as PublicKey12, SystemProgram as SystemProgram11 } from "@solana/web3.js"; // src/evm/MayanSwapArtifact.ts var MayanSwapArtifact_default = { "_format": "hh-sol-artifact-1", "contractName": "MayanSwap", "sourceName": "src/MayanSwap.sol", "abi": [ { "inputs": [ { "internalType": "address", "name": "_tokenBridge", "type": "address" }, { "internalType": "address", "name": "_weth", "type": "address" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "uint16", "name": "emitterChainId", "type": "uint16" }, { "indexed": true, "internalType": "bytes32", "name": "emitterAddress", "type": "bytes32" }, { "indexed": true, "internalType": "uint64", "name": "sequence", "type": "uint64" } ], "name": "Redeemed", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "newGuardian", "type": "address" } ], "name": "changeGuardian", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "claimGuardian", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "uint8", "name": "payloadId", "type": "uint8" }, { "internalType": "bytes32", "name": "tokenAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "tokenChainId", "type": "uint16" }, { "internalType": "bytes32", "name": "destAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "destChainId", "type": "uint16" }, { "internalType": "bytes32", "name": "sourceAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "sourceChainId", "type": "uint16" }, { "internalType": "uint64", "name": "sequence", "type": "uint64" }, { "internalType": "uint64", "name": "amountOutMin", "type": "uint64" }, { "internalType": "uint64", "name": "deadline", "type": "uint64" }, { "internalType": "uint64", "name": "swapFee", "type": "uint64" }, { "internalType": "uint64", "name": "redeemFee", "type": "uint64" }, { "internalType": "uint64", "name": "refundFee", "type": "uint64" }, { "internalType": "bytes32", "name": "auctionAddr", "type": "bytes32" }, { "internalType": "bool", "name": "unwrapRedeem", "type": "bool" }, { "internalType": "bool", "name": "unwrapRefund", "type": "bool" } ], "internalType": "struct MayanStructs.Swap", "name": "s", "type": "tuple" } ], "name": "encodeSwap", "outputs": [ { "internalType": "bytes", "name": "encoded", "type": "bytes" } ], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getWeth", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "isPaused", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "bytes", "name": "encoded", "type": "bytes" } ], "name": "parseRedeemPayload", "outputs": [ { "components": [ { "internalType": "uint8", "name": "payloadId", "type": "uint8" }, { "internalType": "bytes32", "name": "recipient", "type": "bytes32" }, { "internalType": "uint64", "name": "relayerFee", "type": "uint64" }, { "internalType": "bool", "name": "unwrap", "type": "bool" }, { "internalType": "uint64", "name": "gasDrop", "type": "uint64" }, { "internalType": "bytes", "name": "customPayload", "type": "bytes" } ], "internalType": "struct MayanStructs.Redeem", "name": "r", "type": "tuple" } ], "stateMutability": "pure", "type": "function" }, { "inputs": [ { "internalType": "bytes", "name": "encodedVm", "type": "bytes" } ], "name": "redeem", "outputs": [], "stateMutability": "payable", "type": "function" }, { "inputs": [ { "internalType": "bytes", "name": "encodedVm", "type": "bytes" } ], "name": "redeemAndUnwrap", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "bool", "name": "_pause", "type": "bool" } ], "name": "setPause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "uint64", "name": "swapFee", "type": "uint64" }, { "internalType": "uint64", "name": "redeemFee", "type": "uint64" }, { "internalType": "uint64", "name": "refundFee", "type": "uint64" } ], "internalType": "struct MayanSwap.RelayerFees", "name": "relayerFees", "type": "tuple" }, { "components": [ { "internalType": "bytes32", "name": "mayanAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "mayanChainId", "type": "uint16" }, { "internalType": "bytes32", "name": "auctionAddr", "type": "bytes32" }, { "internalType": "bytes32", "name": "destAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "destChainId", "type": "uint16" }, { "internalType": "bytes32", "name": "referrer", "type": "bytes32" }, { "internalType": "bytes32", "name": "refundAddr", "type": "bytes32" } ], "internalType": "struct MayanSwap.Recepient", "name": "recipient", "type": "tuple" }, { "internalType": "bytes32", "name": "tokenOutAddr", "type": "bytes32" }, { "internalType": "uint16", "name": "tokenOutChainId", "type": "uint16" }, { "components": [ { "internalType": "uint256", "name": "transferDeadline", "type": "uint256" }, { "internalType": "uint64", "name": "swapDeadline", "type": "uint64" }, { "internalType": "uint64", "name": "amountOutMin", "type": "uint64" }, { "internalType": "bool", "name": "unwrap", "type": "bool" }, { "internalType": "uint64", "name": "gasDrop", "type": "uint64" }, { "internalType": "bytes", "name": "customPayload", "type": "bytes" } ], "internalType": "struct MayanSwap.Criteria", "name": "criteria", "type": "tuple" }, { "internalType": "address", "name": "tokenIn", "type": "address" }, { "internalType": "uint256", "name": "amountIn", "type": "uint256" } ], "name": "swap", "outputs": [ { "internalType": "uint64", "name": "sequence", "type": "uint64" } ], "stateMutability": "payable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "address payable", "name": "to", "type": "address" } ], "name": "sweepEth", "outputs": [], "stateMutability": "nonpayable",