UNPKG

@xlink-network/xlink-sdk

Version:
1 lines 8.21 kB
{"version":3,"sources":["../src/xlinkSdkUtils/timelockFromEVM.ts"],"sourcesContent":["import { Client, encodeFunctionData, zeroAddress } from \"viem\"\nimport { estimateGas, readContract } from \"viem/actions\"\nimport { BridgeEndpointAbi } from \"../evmUtils/contractAbi/bridgeEndpoint\"\nimport { BridgeTimeLockAbi } from \"../evmUtils/contractAbi/bridgeTimeLock\"\nimport {\n getEVMContractCallInfo,\n getEVMTokenContractInfo,\n numberFromSolidityContractNumber,\n} from \"../evmUtils/xlinkContractHelpers\"\nimport { BigNumber } from \"../utils/BigNumber\"\nimport { UnsupportedChainError } from \"../utils/errors\"\nimport { decodeHex } from \"../utils/hexHelpers\"\nimport { isNotNull } from \"../utils/typeHelpers\"\nimport {\n KnownChainId,\n KnownTokenId,\n _allKnownEVMTokens,\n} from \"../utils/types/knownIds\"\nimport { EVMAddress, SDKNumber, toSDKNumberOrUndefined } from \"./types\"\nimport { SDKGlobalContext } from \"./types.internal\"\nimport { nativeCurrencyAddress } from \"../evmUtils/addressHelpers\"\n\nexport interface TimeLockedAsset {\n id: string\n chain: KnownChainId.EVMChain\n token: KnownTokenId.EVMToken\n amount: SDKNumber\n releaseTime: Date\n}\n\nconst getTimeLockContractCallInfo = async (\n ctx: SDKGlobalContext,\n chain: KnownChainId.EVMChain,\n): Promise<\n | undefined\n | {\n client: Client\n timeLockContractAddress: EVMAddress\n }\n> => {\n const info = await getEVMContractCallInfo(ctx, chain)\n if (info == null) return\n\n const timeLockContractAddress =\n info.timeLockContractAddress ??\n (await readContract(info.client, {\n abi: BridgeEndpointAbi,\n address: info.bridgeEndpointContractAddress,\n functionName: \"timeLock\",\n }).catch(err => {\n console.groupCollapsed(\n `Failed to read timeLock contract address from ${info.bridgeEndpointContractAddress} (${chain})`,\n )\n console.debug(err)\n console.groupEnd()\n return zeroAddress\n }))\n if (timeLockContractAddress === zeroAddress) return\n\n return { client: info.client, timeLockContractAddress }\n}\n\nexport interface GetTimeLockedAssetsInput {\n walletAddress: EVMAddress\n chains: KnownChainId.EVMChain[]\n}\nexport interface GetTimeLockedAssetsOutput {\n assets: TimeLockedAsset[]\n}\nexport async function getTimeLockedAssetsFromEVM(\n ctx: SDKGlobalContext,\n input: GetTimeLockedAssetsInput,\n): Promise<GetTimeLockedAssetsOutput> {\n const promises = input.chains.map(async chain => {\n const timeLockCallInfo = await getTimeLockContractCallInfo(ctx, chain)\n if (timeLockCallInfo == null) return []\n\n const tokenCallInfos = (\n await Promise.all(\n _allKnownEVMTokens.map(token =>\n getEVMTokenContractInfo(ctx, chain, token).then(info =>\n info == null || info.tokenContractAddress === nativeCurrencyAddress\n ? null\n : { ...info, chain, token },\n ),\n ),\n )\n ).filter(isNotNull)\n\n const agreements = (\n await Promise.all(\n tokenCallInfos.map(info =>\n readContract(timeLockCallInfo.client, {\n abi: BridgeTimeLockAbi,\n address: timeLockCallInfo.timeLockContractAddress,\n functionName: \"agreementsByUser\",\n args: [input.walletAddress, 0, info.tokenContractAddress, \"0x\"],\n }).then(agreementId =>\n agreementId === 0n ? [] : [{ agreementId, info }],\n ),\n ),\n )\n ).flat()\n\n return Promise.all(\n agreements.map(async ({ agreementId, info }) => {\n const agreement = await readContract(timeLockCallInfo.client, {\n abi: BridgeTimeLockAbi,\n address: timeLockCallInfo.timeLockContractAddress,\n functionName: \"agreements\",\n args: [agreementId],\n })\n return {\n id: String(agreementId),\n chain: info.chain,\n token: info.token,\n amount: toSDKNumberOrUndefined(\n numberFromSolidityContractNumber(agreement[0]),\n ),\n releaseTime: new Date(agreement[6] * 1000),\n }\n }),\n )\n })\n\n return {\n assets: (await Promise.all(promises)).flat(),\n }\n}\n\nexport interface ClaimTimeLockedAssetsInput {\n chain: KnownChainId.EVMChain\n walletAddress: EVMAddress\n lockedAssetIds: string[]\n sendTransaction: (tx: {\n from: EVMAddress\n to: EVMAddress\n data: Uint8Array\n recommendedGasLimit: SDKNumber\n }) => Promise<{\n txHash: string\n }>\n}\nexport interface ClaimTimeLockedAssetsOutput {\n txHash: string\n}\nexport const claimTimeLockedAssetsFromEVM = async (\n ctx: SDKGlobalContext,\n input: ClaimTimeLockedAssetsInput,\n): Promise<undefined | ClaimTimeLockedAssetsOutput> => {\n const info = await getTimeLockContractCallInfo(ctx, input.chain)\n if (info == null) throw new UnsupportedChainError(input.chain)\n\n const functionData = encodeFunctionData({\n abi: BridgeTimeLockAbi,\n functionName: \"claim\",\n args: [\n input.lockedAssetIds.map(id =>\n BigNumber.toBigInt({ roundingMode: BigNumber.roundDown }, id),\n ),\n ],\n })\n const estimated = await estimateGas(info.client, {\n account: input.walletAddress,\n to: info.timeLockContractAddress,\n data: functionData,\n })\n .then(n => BigNumber.round({ precision: 0 }, BigNumber.mul(n, 1.2)))\n .catch(\n // add a fallback in case estimate failed\n () =>\n // https://bscscan.com/tx/0x28a81312ca7bc93e7ef07867c9906a41b251ea3ea630b0a4837bdb3066489b32\n 1 * 1e6,\n )\n return await input.sendTransaction({\n from: input.walletAddress,\n to: info.timeLockContractAddress,\n data: decodeHex(functionData),\n recommendedGasLimit: toSDKNumberOrUndefined(estimated),\n })\n}\n"],"mappings":"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","names":[]}