1) Add payload3 support into typescript
2) Add tests for payload3 3) Change the contract API for payload3 so that the destination is the appId instead of the app address and no longer part of the data 4) add a testApp into devnet
This commit is contained in:
parent
34ea483dbe
commit
4e53392819
|
@ -1,3 +1,7 @@
|
|||
npm run test -- algorand
|
||||
|
||||
https://developer.algorand.org/docs/rest-apis/algod/v2/#get-v2statuswait-for-block-afterround
|
||||
|
||||
current algorand machine size:
|
||||
|
||||
https://howbigisalgorand.com/
|
||||
|
@ -281,3 +285,29 @@ index 9e224c2..f1714ea 100755
|
|||
--server ":$PORT" \
|
||||
-P "$CONNECTION_STRING" \
|
||||
--algod-net "${ALGOD_ADDR}" \
|
||||
|
||||
--
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ ! -d _sandbox ]; then
|
||||
echo We need to create it...
|
||||
git clone https://github.com/algorand/sandbox.git _sandbox
|
||||
fi
|
||||
|
||||
if [ "`grep enable-all-parameters _sandbox/images/indexer/start.sh | wc -l`" == "0" ]; then
|
||||
echo the indexer is incorrectly configured
|
||||
sed -i -e 's/dev-mode/dev-mode --enable-all-parameters/' _sandbox/images/indexer/start.sh
|
||||
echo delete all the existing docker images
|
||||
./sandbox clean
|
||||
fi
|
||||
|
||||
./sandbox up dev
|
||||
|
||||
echo "run the tests"
|
||||
cd test
|
||||
python3 test.py
|
||||
|
||||
echo "bring the sandbox down"
|
||||
cd ..
|
||||
./sandbox down
|
||||
|
|
|
@ -35,6 +35,8 @@ from algosdk.future.transaction import LogicSig
|
|||
|
||||
from token_bridge import get_token_bridge
|
||||
|
||||
from test_contract import get_test_app
|
||||
|
||||
from algosdk.v2client import indexer
|
||||
|
||||
import pprint
|
||||
|
@ -469,6 +471,40 @@ class PortalCore:
|
|||
|
||||
return response.applicationIndex
|
||||
|
||||
def createTestApp(
|
||||
self,
|
||||
client: AlgodClient,
|
||||
sender: Account,
|
||||
) -> int:
|
||||
approval, clear = get_test_app(client)
|
||||
|
||||
globalSchema = transaction.StateSchema(num_uints=4, num_byte_slices=30)
|
||||
localSchema = transaction.StateSchema(num_uints=0, num_byte_slices=16)
|
||||
|
||||
txn = transaction.ApplicationCreateTxn(
|
||||
sender=sender.getAddress(),
|
||||
on_complete=transaction.OnComplete.NoOpOC,
|
||||
approval_program=b64decode(approval["result"]),
|
||||
clear_program=b64decode(clear["result"]),
|
||||
global_schema=globalSchema,
|
||||
local_schema=localSchema,
|
||||
sp=client.suggested_params(),
|
||||
)
|
||||
|
||||
signedTxn = txn.sign(sender.getPrivateKey())
|
||||
|
||||
client.send_transaction(signedTxn)
|
||||
|
||||
response = self.waitForTransaction(client, signedTxn.get_txid())
|
||||
assert response.applicationIndex is not None and response.applicationIndex > 0
|
||||
|
||||
# Lets give it a bit of money so that it is not a "ghost" account
|
||||
txn = transaction.PaymentTxn(sender = sender.getAddress(), sp = client.suggested_params(), receiver = get_application_address(response.applicationIndex), amt = 100000)
|
||||
signedTxn = txn.sign(sender.getPrivateKey())
|
||||
client.send_transaction(signedTxn)
|
||||
|
||||
return response.applicationIndex
|
||||
|
||||
def account_exists(self, client, app_id, addr):
|
||||
try:
|
||||
ai = client.account_info(addr)
|
||||
|
@ -933,7 +969,13 @@ class PortalCore:
|
|||
|
||||
# The receiver needs to be optin in to receive the coins... Yeah, the relayer pays for this
|
||||
|
||||
addr = encode_address(bytes.fromhex(p["ToAddress"]))
|
||||
aid = 0
|
||||
|
||||
if p["ToChain"] == 8 and p["Type"] == 3:
|
||||
aid = int.from_bytes(bytes.fromhex(p["ToAddress"]), "big")
|
||||
addr = get_application_address(aid)
|
||||
else:
|
||||
addr = encode_address(bytes.fromhex(p["ToAddress"]))
|
||||
|
||||
if a != 0:
|
||||
foreign_assets.append(a)
|
||||
|
@ -954,8 +996,8 @@ class PortalCore:
|
|||
sp=sp
|
||||
))
|
||||
|
||||
if "appid" in p:
|
||||
txns[-1].foreign_apps = [p["appid"]]
|
||||
if aid != 0:
|
||||
txns[-1].foreign_apps = [aid]
|
||||
|
||||
# We need to cover the inner transactions
|
||||
if p["Fee"] != self.zeroPadBytes:
|
||||
|
@ -966,7 +1008,7 @@ class PortalCore:
|
|||
if p["Meta"] == "TokenBridge Transfer With Payload":
|
||||
txns.append(transaction.ApplicationCallTxn(
|
||||
sender=sender.getAddress(),
|
||||
index=p["appid"],
|
||||
index=int.from_bytes(bytes.fromhex(p["ToAddress"]), "big"),
|
||||
on_complete=transaction.OnComplete.NoOpOC,
|
||||
app_args=[b"completeTransfer", vaa],
|
||||
foreign_assets = foreign_assets,
|
||||
|
@ -1100,8 +1142,7 @@ class PortalCore:
|
|||
ret["Fee"] = vaa[off:(off + 32)].hex()
|
||||
off += 32
|
||||
ret["Payload"] = vaa[off:].hex()
|
||||
ret["appid"] = int.from_bytes(vaa[off:(off + 8)], "big")
|
||||
ret["body"] = vaa[off + 8:].hex()
|
||||
ret["body"] = ret["Payload"]
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -1117,7 +1158,12 @@ class PortalCore:
|
|||
pprint.pprint({"token bridge": str(self.tokenid), "address": get_application_address(self.tokenid), "emitterAddress": decode_address(get_application_address(self.tokenid)).hex()})
|
||||
|
||||
if self.devnet or self.args.testnet:
|
||||
|
||||
if self.devnet:
|
||||
print("Create test app")
|
||||
self.testid = self.createTestApp(self.client, self.foundation)
|
||||
pprint.pprint({"testapp": str(self.testid)})
|
||||
|
||||
suggestedParams = self.client.suggested_params()
|
||||
fundingAccount = self.getGenesisAccounts()[0]
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../teal
|
|
@ -0,0 +1,2 @@
|
|||
*.teal
|
||||
|
|
@ -408,7 +408,7 @@ class AlgoTest(PortalCore):
|
|||
))
|
||||
accounts=[emitter_addr, creator, c["address"]]
|
||||
|
||||
args = [b"sendTransfer", asset_id, quantity, decode_address(receiver), chain, fee]
|
||||
args = [b"sendTransfer", asset_id, quantity, receiver, chain, fee]
|
||||
if None != payload:
|
||||
args.append(payload)
|
||||
|
||||
|
@ -484,6 +484,11 @@ class AlgoTest(PortalCore):
|
|||
print("woah! optin succeeded")
|
||||
|
||||
def simple_test(self):
|
||||
|
||||
vaa = self.parseVAA(bytes.fromhex("01000000000100ddc6993585b909c3e861830244122e0daf45101663942484aa56ee2b51fa3ff016411102f993935d428a5aa0c3ace74facd60822435893b74b24fadde0fbad49006277c3fe0000000000088edf5b0e108c3a1a0a4b704cc89591f2ad8d50df24e991567e640ed720a94be200000000000000060003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800080000000000000000000000000000000000000000000000000000000000000000ff"))
|
||||
pprint.pprint(vaa)
|
||||
sys.exit(0)
|
||||
|
||||
# q = bytes.fromhex(gt.genAssetMeta(gt.guardianPrivKeys, 1, 1, 1, bytes.fromhex("4523c3F29447d1f32AEa95BEBD00383c4640F1b4"), 1, 8, b"USDC", b"CircleCoin"))
|
||||
# pprint.pprint(self.parseVAA(q))
|
||||
# sys.exit(0)
|
||||
|
@ -652,7 +657,7 @@ class AlgoTest(PortalCore):
|
|||
|
||||
print("Lets transfer that asset to one of our other accounts... first lets create the vaa")
|
||||
# paul - transferFromAlgorand
|
||||
sid = self.transferFromAlgorand(client, player2, self.testasset, 100, player3.getAddress(), 8, 0)
|
||||
sid = self.transferFromAlgorand(client, player2, self.testasset, 100, decode_address(player3.getAddress()), 8, 0)
|
||||
print("... track down the generated VAA")
|
||||
vaa = self.getVAA(client, player, sid, self.tokenid)
|
||||
print(".. and lets pass that to player3")
|
||||
|
@ -666,7 +671,7 @@ class AlgoTest(PortalCore):
|
|||
|
||||
# Lets split it into two parts... the payload and the fee
|
||||
print("Lets split it into two parts... the payload and the fee (400 should go to player, 600 should go to player3)")
|
||||
sid = self.transferFromAlgorand(client, player2, self.testasset, 1000, player3.getAddress(), 8, 400)
|
||||
sid = self.transferFromAlgorand(client, player2, self.testasset, 1000, decode_address(player3.getAddress()), 8, 400)
|
||||
print("... track down the generated VAA")
|
||||
vaa = self.getVAA(client, player, sid, self.tokenid)
|
||||
# pprint.pprint(self.parseVAA(bytes.fromhex(vaa)))
|
||||
|
@ -688,7 +693,7 @@ class AlgoTest(PortalCore):
|
|||
|
||||
# paul - transferFromAlgorand
|
||||
print("Lets transfer algo this time.... first lets create the vaa")
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 1000000, emptyAccount.getAddress(), 8, 0)
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 1000000, decode_address(emptyAccount.getAddress()), 8, 0)
|
||||
print("... track down the generated VAA")
|
||||
vaa = self.getVAA(client, player, sid, self.tokenid)
|
||||
# pprint.pprint(vaa)
|
||||
|
@ -709,7 +714,7 @@ class AlgoTest(PortalCore):
|
|||
pprint.pprint(self.getBalances(client, player3.getAddress()))
|
||||
|
||||
print("Lets transfer more algo.. split 40/60 with the relayer.. going to player3")
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 1000000, player3.getAddress(), 8, 400000)
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 1000000, decode_address(player3.getAddress()), 8, 400000)
|
||||
print("... track down the generated VAA")
|
||||
vaa = self.getVAA(client, player, sid, self.tokenid)
|
||||
print(".. and lets pass that to player3.. but use the previously empty account to relay it")
|
||||
|
@ -724,18 +729,23 @@ class AlgoTest(PortalCore):
|
|||
print("How much is in the player3 account now?")
|
||||
pprint.pprint(self.getBalances(client, player3.getAddress()))
|
||||
|
||||
print("How about a payload3")
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 100, get_application_address(self.testid), 8, 0, self.testid.to_bytes(8, "big")+b'hi mom')
|
||||
print("How about a payload3: " + self.testid.to_bytes(32, "big").hex())
|
||||
sid = self.transferFromAlgorand(client, player2, 0, 100, self.testid.to_bytes(32, "big"), 8, 0, b'hi mom')
|
||||
print("... track down the generated VAA")
|
||||
vaa = self.getVAA(client, player, sid, self.tokenid)
|
||||
|
||||
pprint.pprint(self.parseVAA(bytes.fromhex(vaa)))
|
||||
|
||||
print("testid balance before = ", self.getBalances(client, get_application_address(self.testid)))
|
||||
|
||||
print(".. Lets let player3 relay it for us")
|
||||
self.submitVAA(bytes.fromhex(vaa), client, player3, self.tokenid)
|
||||
|
||||
|
||||
print("testid balance after = ", self.getBalances(client, get_application_address(self.testid)))
|
||||
|
||||
# sys.exit(0)
|
||||
|
||||
print(".. Ok, now it is time to up the message fees")
|
||||
|
||||
bal = self.getBalances(client, get_application_address(self.coreid))
|
||||
|
|
|
@ -84,8 +84,8 @@ def approve_token_bridge(seed_amt: int, tmpl_sig: TmplSig, devMode: bool):
|
|||
return Seq(maybe, MagicAssert(maybe.hasValue()), maybe.value())
|
||||
|
||||
@Subroutine(TealType.bytes)
|
||||
def getNextAddress() -> Expr:
|
||||
maybe = AppParam.address(Gtxn[Txn.group_index() + Int(1)].application_id())
|
||||
def getAppAddress(appid : Expr) -> Expr:
|
||||
maybe = AppParam.address(appid)
|
||||
return Seq(maybe, MagicAssert(maybe.hasValue()), maybe.value())
|
||||
|
||||
def assert_common_checks(e) -> Expr:
|
||||
|
@ -456,6 +456,7 @@ def approve_token_bridge(seed_amt: int, tmpl_sig: TmplSig, devMode: bool):
|
|||
d = ScratchVar()
|
||||
zb = ScratchVar()
|
||||
action = ScratchVar()
|
||||
aid = ScratchVar()
|
||||
|
||||
return Seq([
|
||||
checkForDuplicate(),
|
||||
|
@ -517,13 +518,15 @@ def approve_token_bridge(seed_amt: int, tmpl_sig: TmplSig, devMode: bool):
|
|||
MagicAssert(Fee.load() <= Amount.load()),
|
||||
|
||||
If (action.load() == Int(3), Seq([
|
||||
aid.store(Btoi(Extract(Destination.load(), Int(24), Int(8)))), # The destination is the appid in a payload3
|
||||
tidx.store(Txn.group_index() + Int(1)),
|
||||
MagicAssert(And(
|
||||
Gtxn[tidx.load()].type_enum() == TxnType.ApplicationCall,
|
||||
Gtxn[tidx.load()].application_args[0] == Txn.application_args[0],
|
||||
Gtxn[tidx.load()].application_args[1] == Txn.application_args[1]
|
||||
Gtxn[tidx.load()].application_args[1] == Txn.application_args[1],
|
||||
Gtxn[tidx.load()].application_id() == aid.load()
|
||||
)),
|
||||
MagicAssert(getNextAddress() == Destination.load())
|
||||
Destination.store(getAppAddress(aid.load()))
|
||||
])),
|
||||
|
||||
If(OriginChain.load() == Int(8),
|
||||
|
|
|
@ -375,8 +375,6 @@ export function _parseVAAAlgorand(vaa: Uint8Array): Map<string, any> {
|
|||
ret.set("Fee", extract3(vaa, off, 32));
|
||||
off += 32;
|
||||
ret.set("Payload", vaa.slice(off));
|
||||
ret.set("appid", buf.readIntBE(off, 8));
|
||||
ret.set("body", uint8ArrayToHex(vaa.slice(off + 8)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -815,7 +813,15 @@ export async function _submitVAAAlgorand(
|
|||
|
||||
// The receiver needs to be optin in to receive the coins... Yeah, the relayer pays for this
|
||||
|
||||
const addr = encodeAddress(hexToUint8Array(parsedVAA.get("ToAddress")));
|
||||
let aid = 0;
|
||||
let addr;
|
||||
|
||||
if ((parsedVAA.get("ToChain") == 8) && (parsedVAA.get("Type") == 3)) {
|
||||
aid = Number(hexToNativeAssetBigIntAlgorand(parsedVAA.get("ToAddress")));
|
||||
addr = getApplicationAddress(aid);
|
||||
} else {
|
||||
addr = encodeAddress(hexToUint8Array(parsedVAA.get("ToAddress")));
|
||||
}
|
||||
|
||||
if (a !== 0) {
|
||||
foreignAssets.push(a);
|
||||
|
@ -863,12 +869,12 @@ export async function _submitVAAAlgorand(
|
|||
else txs[txs.length - 1].tx.fee = txs[txs.length - 1].tx.fee * 3;
|
||||
|
||||
if (meta === "TokenBridge Transfer With Payload") {
|
||||
txs[txs.length - 1].tx.appForeignApps = [parsedVAA.get("appid")];
|
||||
txs[txs.length - 1].tx.appForeignApps = [aid];
|
||||
|
||||
txs.push({
|
||||
tx: makeApplicationCallTxnFromObject({
|
||||
appArgs: [textToUint8Array("completeTransfer"), vaa],
|
||||
appIndex: parsedVAA.get("appid"),
|
||||
appIndex: aid,
|
||||
foreignAssets: foreignAssets,
|
||||
from: senderAddr,
|
||||
onComplete: OnApplicationComplete.NoOpOC,
|
||||
|
|
|
@ -27,7 +27,7 @@ import algosdk, {
|
|||
waitForConfirmation,
|
||||
} from "algosdk";
|
||||
import axios from "axios";
|
||||
import { ethers } from "ethers";
|
||||
import { BigNumber, utils, ethers } from "ethers";
|
||||
import {
|
||||
approveEth,
|
||||
attestFromAlgorand,
|
||||
|
@ -3085,5 +3085,98 @@ describe("Integration Tests", () => {
|
|||
done();
|
||||
})();
|
||||
});
|
||||
|
||||
test("testing algorand payload3", (done) => {
|
||||
(async () => {
|
||||
try {
|
||||
console.log("Starting new test of transferring ETH to algorand.");
|
||||
const tbAddr: string = getApplicationAddress(TOKEN_BRIDGE_ID);
|
||||
const decTbAddr: Uint8Array = decodeAddress(tbAddr).publicKey;
|
||||
const aa: string = uint8ArrayToHex(decTbAddr);
|
||||
|
||||
const client: algosdk.Algodv2 = getAlgoClient();
|
||||
const tempAccts: Account[] = await getTempAccounts();
|
||||
const numAccts: number = tempAccts.length;
|
||||
expect(numAccts).toBeGreaterThan(0);
|
||||
const algoWallet: Account = tempAccts[0];
|
||||
|
||||
const Fee: number = 0;
|
||||
var testapp: number = 8;
|
||||
var dest = utils.hexZeroPad(BigNumber.from(testapp).toHexString(), 32).substring(2);
|
||||
console.log("Dest address: ", dest);
|
||||
|
||||
const transferTxs = await transferFromAlgorand(
|
||||
client,
|
||||
TOKEN_BRIDGE_ID,
|
||||
CORE_ID,
|
||||
algoWallet.addr,
|
||||
BigInt(0),
|
||||
BigInt(100),
|
||||
dest,
|
||||
CHAIN_ID_ALGORAND,
|
||||
BigInt(Fee),
|
||||
hexToUint8Array("ff")
|
||||
);
|
||||
|
||||
const transferResult = await signSendAndConfirmAlgorand(
|
||||
client,
|
||||
transferTxs,
|
||||
algoWallet
|
||||
);
|
||||
const txSid = parseSequenceFromLogAlgorand(transferResult);
|
||||
console.log("Getting signed VAA...");
|
||||
const signedVaa = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
CHAIN_ID_ALGORAND,
|
||||
aa,
|
||||
txSid,
|
||||
{ transport: NodeHttpTransport() }
|
||||
);
|
||||
console.log("payload3 vaa", uint8ArrayToHex(signedVaa.vaaBytes));
|
||||
console.log("About to send back into algorand...");
|
||||
|
||||
const txns = await redeemOnAlgorand(
|
||||
client,
|
||||
TOKEN_BRIDGE_ID,
|
||||
CORE_ID,
|
||||
signedVaa.vaaBytes,
|
||||
algoWallet.addr
|
||||
);
|
||||
console.log("signSendAndConfirm...");
|
||||
|
||||
const wbefore = await getBalance(client, getApplicationAddress(testapp), BigInt(0));
|
||||
console.log(
|
||||
"test app wallet before:",
|
||||
wbefore
|
||||
);
|
||||
|
||||
await signSendAndConfirmAlgorand(
|
||||
client,
|
||||
txns,
|
||||
algoWallet
|
||||
);
|
||||
expect(
|
||||
await getIsTransferCompletedAlgorand(
|
||||
client,
|
||||
TOKEN_BRIDGE_ID,
|
||||
signedVaa.vaaBytes
|
||||
)
|
||||
).toBe(true);
|
||||
const wafter = await getBalance(client, getApplicationAddress(testapp), BigInt(0));
|
||||
console.log(
|
||||
"test app wallet after:",
|
||||
wafter
|
||||
);
|
||||
|
||||
expect(BigInt(wafter - wbefore) == BigInt(100));
|
||||
console.log("payload3 sent...");
|
||||
} catch (e) {
|
||||
console.error("new test error:", e);
|
||||
done("new test error");
|
||||
return;
|
||||
}
|
||||
done();
|
||||
})();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -393,6 +393,7 @@ export async function transferFromSolana(
|
|||
* @param receiver Receiving account
|
||||
* @param chain Reeiving chain
|
||||
* @param fee Transfer fee
|
||||
* @param payload payload for payload3 transfers
|
||||
* @returns Sequence number of confirmation
|
||||
*/
|
||||
export async function transferFromAlgorand(
|
||||
|
@ -404,7 +405,8 @@ export async function transferFromAlgorand(
|
|||
qty: bigint,
|
||||
receiver: string,
|
||||
chain: ChainId | ChainName,
|
||||
fee: bigint
|
||||
fee: bigint,
|
||||
payload : Uint8Array | null = null
|
||||
): Promise<TransactionSignerPair[]> {
|
||||
const recipientChainId = coalesceChainId(chain);
|
||||
const tokenAddr: string = getApplicationAddress(tokenBridgeId);
|
||||
|
@ -524,6 +526,9 @@ export async function transferFromAlgorand(
|
|||
bigIntToBytes(recipientChainId, 8),
|
||||
bigIntToBytes(fee, 8),
|
||||
];
|
||||
if (payload != null) {
|
||||
args.push(payload);
|
||||
}
|
||||
let acTxn = makeApplicationCallTxnFromObject({
|
||||
from: senderAddr,
|
||||
appIndex: safeBigIntToNumber(tokenBridgeId),
|
||||
|
|
Loading…
Reference in New Issue