diff --git a/examples/package.json b/examples/package.json index cad20ed3f5..084f9ca7a9 100644 --- a/examples/package.json +++ b/examples/package.json @@ -33,7 +33,7 @@ }, "sideEffects": false, "scripts": { - "algo": "cd ../platforms/algorand/protocols/tokenBridge && npm run build && cd - && tsx src/algoTokenBridge.ts", + "algo": "cd ../platforms/algorand/protocols/core && npm run build && cd - && tsx src/algoTokenBridge.ts", "tb": "tsx src/tokenBridge.ts", "cctp": "tsx src/cctp.ts", "demo": "tsx src/index.ts", diff --git a/examples/src/algoTokenBridge.ts b/examples/src/algoTokenBridge.ts index 730c8232d7..894fa34e9a 100644 --- a/examples/src/algoTokenBridge.ts +++ b/examples/src/algoTokenBridge.ts @@ -36,8 +36,8 @@ import "@wormhole-foundation/connect-sdk-evm-tokenbridge"; const wh = new Wormhole("Testnet", [AlgorandPlatform, EvmPlatform]); // Grab chain Contexts -- these hold a reference to a cached rpc client - const sendChain = wh.getChain("Avalanche"); - const rcvChain = wh.getChain("Algorand"); + const sendChain = wh.getChain("Algorand"); + const rcvChain = wh.getChain("Avalanche"); // Shortcut to allow transferring native gas token - worked 12-28-23 const token: TokenId | "native" = "native"; @@ -85,7 +85,9 @@ import "@wormhole-foundation/connect-sdk-evm-tokenbridge"; // and attempt to fetch details about its progress. let recoverTxid = undefined; // let recoverTxid = "0xdab98de823cd9e2ec3975bf366503dcd896a47a7ce3764fb964cc84b54f7159c"; // Avalanche-->Algorand - // recoverTxid = "0x83b4438b9135eef05734beea4fd4e41d644b1d07196c491e9576bf0ed24a9797"; + // recoverTxid = "NLI5KZSGDVO6JFZCJTN6VA7PSCWJB22FBGC33CPHQWGXFDOFKFVA"; + // recoverTxid = "3I552XXYJZ52G6WH7KVAM2CNNSWAZJTYNYUDTIKK3342NU2U2J4A"; + recoverTxid = "T3C2VCOGZPW2OAPZZ4V5YWA2KM3PZWYSEVAQDZE5YQGCTAO75IRA"; // Finally create and perform the transfer given the parameters set above const xfer = !recoverTxid diff --git a/platforms/algorand/protocols/core/src/core.ts b/platforms/algorand/protocols/core/src/core.ts index 1c8e7a35ee..213aa3d1cd 100644 --- a/platforms/algorand/protocols/core/src/core.ts +++ b/platforms/algorand/protocols/core/src/core.ts @@ -133,9 +133,21 @@ export class AlgorandWormholeCore async parseTransaction(txId: string): Promise { const result = await this.connection.pendingTransactionInformation(txId).do(); const ptr = modelsv2.PendingTransactionResponse.from_obj_for_encoding(result); + return this.parseTx(ptr); + } + + private parseTx(ptr: modelsv2.PendingTransactionResponse): WormholeMessageId[] { + const msgs: WormholeMessageId[] = []; + + if (ptr.innerTxns && ptr.innerTxns.length > 0) { + msgs.push(...ptr.innerTxns.flatMap((tx) => this.parseTx(tx))); + } // Expect target is core app - if (BigInt(ptr.txn.txn.apid) !== this.coreAppId) throw new Error("Invalid app id"); + if (BigInt(ptr.txn.txn.apid) !== this.coreAppId) return msgs; + + // Expect logs + if (!ptr.logs || ptr.logs.length === 0) return msgs; // Expect publish messeage as first arg const args = ptr.txn.txn.apaa; @@ -143,14 +155,14 @@ export class AlgorandWormholeCore args.length !== 3 || !encoding.bytes.equals(new Uint8Array(args[0]), AlgorandWormholeCore.publishMessage) ) - throw new Error("Invalid transaction arguments"); - - if (!ptr.logs || ptr.logs.length === 0) throw new Error("No logs found to parse sequence"); + return msgs; const sequence = encoding.bignum.decode(ptr.logs[0]); + console.log(ptr.txn.txn); const emitter = new AlgorandAddress(ptr.txn.txn.snd).toUniversalAddress(); + msgs.push({ chain: this.chain, emitter, sequence }); - return [{ chain: this.chain, emitter, sequence }]; + return msgs; } private createUnsignedTx( diff --git a/platforms/algorand/src/address.ts b/platforms/algorand/src/address.ts index 4e6c5b9810..7302a1ef2c 100644 --- a/platforms/algorand/src/address.ts +++ b/platforms/algorand/src/address.ts @@ -56,6 +56,10 @@ export class AlgorandAddress implements Address { return new UniversalAddress(this.toUint8Array()); } + toInt(): bigint { + return encoding.bignum.decode(this.toUint8Array()); + } + static instanceof(address: any): address is AlgorandAddress { return address.constructor.platform === AlgorandPlatform._platform; } diff --git a/platforms/algorand/src/platform.ts b/platforms/algorand/src/platform.ts index f71547887a..89fb8b62d1 100644 --- a/platforms/algorand/src/platform.ts +++ b/platforms/algorand/src/platform.ts @@ -16,14 +16,14 @@ import { import { Algodv2, SignedTransaction, - bytesToBigInt, decodeSignedTransaction, - waitForConfirmation, modelsv2, + waitForConfirmation, } from "algosdk"; +import { AlgorandAddress, AlgorandZeroAddress } from "./address"; import { AlgorandChain } from "./chain"; import { AlgorandChains, AlgorandPlatformType, AnyAlgorandAddress, _platform } from "./types"; -import { AlgorandAddress, AlgorandZeroAddress } from "./address"; +import { safeBigIntToNumber } from "./utilities"; /** * @category Algorand @@ -76,18 +76,8 @@ export class AlgorandPlatform extends PlatformContext extends PlatformContext { - if (token === "native") return BigInt(decimals.nativeDecimals(AlgorandPlatform._platform)); - const asaId = this.anyAlgorandAddressToAsaId(token); - const assetResp = await rpc.getAssetByID(asaId).do(); + // It may come in as a universal address + const assetId = token === "native" ? 0 : this.anyAlgorandAddressToAsaId(token); + + if (assetId === 0) return BigInt(decimals.nativeDecimals(AlgorandPlatform._platform)); + + const assetResp = await rpc.getAssetByID(assetId).do(); const asset = modelsv2.Asset.from_obj_for_encoding(assetResp); if (!asset.params || !asset.params.decimals) throw new Error("Could not fetch token details"); return BigInt(asset.params.decimals); @@ -109,12 +102,14 @@ export class AlgorandPlatform extends PlatformContext { - if (token === "native") { + const asaId = token === "native" ? 0 : this.anyAlgorandAddressToAsaId(token); + + if (asaId === 0) { const resp = await rpc.accountInformation(walletAddr).do(); const accountInfo = modelsv2.Account.from_obj_for_encoding(resp); return BigInt(accountInfo.amount); } - const asaId = this.anyAlgorandAddressToAsaId(token); + const acctAssetInfoResp = await rpc.accountAssetInformation(walletAddr, asaId).do(); const accountAssetInfo = modelsv2.AssetHolding.from_obj_for_encoding(acctAssetInfoResp); return BigInt(accountAssetInfo.amount);