Skip to content

Commit

Permalink
Refactor-algorand-sr (#186)
Browse files Browse the repository at this point in the history
* Testing notes

* wrapper fixes

---------

Co-authored-by: Ben Guidarelli <ben.guidarelli@gmail.com>
  • Loading branch information
SilentRhetoric and barnjamin authored Dec 29, 2023
1 parent eb561b6 commit 7575b4c
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 51 deletions.
1 change: 0 additions & 1 deletion connect/src/protocols/tokenTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ export class TokenTransfer<N extends Network = Network>
// otherwise, check to see if it is a wrapped token locally
lookup = await tb.getOriginalAsset(token.address);
} catch (e) {
console.error(e);
// not a from-chain native wormhole-wrapped one
lookup = token;
}
Expand Down
7 changes: 5 additions & 2 deletions core/base/src/utils/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ export const b58 = {
};

export const bignum = {
decode: (input: string | Uint8Array) =>
typeof input === "string" ? BigInt(input) : BigInt(hex.encode(input, true)),
decode: (input: string | Uint8Array) => {
if (typeof input !== "string") input = hex.encode(input, true);
if (input === "" || input === "0x") return 0n;
return BigInt(input);
},
encode: (input: bigint, prefix: boolean = false) => bignum.toString(input, prefix),
toString: (input: bigint, prefix: boolean = false) => {
let str = input.toString(16);
Expand Down
5 changes: 3 additions & 2 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"sideEffects": false,
"scripts": {
"algo": "cd ../platforms/algorand/protocols/tokenBridge && npm run build && cd - && tsx src/algoTokenBridge.ts",
"wrapped": "cd ../platforms/algorand/protocols/tokenBridge && npm run build && cd - && tsx src/createWrapped.ts",
"tb": "tsx src/tokenBridge.ts",
"cctp": "tsx src/cctp.ts",
"demo": "tsx src/index.ts",
Expand Down Expand Up @@ -64,6 +65,6 @@
"@wormhole-foundation/connect-sdk-evm-cctp": "^0.3.0-beta.6",
"@wormhole-foundation/connect-sdk-solana-cctp": "^0.3.0-beta.6",
"@wormhole-foundation/connect-sdk-cosmwasm-ibc": "^0.3.0-beta.6",
"algosdk":"^2.7.0"
"algosdk": "^2.7.0"
}
}
}
36 changes: 23 additions & 13 deletions examples/src/algoTokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
TokenId,
TokenTransfer,
TransferState,
UniversalAddress,
Wormhole,
encoding,
isTokenId,
normalizeAmount,
} from "@wormhole-foundation/connect-sdk";
Expand All @@ -21,16 +21,19 @@ import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
import "@wormhole-foundation/connect-sdk-algorand-tokenbridge";
import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
import "@wormhole-foundation/connect-sdk-solana-tokenbridge";
import algosdk, { Algodv2 } from "algosdk";
import { AlgorandSigner } from "@wormhole-foundation/connect-sdk-algorand/src/testing";

/*
1. Algorand native to other chain
2. Return wrapped ALGO from other chain to Algorand native
3. Algorand ASA to other chain
4. Return wrapped ASA from other chain to Algorand ASA
5. Other chain native to Algorand wrapped token
6. Return Algorand wrapped token to other chain native
7. Other chain token to Algorand wrapped token
8. Return Algorand wrapped token to other chain token
# Scenario | Status | TxID
1. Algorand native ALGO to other chain | OK | NK7DK5CLRU2HWNHFNBNFCLM5RLNBVICBUYEW6FBEQVMCVFBBG7JA
2. Return wrapped ALGO from other chain to Algorand native ALGO | FAIL | 4JGo9dwVv8XVTyf9CDXzX5QD4aBc4ZB6sHF7wFqw5LNLstqkRFmumwvu8HATddBVDcybKAAvrACfw1UEw3TD122b
3. Algorand ASA to other chain | OK_Ava | BNRWXLRWR7FVYMBBWHNWWCF65YQBDJAHVA5AMWADEC6K3WH76VYQ
4. Return wrapped token from other chain to original Algorand ASA | FAIL | 0x0dc8e8a052de3c62cda7d8a8211ac49c3c2c43d8841ee462e309c3d1abccbda4
5. Other chain native asset orand wrapped token | OK | 4wapEufhVAtv8oRqdrRzEovBHKkJDDD3m2pf1Jq3XtpvFwqA2YUijFqFufrGNyxY54vohmy3tsXCb2frcuBNa61T
6. Return Algorand wrapped token to other chain native asset | OK | TD5OWVV6BED5VFAGXBUWVITW6EX3KYOPXEJQLGMFIXM3JJ75HULQ
7. Other chain token to Algorand wrapped token | |
8. Return Algorand wrapped token to other chain token | |
*/

(async function () {
Expand All @@ -43,14 +46,18 @@ import "@wormhole-foundation/connect-sdk-solana-tokenbridge";
const rcvChain = wh.getChain("Solana");

// Shortcut to allow transferring native gas token
const token: TokenId | "native" = "native";
// const token = Wormhole.chainAddress("Algorand", "86897238");
// const token: TokenId | "native" = "native";

const token = Wormhole.chainAddress("Algorand", "10458941"); // USDC on Algorand
// const token = Wormhole.chainAddress("Avalanche", "0x12EB0d635FD4C5692d779755Ba82b33F6439fc73"); // wUSDC on Avalanche
// const token = Wormhole.chainAddress("Algorand", "86897238"); // wSOL on Algorand
// const token = Wormhole.chainAddress("Solana", "9rU2jFrzA5zDDmt9yR7vEABvXCUNJ1YgGigdTb9oCaTv"); // wALGO on Solana

// Normalized given token decimals later but can just pass bigints as base units
// Note: The Token bridge will dedust past 8 decimals
// this means any amount specified past that point will be returned
// to the caller
const amount = "0.0001";
const amount = "0.00001";

// With automatic set to true, perform an automatic transfer. This will invoke a relayer
// contract intermediary that knows to pick up the transfers
Expand Down Expand Up @@ -79,7 +86,10 @@ import "@wormhole-foundation/connect-sdk-solana-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;
// recoverTxid = "BCAAZRCXAVTKKPIOTUE32GH6LQCW3CSCR3HAEM3I65KNH7PUUPKA";
// recoverTxid =
// "4JGo9dwVv8XVTyf9CDXzX5QD4aBc4ZB6sHF7wFqw5LNLstqkRFmumwvu8HATddBVDcybKAAvrACfw1UEw3TD122b"; // Recover scenario 2
// recoverTxid =
// "0x0dc8e8a052de3c62cda7d8a8211ac49c3c2c43d8841ee462e309c3d1abccbda4"; // Recover scenario 4

// Finally create and perform the transfer given the parameters set above
const xfer = !recoverTxid
Expand Down
91 changes: 91 additions & 0 deletions examples/src/createWrapped.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { TokenId, Wormhole, signSendWait } from "@wormhole-foundation/connect-sdk";
import { AlgorandPlatform } from "@wormhole-foundation/connect-sdk-algorand";
import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
import { getStuff } from "./helpers";

import "@wormhole-foundation/connect-sdk-algorand-tokenbridge";
import "@wormhole-foundation/connect-sdk-solana-tokenbridge";

(async function () {
const wh = new Wormhole("Testnet", [AlgorandPlatform, SolanaPlatform]);

// Original Token to Attest
const token: TokenId = Wormhole.chainAddress("Algorand", "10458941");

// grab context and signer
const origChain = wh.getChain(token.chain);
const { signer: origSigner } = await getStuff(origChain);

// Note: if the VAA is not produced before the attempt to retrieve it times out
// you should set this value to the txid logged in the previous run
let txid = undefined;
// txid = "0x55127b9c8af46aaeea9ef28d8bf91e1aff920422fc1c9831285eb0f39ddca2fe";

txid = "FPNHIFFUZDVPT5SATZQZZ7DFGZMPCCHEFBCB5EZQJV4RRK3ZYTVA";
txid = "GWZU432ERFU3NES4MA7IAAP6DX73F5VRSSIWGJVC5JRHOH6UMWEQ";

if (!txid) {
// create attestation from origin chain, the same VAA
// can be used across all chains
const tb = await origChain.getTokenBridge();
const attestTxns = tb.createAttestation(
token.address,
Wormhole.parseAddress(origSigner.chain(), origSigner.address()),
);
const txids = await signSendWait(origChain, attestTxns, origSigner);
txid = txids[0].txid;
console.log("Created attestation (save this): ", txid);
}

// Get the wormhole message id from the transaction logs
const msgs = await origChain.parseTransaction(txid);
console.log(msgs);

// Get the Signed VAA from the API
const timeout = 60_000; // 60 seconds
const vaa = await wh.getVaa(msgs[0], "TokenBridge:AttestMeta", timeout);
if (!vaa) throw new Error("VAA not found after retries exhausted, try extending the timeout");

console.log(vaa.payload.token.address);

// Check if its attested and if not
// submit the attestation to the token bridge on the
// destination chain
const chain = "Solana";
const destChain = wh.getChain(chain);
const { signer } = await getStuff(destChain);

// grab a ref to the token bridge
const tb = await destChain.getTokenBridge();
try {
// try to get the wrapped version, an error here likely means
// its not been attested
const wrapped = await tb.getWrappedAsset(token);
console.log("already wrapped");
return { chain, address: wrapped };
} catch (e) {}

// no wrapped asset, needs to be attested
console.log("attesting asset");
await signSendWait(
destChain,
tb.submitAttestation(vaa, Wormhole.parseAddress(signer.chain(), signer.address())),
signer,
);

async function waitForIt() {
do {
// check again
try {
const wrapped = await tb.getWrappedAsset(token);
return { chain, address: wrapped };
} catch (e) {
console.error(e);
}
console.log("Waiting before checking again...");
await new Promise((r) => setTimeout(r, 2000));
} while (true);
}

console.log("wrapped: ", await waitForIt());
})();
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions platforms/algorand/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wormhole-foundation/connect-sdk-algorand",
"version": "0.3.0-beta.5",
"version": "0.3.0-beta.6",
"repository": {
"type": "git",
"url": "git+https://github.com/wormhole-foundation/connect-sdk.git"
Expand Down Expand Up @@ -43,7 +43,7 @@
"test": "jest --config ./jest.config.ts"
},
"dependencies": {
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.5",
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.6",
"algosdk": "2.7.0"
}
}
6 changes: 3 additions & 3 deletions platforms/algorand/protocols/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wormhole-foundation/connect-sdk-algorand-core",
"version": "0.3.0-beta.5",
"version": "0.3.0-beta.6",
"repository": {
"type": "git",
"url": "git+https://github.com/wormhole-foundation/connect-sdk.git"
Expand Down Expand Up @@ -42,7 +42,7 @@
"prettier": "prettier --write ./src"
},
"dependencies": {
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.5",
"@wormhole-foundation/connect-sdk-algorand": "^0.3.0-beta.5"
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.6",
"@wormhole-foundation/connect-sdk-algorand": "^0.3.0-beta.6"
}
}
8 changes: 4 additions & 4 deletions platforms/algorand/protocols/tokenBridge/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wormhole-foundation/connect-sdk-algorand-tokenbridge",
"version": "0.3.0-beta.5",
"version": "0.3.0-beta.6",
"repository": {
"type": "git",
"url": "git+https://github.com/wormhole-foundation/connect-sdk.git"
Expand Down Expand Up @@ -42,8 +42,8 @@
"prettier": "prettier --write ./src"
},
"dependencies": {
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.5",
"@wormhole-foundation/connect-sdk-algorand": "^0.3.0-beta.5",
"@wormhole-foundation/connect-sdk-algorand-core": "^0.3.0-beta.5"
"@wormhole-foundation/connect-sdk": "^0.3.0-beta.6",
"@wormhole-foundation/connect-sdk-algorand": "^0.3.0-beta.6",
"@wormhole-foundation/connect-sdk-algorand-core": "^0.3.0-beta.6"
}
}
22 changes: 17 additions & 5 deletions platforms/algorand/protocols/tokenBridge/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
assetInfo.params.creator,
);

const chainId = encoding.bignum.decode(decodedLocalState.slice(92, 94));
if (decodedLocalState.length < 94) throw new Error("Invalid local state data");

const chainBytes = decodedLocalState.slice(92, 94);
const chainId = encoding.bignum.decode(chainBytes);
const assetAddress = decodedLocalState.slice(60, 60 + 32);

return {
Expand Down Expand Up @@ -402,6 +405,8 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
const chainId = toChainId(recipient.chain);
const receiver = recipient.address.toUniversalAddress().toUint8Array();

const suggestedParams: SuggestedParams = await this.connection.getTransactionParams().do();

const fee = BigInt(0);

const tbs = StorageLogicSig.fromData({
Expand All @@ -415,7 +420,13 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
const {
accounts: [emitterAddr],
txs: emitterOptInTxs,
} = await maybeCreateStorageTx(this.connection, senderAddr, this.coreAppId, tbs);
} = await maybeCreateStorageTx(
this.connection,
senderAddr,
this.coreAppId,
tbs,
suggestedParams,
);
txs.push(...emitterOptInTxs);

// Check that the auth address of the creator
Expand All @@ -427,12 +438,12 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
const assetInfoResp: Record<string, any> = await this.connection.getAssetByID(assetId).do();
const asset = modelsv2.Asset.from_obj_for_encoding(assetInfoResp);
creator = asset.params.creator;

const creatorAcctInfoResp = await this.connection.accountInformation(creator).do();
creatorAcct = modelsv2.Account.from_obj_for_encoding(creatorAcctInfoResp);
wormhole = creatorAcct.authAddr === this.tokenBridgeAddress.toString();
}

const suggestedParams: SuggestedParams = await this.connection.getTransactionParams().do();
const msgFee: bigint = await getMessageFee(this.connection, this.coreAppId);
if (msgFee > 0)
txs.push({
Expand All @@ -458,6 +469,7 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
senderAddr,
this.tokenBridgeAppId,
nativeStorageAccount,
suggestedParams,
);
creator = address;
txs.push(...txs);
Expand All @@ -471,7 +483,7 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
amount: 100000,
suggestedParams,
});
txs.push({ tx: payTxn, signer: null });
txs.unshift({ tx: payTxn, signer: null });
// The tokenid app needs to do the optin since it has signature authority
let txn = makeApplicationCallTxnFromObject({
from: senderAddr,
Expand All @@ -483,7 +495,7 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
suggestedParams,
});
txn.fee *= 2;
txs.push({ tx: txn, signer: null });
txs.unshift({ tx: txn, signer: null });
}

const t = makeApplicationCallTxnFromObject({
Expand Down
Loading

0 comments on commit 7575b4c

Please sign in to comment.