Skip to content

Commit

Permalink
cleanup again
Browse files Browse the repository at this point in the history
  • Loading branch information
barnjamin committed Dec 29, 2023
1 parent da3b608 commit 471b78d
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 276 deletions.
3 changes: 1 addition & 2 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,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",
"wrapped": "tsx src/createWrapped.ts",
"tb": "tsx src/tokenBridge.ts",
"cctp": "tsx src/cctp.ts",
"demo": "tsx src/index.ts",
Expand Down
174 changes: 0 additions & 174 deletions examples/src/algoTokenBridge.ts

This file was deleted.

10 changes: 7 additions & 3 deletions examples/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,27 @@ import { TransferStuff, getStuff, waitLog } from "./helpers";
// Import the platform specific packages
import { EvmPlatform } from "@wormhole-foundation/connect-sdk-evm";
import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
import { AlgorandPlatform } from "@wormhole-foundation/connect-sdk-algorand";

// Register the protocols
import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
import "@wormhole-foundation/connect-sdk-solana-tokenbridge";
import "@wormhole-foundation/connect-sdk-algorand-tokenbridge";

(async function () {
// init Wormhole object, passing config for which network
// to use (e.g. Mainnet/Testnet) and what Platforms to support
const wh = new Wormhole("Testnet", [EvmPlatform, SolanaPlatform]);
const wh = new Wormhole("Testnet", [EvmPlatform, SolanaPlatform, AlgorandPlatform]);

// Grab chain Contexts -- these hold a reference to a cached rpc client
const sendChain = wh.getChain("Solana");
const rcvChain = wh.getChain("Avalanche");
const sendChain = wh.getChain("Algorand");
const rcvChain = wh.getChain("Solana");

// shortcut to allow transferring native gas token
const token: TokenId | "native" = "native";

// const token = Wormhole.chainAddress("Algorand", "10458941"); // USDC on Algorand

// A TokenId is just a `{chain, address}` pair and an alias for ChainAddress
// The `address` field must be a parsed address.
// You can get a TokenId (or ChainAddress) prepared for you
Expand Down
22 changes: 15 additions & 7 deletions platforms/algorand/protocols/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import {
TransactionSet,
TransactionSignerPair,
safeBigIntToNumber,
ALGO_VERIFY,
ALGO_VERIFY_HASH,
MAX_SIGS_PER_TXN,
} from "@wormhole-foundation/connect-sdk-algorand";
import {
Algodv2,
Expand All @@ -50,6 +47,17 @@ export class AlgorandWormholeCore<N extends Network, C extends AlgorandChains>
readonly tokenBridgeAppId: bigint;
readonly tokenBridgeAppAddress: string;

static MAX_SIGS_PER_TXN: number = 6;
static ALGO_VERIFY_HASH = "EZATROXX2HISIRZDRGXW4LRQ46Z6IUJYYIHU3PJGP7P5IQDPKVX42N767A";
static ALGO_VERIFY = new Uint8Array([
6, 32, 4, 1, 0, 32, 20, 38, 1, 0, 49, 32, 50, 3, 18, 68, 49, 1, 35, 18, 68, 49, 16, 129, 6, 18,
68, 54, 26, 1, 54, 26, 3, 54, 26, 2, 136, 0, 3, 68, 34, 67, 53, 2, 53, 1, 53, 0, 40, 53, 240,
40, 53, 241, 52, 0, 21, 53, 5, 35, 53, 3, 35, 53, 4, 52, 3, 52, 5, 12, 65, 0, 68, 52, 1, 52, 0,
52, 3, 129, 65, 8, 34, 88, 23, 52, 0, 52, 3, 34, 8, 36, 88, 52, 0, 52, 3, 129, 33, 8, 36, 88, 7,
0, 53, 241, 53, 240, 52, 2, 52, 4, 37, 88, 52, 240, 52, 241, 80, 2, 87, 12, 20, 18, 68, 52, 3,
129, 66, 8, 53, 3, 52, 4, 37, 8, 53, 4, 66, 255, 180, 34, 137,
]);

// global state key for message fee
static feeKey = encoding.b64.encode("MessageFee");
// method selector for verifying a VAA
Expand Down Expand Up @@ -317,14 +325,14 @@ export class AlgorandWormholeCore<N extends Network, C extends AlgorandChains>
// How many signatures can we process in a single txn... we can do 6!
// There are likely upwards of 19 signatures. So, we ned to split things up
const numSigs: number = vaa.signatures.length;
const numTxns: number = Math.floor(numSigs / MAX_SIGS_PER_TXN) + 1;
const numTxns: number = Math.floor(numSigs / AlgorandWormholeCore.MAX_SIGS_PER_TXN) + 1;

const SIG_LEN: number = 66;
const GuardianKeyLen: number = 20;
const lsa = new LogicSigAccount(ALGO_VERIFY);
const lsa = new LogicSigAccount(AlgorandWormholeCore.ALGO_VERIFY);

for (let nt = 0; nt < numTxns; nt++) {
let sigs = vaa.signatures.slice(nt, nt + MAX_SIGS_PER_TXN);
let sigs = vaa.signatures.slice(nt, nt + AlgorandWormholeCore.MAX_SIGS_PER_TXN);

// The keyset is the set of Guardians that correspond
// to the current set of signatures in this loop.
Expand Down Expand Up @@ -356,7 +364,7 @@ export class AlgorandWormholeCore<N extends Network, C extends AlgorandChains>
],
accounts: accts,
appIndex: safeBigIntToNumber(coreId),
from: ALGO_VERIFY_HASH,
from: AlgorandWormholeCore.ALGO_VERIFY_HASH,
onComplete: OnApplicationComplete.NoOpOC,
suggestedParams,
});
Expand Down
48 changes: 47 additions & 1 deletion platforms/algorand/protocols/core/src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
toChainId,
} from "@wormhole-foundation/connect-sdk";
import { Algodv2, LogicSigAccount, decodeAddress, getApplicationAddress, modelsv2 } from "algosdk";
import { safeBigIntToNumber, varint } from "@wormhole-foundation/connect-sdk-algorand";
import { safeBigIntToNumber } from "@wormhole-foundation/connect-sdk-algorand";

export const SEED_AMT: number = 1002000;
export const MAX_KEYS: number = 15;
Expand All @@ -23,6 +23,52 @@ export interface PopulateData {
idx: bigint;
}

// Useful for encoding numbers as varints to patch TEAL binary
export const varint = {
// Forever grateful to https://github.com/joeltg/big-varint/blob/main/src/unsigned.ts
_limit: 0x7f,
encodingLength: (value: number) => {
let i = 0;
for (; value >= 0x80; i++) value >>= 7;
return i + 1;
},
encode: (i: bigint | number, buffer?: ArrayBuffer, byteOffset?: number) => {
if (typeof i === "bigint") i = safeBigIntToNumber(i);

if (i < 0) throw new RangeError("value must be unsigned");

const byteLength = varint.encodingLength(i);
buffer = buffer || new ArrayBuffer(byteLength);
byteOffset = byteOffset || 0;

if (buffer.byteLength < byteOffset + byteLength)
throw new RangeError("the buffer is too small to encode the number at the offset");

const array = new Uint8Array(buffer, byteOffset);

let offset = 0;
while (varint._limit < i) {
array[offset++] = (i & varint._limit) | 0x80;
i >>= 7;
}
array[offset] = Number(i);
return array;
},
decode: (data: Uint8Array, offset = 0) => {
let i = 0;
let n = 0;
let b: number | undefined;
do {
b = data[offset + n];
if (b === undefined) throw new RangeError("offset out of range");

i += (b & varint._limit) << (n * 7);
n++;
} while (0x80 <= b);
return i;
},
};

export const StorageLogicSig = {
// Get the storage lsig for a Wormhole message ID
forMessageId: (appId: bigint, whm: WormholeMessageId) => {
Expand Down
26 changes: 23 additions & 3 deletions platforms/algorand/protocols/tokenBridge/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
AlgorandUnsignedTransaction,
AnyAlgorandAddress,
TransactionSignerPair,
isOptedIn,
safeBigIntToNumber,
} from "@wormhole-foundation/connect-sdk-algorand";
import {
Expand Down Expand Up @@ -464,7 +463,10 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
txs.push(...txs);
}

if (assetId !== 0 && !(await isOptedIn(this.connection, creator, assetId))) {
if (
assetId !== 0 &&
!(await AlgorandTokenBridge.isOptedInToAsset(this.connection, creator, assetId))
) {
// Looks like we need to optin
const payTxn = makePaymentTxnWithSuggestedParamsFromObject({
from: senderAddr,
Expand Down Expand Up @@ -596,7 +598,9 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>

if (assetId !== 0) {
foreignAssets.push(assetId);
if (!(await isOptedIn(this.connection, receiverAddress, assetId))) {
if (
!(await AlgorandTokenBridge.isOptedInToAsset(this.connection, receiverAddress, assetId))
) {
if (senderAddr != receiverAddress) {
throw new Error("Cannot ASA optin for somebody else (asset " + assetId.toString() + ")");
}
Expand Down Expand Up @@ -661,6 +665,22 @@ export class AlgorandTokenBridge<N extends Network, C extends AlgorandChains>
}
}

/**
* 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
*/
static async isOptedInToAsset(client: Algodv2, address: string, asset: number): Promise<boolean> {
try {
const acctInfoResp = await client.accountAssetInformation(address, asset).do();
const acctInfo = modelsv2.AccountAssetResponse.from_obj_for_encoding(acctInfoResp);
return acctInfo.assetHolding.amount > 0;
} catch {}
return false;
}

private createUnsignedTx(
txReq: TransactionSignerPair,
description: string,
Expand Down
3 changes: 1 addition & 2 deletions platforms/algorand/src/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import {
} from "@wormhole-foundation/connect-sdk";

import { AlgorandPlatform } from "./platform";
import { _platform, AnyAlgorandAddress } from "./types";
import { _platform, AnyAlgorandAddress, safeBigIntToNumber } from "./types";
import { decodeAddress, encodeAddress, isValidAddress } from "algosdk";
import { safeBigIntToNumber } from "./utilities";

export const AlgorandZeroAddress = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ";

Expand Down
Loading

0 comments on commit 471b78d

Please sign in to comment.