Skip to content

Commit

Permalink
make token bridge work again
Browse files Browse the repository at this point in the history
  • Loading branch information
barnjamin committed Dec 29, 2023
1 parent a0f6fb5 commit 8290886
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 85 deletions.
4 changes: 1 addition & 3 deletions connect/src/protocols/tokenTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ export class TokenTransfer<N extends Network = Network>
const fromChain = this.wh.getChain(this.transfer.from.chain);
this.txids = await TokenTransfer.transfer<N>(fromChain, this.transfer, signer);
this._state = TransferState.SourceInitiated;

return this.txids.map(({ txid }) => txid);
}

Expand Down Expand Up @@ -225,7 +224,6 @@ export class TokenTransfer<N extends Network = Network>
timeout,
);
}

this._state = TransferState.Attested;
return this.attestations.map((vaa) => vaa.id);
}
Expand Down Expand Up @@ -254,8 +252,8 @@ export class TokenTransfer<N extends Network = Network>
attestation as TokenTransferVAA,
signer,
);

this.txids.push(...redeemTxids);
this._state = TransferState.DestinationInitiated;
return redeemTxids.map(({ txid }) => txid);
}

Expand Down
4 changes: 2 additions & 2 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
},
"sideEffects": false,
"scripts": {
"algo": "tsx src/algoTokenBridge.ts",
"algo": "cd ../platforms/algorand/protocols/tokenBridge && npm run build && cd - && tsx src/algoTokenBridge.ts",
"tb": "tsx src/tokenBridge.ts",
"cctp": "tsx src/cctp.ts",
"demo": "tsx src/index.ts",
"cosmos": "tsx src/cosmos.ts",
"retb": "cd .. && npm run build && cd - && npm run tb",
"msg": "cd ../platforms/algorand/protocols/core && npm run build && cd - && tsx src/messaging.ts",
"msg": "tsx src/messaging.ts",
"clean": "rm -rf ./dist && rm -f ./*.tsbuildinfo",
"lint": "npm run prettier && eslint --fix",
"prettier": "prettier --write ./src",
Expand Down
38 changes: 8 additions & 30 deletions examples/src/algoTokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ 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("Algorand");
const rcvChain = wh.getChain("Avalanche");
const sendChain = wh.getChain("Avalanche");
const rcvChain = wh.getChain("Algorand");

// Shortcut to allow transferring native gas token - worked 12-28-23
// const token: TokenId | "native" = "native";
const token: TokenId | "native" = "native";

// Test Algorand native ASA outbound with Testnet USDC 10458941 - worked 12-28-23
// const token = Wormhole.chainAddress("Algorand", new AlgorandAddress(BigInt(10458941)).toString());
Expand All @@ -49,7 +49,7 @@ import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
// const token = Wormhole.chainAddress("Algorand", new AlgorandAddress(BigInt(86783266)).toString());

// Test other chain wrapped token back to Algorand ASA with Avalanche wUSDC 0x12EB0d635FD4C5692d779755Ba82b33F6439fc73 - Failing on redeem 12-28-23
const token = Wormhole.chainAddress("Avalanche", "0x12EB0d635FD4C5692d779755Ba82b33F6439fc73");
// const token = Wormhole.chainAddress("Avalanche", "0x12EB0d635FD4C5692d779755Ba82b33F6439fc73");

// Normalized given token decimals later but can just pass bigints as base units
// Note: The Token bridge will dedust past 8 decimals
Expand Down Expand Up @@ -83,8 +83,9 @@ import "@wormhole-foundation/connect-sdk-evm-tokenbridge";

// Set this to the transfer txid of the initiating transaction to recover a token transfer
// and attempt to fetch details about its progress.
// let recoverTxid = undefined;
let recoverTxid = "0xdab98de823cd9e2ec3975bf366503dcd896a47a7ce3764fb964cc84b54f7159c"; // Avalanche-->Algorand
let recoverTxid = undefined;
// let recoverTxid = "0xdab98de823cd9e2ec3975bf366503dcd896a47a7ce3764fb964cc84b54f7159c"; // Avalanche-->Algorand
// recoverTxid = "0x83b4438b9135eef05734beea4fd4e41d644b1d07196c491e9576bf0ed24a9797";

// Finally create and perform the transfer given the parameters set above
const xfer = !recoverTxid
Expand All @@ -107,7 +108,7 @@ import "@wormhole-foundation/connect-sdk-evm-tokenbridge";

console.log("xfer: ", xfer);
// Log out the results
if (xfer.getTransferState() <= TransferState.DestinationInitiated) {
if (xfer.getTransferState() < TransferState.DestinationInitiated) {
console.log(await xfer.completeTransfer(destination.signer));
}
})();
Expand All @@ -125,7 +126,6 @@ async function tokenTransfer<N extends Network>(
};
payload?: Uint8Array;
},
roundTrip?: boolean,
): Promise<TokenTransfer<N>> {
// Create a TokenTransfer object to track the state of
// the transfer over time
Expand Down Expand Up @@ -170,26 +170,4 @@ async function tokenTransfer<N extends Network>(
console.log(`Completed Transfer: `, destTxids);

return xfer;
// // No need to send back, dip
// if (!roundTrip) return xfer;

// // We can look up the destination asset for this transfer given the context of
// // the sending chain and token and destination chain
// const token = await TokenTransfer.lookupDestinationToken(
// route.source.chain,
// route.destination.chain,
// xfer.transfer,
// );
// console.log(token);

// // The wrapped token may have a different number of decimals
// // to make things easy, lets just send the amount from the VAA back
// const amount = xfer.vaas![0]!.vaa!.payload.token.amount;
// return await tokenTransfer(wh, {
// ...route,
// token,
// amount,
// source: route.destination,
// destination: route.source,
// });
}
5 changes: 3 additions & 2 deletions platforms/algorand/protocols/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,16 @@ export class AlgorandWormholeCore<N extends Network, C extends AlgorandChains>
this.tokenBridgeAppAddress = getApplicationAddress(tokenBridge);
}

async *verifyMessage(sender: AnyAlgorandAddress, vaa: VAA) {
async *verifyMessage(sender: AnyAlgorandAddress, vaa: VAA, appId?: bigint) {
const address = new AlgorandAddress(sender).toString();
const txset = await submitVAAHeader(
this.connection,
this.coreAppId,
this.coreAppId,
appId ?? this.coreAppId,
vaa,
address,
);

for (const tx of txset.txs) {
yield this.createUnsignedTx(tx, "Core.verifyMessage");
}
Expand Down
20 changes: 0 additions & 20 deletions platforms/algorand/protocols/tokenBridge/src/assets.ts

This file was deleted.

2 changes: 0 additions & 2 deletions platforms/algorand/protocols/tokenBridge/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@ declare global {

registerProtocol(_platform, "TokenBridge", AlgorandTokenBridge);

export * from "./assets";
export * from "./tokenBridge";
export * from "./tokenBridge";
52 changes: 26 additions & 26 deletions platforms/algorand/protocols/tokenBridge/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ import {
decodeLocalState,
getMessageFee,
safeBigIntToNumber,
isOptedIn,
varint,
} from "@wormhole-foundation/connect-sdk-algorand";
import {
AlgorandWormholeCore,
maybeCreateStorageTx,
submitVAAHeader,
} from "@wormhole-foundation/connect-sdk-algorand-core";
import {
ABIMethod,
ABIType,
Algodv2,
OnApplicationComplete,
Expand All @@ -49,14 +56,7 @@ import {
makeAssetTransferTxnWithSuggestedParamsFromObject,
makePaymentTxnWithSuggestedParamsFromObject,
modelsv2,
ABIMethod,
} from "algosdk";
import { isOptedIn } from "./assets";
import { submitVAAHeader } from "@wormhole-foundation/connect-sdk-algorand-core/src/vaa";
import {
AlgorandWormholeCore,
maybeCreateStorageTx,
} from "@wormhole-foundation/connect-sdk-algorand-core";

import "@wormhole-foundation/connect-sdk-algorand-core";

Expand All @@ -74,6 +74,8 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
readonly tokenBridgeAppId: bigint;
readonly tokenBridgeAddress: string;

static completeTransfer = encoding.bytes.encode("completeTransfer");

constructor(
readonly network: N,
readonly chain: C,
Expand Down Expand Up @@ -556,43 +558,40 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
console.log("vaa payload token: ", vaa.payload.token.address.toString());
const senderAddr = new AlgorandAddress(sender).toString();

//yield *this.coreBridge.verifyMessage(senderAddr, vaa);
let { accounts, txs } = await submitVAAHeader(
const { accounts, txs } = await submitVAAHeader(
this.connection,
this.coreAppId,
this.tokenBridgeAppId,
vaa,
senderAddr,
);
console.log("accounts: ", accounts);
console.log("txs: ", txs);

const tokenStorage = StorageLogicSig.forWrappedAsset(this.tokenBridgeAppId, vaa.payload.token);
const tokenStorageAddress = tokenStorage.address();

let foreignAssets: number[] = [];
let assetId: number = 0;
if (vaa.payload.token.chain !== "Algorand") {
if (vaa.payload.token.chain !== this.chain) {
let asset = await decodeLocalState(
this.connection,
this.tokenBridgeAppId,
tokenStorageAddress,
);
if (asset.length > 8) {
const tmp = Buffer.from(asset.slice(0, 8));
assetId = safeBigIntToNumber(tmp.readBigUInt64BE(0));
console.log("assetId1: ", assetId);
}
assetId = safeBigIntToNumber(encoding.bignum.decode(asset.slice(0, 8)));
} else {
assetId = parseInt(vaa.payload.token.address.toString().slice(2), 16);
console.log("assetId2: ", assetId);
assetId = safeBigIntToNumber(
encoding.bignum.decode(vaa.payload.token.address.toUint8Array().slice(0, 8)),
);
}

accounts.push(tokenStorageAddress);

let aid = 0;
let addr = "";
if (vaa.payloadName === "TransferWithPayload") {
aid = Number(bytesToBigInt(vaa.payload.to.address.toUint8Array()));
aid = safeBigIntToNumber(
encoding.bignum.decode(vaa.payload.to.address.toUint8Array().slice(0, 8)),
);
addr = getApplicationAddress(aid);
} else {
addr = encodeAddress(vaa.payload.to.address.toUint8Array());
Expand Down Expand Up @@ -621,25 +620,26 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
accounts.push(addr);
const appCallObj = {
accounts: accounts,
appArgs: [encoding.bytes.encode("completeTransfer"), serialize(vaa)],
appArgs: [AlgorandTokenBridge.completeTransfer, serialize(vaa)],
appIndex: safeBigIntToNumber(this.tokenBridgeAppId),
foreignAssets: foreignAssets,
from: senderAddr,
onComplete: OnApplicationComplete.NoOpOC,
suggestedParams,
};

console.log("appCallObj: ", appCallObj);
txs.push({
tx: makeApplicationCallTxnFromObject(appCallObj),
signer: null,
});

// We need to cover the inner transactions
if (vaa.payloadName === "Transfer" && vaa.payload.fee !== undefined && vaa.payload.fee === 0n) {
txs[txs.length - 1].tx.fee = txs[txs.length - 1].tx.fee * 2;
} else {
txs[txs.length - 1].tx.fee = txs[txs.length - 1].tx.fee * 3;
}
txs[txs.length - 1].tx.fee =
txs[txs.length - 1].tx.fee *
(vaa.payloadName === "Transfer" && vaa.payload.fee !== undefined && vaa.payload.fee === 0n
? 2
: 3);

if (vaa.payloadName === "TransferWithPayload") {
txs[txs.length - 1].tx.appForeignApps = [aid];
Expand Down
18 changes: 18 additions & 0 deletions platforms/algorand/src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,21 @@ export async function decodeLocalState(
}
return new Uint8Array(ret);
}

/**
* Checks if the asset has been opted in by the receiver
* @param client Algodv2 client
* @param asset Algorand asset index
* @param receiver Account address
* @returns Promise with True if the asset was opted in, False otherwise
*/
export async function isOptedIn(client: Algodv2, address: string, asset: bigint): Promise<boolean> {
try {
const acctInfoResp = await client
.accountAssetInformation(address, safeBigIntToNumber(asset))
.do();
const acctInfo = modelsv2.AccountAssetResponse.from_obj_for_encoding(acctInfoResp);
return acctInfo.assetHolding.amount > 0;
} catch {}
return false;
}

0 comments on commit 8290886

Please sign in to comment.