Browse Source

sdk/js: Near refactor, added integration tests (#1648)

* near-sdk-refactor: Fix attest
                 : Fix missing function calls
                 : make near on near
                 : renamed tryHexToNativeStringNear

* near-sdk-refactor: bumped near-sdk-js version

Co-authored-by: Josh Siegel <jsiegel@jumptrading.com>
kev1n-peters 3 years ago
parent
commit
c5d2f9d54d
38 changed files with 1016 additions and 681 deletions
  1. 4 2
      Tiltfile
  2. 5 7
      clients/js/near.ts
  3. 2 0
      cosmwasm/tools/deploy.js
  4. 1 1
      devnet/eth-devnet.yaml
  5. 1 1
      devnet/eth-devnet2.yaml
  6. 3 3
      devnet/near-devnet.yaml
  7. 29 0
      ethereum/scripts/register_near_chain.js
  8. 28 0
      near/Dockerfile.deploy
  9. 89 86
      near/devnet_deploy.ts
  10. 1 3
      near/mainnet_deploy.ts
  11. 14 22
      near/package-lock.json
  12. 1 1
      near/package.json
  13. 21 17
      near/test/attester.ts
  14. 3 5
      near/test/deposit.ts
  15. 33 46
      near/test/foo.ts
  16. 38 69
      near/test/p3.ts
  17. 155 98
      near/test/sdk.ts
  18. 16 7
      near/test/transferFromNear.ts
  19. 7 5
      near/test/transferToNear.ts
  20. 9 19
      sdk/js/package-lock.json
  21. 1 1
      sdk/js/package.json
  22. 8 3
      sdk/js/src/bridge/getEmitterAddress.ts
  23. 11 7
      sdk/js/src/bridge/parseSequenceFromLog.ts
  24. 1 1
      sdk/js/src/nft_bridge/getIsTransferCompleted.ts
  25. 2 0
      sdk/js/src/token_bridge/__tests__/consts.ts
  26. 223 0
      sdk/js/src/token_bridge/__tests__/near-integration.ts
  27. 34 56
      sdk/js/src/token_bridge/attest.ts
  28. 22 28
      sdk/js/src/token_bridge/createWrapped.ts
  29. 13 12
      sdk/js/src/token_bridge/getForeignAsset.ts
  30. 7 15
      sdk/js/src/token_bridge/getIsTransferCompleted.ts
  31. 0 6
      sdk/js/src/token_bridge/getIsWrappedAsset.ts
  32. 17 14
      sdk/js/src/token_bridge/getOriginalAsset.ts
  33. 49 53
      sdk/js/src/token_bridge/redeem.ts
  34. 79 88
      sdk/js/src/token_bridge/transfer.ts
  35. 17 5
      sdk/js/src/utils/array.ts
  36. 69 0
      sdk/js/src/utils/near.ts
  37. 1 0
      solana/devnet_setup.sh
  38. 2 0
      terra/tools/deploy.js

+ 4 - 2
Tiltfile

@@ -124,6 +124,7 @@ docker_build(
     context = ".",
     context = ".",
     dockerfile = "Dockerfile.node",
     dockerfile = "Dockerfile.node",
     target = "build",
     target = "build",
+    ignore=["./sdk/js"]
 )
 )
 
 
 def command_with_dlv(argv):
 def command_with_dlv(argv):
@@ -697,9 +698,10 @@ if near:
     )
     )
 
 
     docker_build(
     docker_build(
-        ref = "near-contracts",
+        ref = "near-deploy",
         context = "near",
         context = "near",
-        dockerfile = "near/Dockerfile.contracts",
+        dockerfile = "near/Dockerfile.deploy",
+        ignore = ["./test"]
     )
     )
 
 
     k8s_resource(
     k8s_resource(

+ 5 - 7
clients/js/near.ts

@@ -14,7 +14,7 @@ export async function execute_near(
   let contracts = CONTRACTS[network]["near"];
   let contracts = CONTRACTS[network]["near"];
 
 
   let target_contract = "";
   let target_contract = "";
-  let numSubmits = 1
+  let numSubmits = 1;
 
 
   switch (payload.module) {
   switch (payload.module) {
     case "Core":
     case "Core":
@@ -37,7 +37,7 @@ export async function execute_near(
       if (contracts.nft_bridge === undefined) {
       if (contracts.nft_bridge === undefined) {
         throw new Error("NFT bridge not supported yet for near");
         throw new Error("NFT bridge not supported yet for near");
       }
       }
-      numSubmits = 2
+      numSubmits = 2;
       target_contract = contracts.nft_bridge;
       target_contract = contracts.nft_bridge;
       switch (payload.type) {
       switch (payload.type) {
         case "ContractUpgrade":
         case "ContractUpgrade":
@@ -57,7 +57,7 @@ export async function execute_near(
       if (contracts.token_bridge === undefined) {
       if (contracts.token_bridge === undefined) {
         throw new Error("Token bridge not supported yet for near");
         throw new Error("Token bridge not supported yet for near");
       }
       }
-      numSubmits = 2
+      numSubmits = 2;
       target_contract = contracts.token_bridge;
       target_contract = contracts.token_bridge;
       switch (payload.type) {
       switch (payload.type) {
         case "ContractUpgrade":
         case "ContractUpgrade":
@@ -89,9 +89,7 @@ export async function execute_near(
   keyStore.setKey(n.networkId, n.deployerAccount, key);
   keyStore.setKey(n.networkId, n.deployerAccount, key);
 
 
   let near = await nearAPI.connect({
   let near = await nearAPI.connect({
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: n.networkId,
     networkId: n.networkId,
     nodeUrl: n.rpc,
     nodeUrl: n.rpc,
   });
   });
@@ -111,7 +109,7 @@ export async function execute_near(
 
 
   if (numSubmits <= 1) {
   if (numSubmits <= 1) {
     console.log("Hash: " + result1.transaction.hash);
     console.log("Hash: " + result1.transaction.hash);
-    return
+    return;
   }
   }
 
 
   // You have to feed a vaa twice into the contract (two submits),
   // You have to feed a vaa twice into the contract (two submits),

+ 2 - 0
cosmwasm/tools/deploy.js

@@ -216,6 +216,8 @@ const contract_registrations = {
     process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA,
     process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA,
     // TERRA
     // TERRA
     process.env.REGISTER_TERRA_TOKEN_BRIDGE_VAA,
     process.env.REGISTER_TERRA_TOKEN_BRIDGE_VAA,
+    // NEAR
+    process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA,
   ],
   ],
 };
 };
 
 

+ 1 - 1
devnet/eth-devnet.yaml

@@ -53,7 +53,7 @@ spec:
           command:
           command:
             - /bin/sh
             - /bin/sh
             - -c
             - -c
-            - "npm run migrate && npx truffle exec scripts/deploy_test_token.js && npm run deploy-batched-vaa-sender && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_bsc_chain.js && npx truffle exec scripts/register_algo_chain.js && nc -lkp 2000 0.0.0.0"
+            - "npm run migrate && npx truffle exec scripts/deploy_test_token.js && npm run deploy-batched-vaa-sender && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_bsc_chain.js && npx truffle exec scripts/register_algo_chain.js && npx truffle exec scripts/register_near_chain.js && nc -lkp 2000 0.0.0.0"
           readinessProbe:
           readinessProbe:
             periodSeconds: 1
             periodSeconds: 1
             failureThreshold: 300
             failureThreshold: 300

+ 1 - 1
devnet/eth-devnet2.yaml

@@ -55,7 +55,7 @@ spec:
           command:
           command:
             - /bin/sh
             - /bin/sh
             - -c
             - -c
-            - "sed -i 's/CHAIN_ID=0x2/CHAIN_ID=0x4/g;s/EVM_CHAIN_ID=1/EVM_CHAIN_ID=1397/g' .env && npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_eth_chain.js && npx truffle exec scripts/register_algo_chain.js && nc -lkp 2000 0.0.0.0"
+            - "sed -i 's/CHAIN_ID=0x2/CHAIN_ID=0x4/g;s/EVM_CHAIN_ID=1/EVM_CHAIN_ID=1397/g' .env && npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_terra2_chain.js && npx truffle exec scripts/register_eth_chain.js && npx truffle exec scripts/register_algo_chain.js && npx truffle exec scripts/register_near_chain.js && nc -lkp 2000 0.0.0.0"
           readinessProbe:
           readinessProbe:
             periodSeconds: 1
             periodSeconds: 1
             failureThreshold: 300
             failureThreshold: 300

+ 3 - 3
devnet/near-devnet.yaml

@@ -46,12 +46,12 @@ spec:
           readinessProbe:
           readinessProbe:
             tcpSocket:
             tcpSocket:
               port: 3030
               port: 3030
-        - name: near-contracts
-          image: near-contracts
+        - name: near-deploy
+          image: near-deploy
           command:
           command:
             - /bin/sh
             - /bin/sh
             - -c
             - -c
-            - "sh devnet_deploy.sh && touch success && sleep infinity"
+            - "sh /app/devnet_deploy.sh && touch success && sleep infinity"
           readinessProbe:
           readinessProbe:
             tcpSocket:
             tcpSocket:
               port: 3030
               port: 3030

+ 29 - 0
ethereum/scripts/register_near_chain.js

@@ -0,0 +1,29 @@
+// run this script with truffle exec
+
+const jsonfile = require("jsonfile");
+const TokenBridge = artifacts.require("TokenBridge");
+const BridgeImplementationFullABI = jsonfile.readFileSync(
+    "../build/contracts/BridgeImplementation.json"
+).abi;
+const nearTokenBridgeVAA = process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA;
+
+module.exports = async function (callback) {
+    try {
+        const accounts = await web3.eth.getAccounts();
+        const tokenBridge = new web3.eth.Contract(
+            BridgeImplementationFullABI,
+            TokenBridge.address
+        );
+
+        // Register the near token bridge endpoint
+        await tokenBridge.methods.registerChain("0x" + nearTokenBridgeVAA).send({
+            value: 0,
+            from: accounts[0],
+            gasLimit: 2000000,
+        });
+
+        callback();
+    } catch (e) {
+        callback(e);
+    }
+};

+ 28 - 0
near/Dockerfile.deploy

@@ -0,0 +1,28 @@
+FROM debian@sha256:2ce44bbc00a79113c296d9d25524e15d423b23303fdbbe20190d2f96e0aeb251 as build
+
+RUN apt-get update && apt-get install -y curl \
+    make \
+    build-essential
+
+WORKDIR /app
+COPY ./setup-rust.sh .
+RUN ./setup-rust.sh
+
+COPY . .
+
+RUN ./build-contracts.sh
+
+FROM node:16-alpine@sha256:004dbac84fed48e20f9888a23e32fa7cf83c2995e174a78d41d9a9dd1e051a20 AS deploy
+
+WORKDIR /app
+COPY package.json .
+COPY package-lock.json .
+COPY .env .
+COPY devnet_deploy.sh .
+COPY devnet_deploy.ts .
+COPY --from=build /app/contracts/*/target/wasm32-unknown-unknown/release/*.wasm .
+
+# mount the buildkit cache on npm's cache dir, install dependencies
+RUN --mount=type=cache,target=/root/.npm npm ci --production
+
+

+ 89 - 86
near/devnet_deploy.ts

@@ -59,9 +59,7 @@ async function initNear() {
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
 
 
   let near = await nearAPI.connect({
   let near = await nearAPI.connect({
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: config.networkId,
     networkId: config.networkId,
     nodeUrl: config.nodeUrl,
     nodeUrl: config.nodeUrl,
   });
   });
@@ -76,21 +74,25 @@ async function initNear() {
   );
   );
 
 
   if (e === "sandbox") {
   if (e === "sandbox") {
-      let da = parseSeedPhrase("weather opinion slam purpose access artefact word orbit matter rice poem badge");
-      console.log(da);
-      let resp = await masterAccount.createAccount(
-          "devnet.test.near",
-          da.publicKey,
-          new BN(10).pow(new BN(27))
-      );
-
-      console.log("devnet.test.near funded");
+    let da = parseSeedPhrase(
+      "weather opinion slam purpose access artefact word orbit matter rice poem badge"
+    );
+    console.log(da);
+    let resp = await masterAccount.createAccount(
+      "devnet.test.near",
+      da.publicKey,
+      new BN(10).pow(new BN(27))
+    );
+
+    console.log("devnet.test.near funded");
   }
   }
 
 
   const wormholeContract = await fs.readFileSync("./near_wormhole.wasm");
   const wormholeContract = await fs.readFileSync("./near_wormhole.wasm");
   const tokenContract = await fs.readFileSync("./near_token_bridge.wasm");
   const tokenContract = await fs.readFileSync("./near_token_bridge.wasm");
   const nftContract = await fs.readFileSync("./near_nft_bridge.wasm");
   const nftContract = await fs.readFileSync("./near_nft_bridge.wasm");
-  const testContract = await fs.readFileSync("./near_mock_bridge_integration.wasm");
+  const testContract = await fs.readFileSync(
+    "./near_mock_bridge_integration.wasm"
+  );
 
 
   let wormholeAccount: any;
   let wormholeAccount: any;
 
 
@@ -108,27 +110,27 @@ async function initNear() {
       new BN("20000000000000000000000000")
       new BN("20000000000000000000000000")
     );
     );
 
 
-      await wormholeAccount.functionCall({
-        contractId: config.wormholeAccount,
-        methodName: "register_emitter",
-        args: {emitter: config.tokenAccount},
-        attachedDeposit: new BN("30000000000000000000000"),
-        gas: new BN("100000000000000"),
-      })
-      await wormholeAccount.functionCall({
-        contractId: config.wormholeAccount,
-        methodName: "register_emitter",
-        args: {emitter: config.testAccount},
-        attachedDeposit: new BN("30000000000000000000000"),
-        gas: new BN("100000000000000"),
-      })
-      await wormholeAccount.functionCall({
-        contractId: config.wormholeAccount,
-        methodName: "register_emitter",
-        args: {emitter: config.nftAccount},
-        attachedDeposit: new BN("30000000000000000000000"),
-        gas: new BN("100000000000000"),
-      })
+    await wormholeAccount.functionCall({
+      contractId: config.wormholeAccount,
+      methodName: "register_emitter",
+      args: { emitter: config.tokenAccount },
+      attachedDeposit: new BN("30000000000000000000000"),
+      gas: new BN("100000000000000"),
+    });
+    await wormholeAccount.functionCall({
+      contractId: config.wormholeAccount,
+      methodName: "register_emitter",
+      args: { emitter: config.testAccount },
+      attachedDeposit: new BN("30000000000000000000000"),
+      gas: new BN("100000000000000"),
+    });
+    await wormholeAccount.functionCall({
+      contractId: config.wormholeAccount,
+      methodName: "register_emitter",
+      args: { emitter: config.nftAccount },
+      attachedDeposit: new BN("30000000000000000000000"),
+      gas: new BN("100000000000000"),
+    });
   } else {
   } else {
     // This uses the standard API to redeploy ... we can migrate over to the vaa's later
     // This uses the standard API to redeploy ... we can migrate over to the vaa's later
     console.log(
     console.log(
@@ -140,18 +142,17 @@ async function initNear() {
     );
     );
     await wormholeAccount.deployContract(wormholeContract);
     await wormholeAccount.deployContract(wormholeContract);
 
 
-//    console.log("migrating " + config.wormholeAccount);
-//    console.log(
-//      await wormholeAccount.functionCall({
-//        contractId: config.wormholeAccount,
-//        methodName: "migrate",
-//        args: {},
-//        attachedDeposit: new BN(1),
-//        gas: new BN("100000000000000"),
-//      })
-//    );
-//    console.log("done migrating " + config.tokenAccount);
-
+    //    console.log("migrating " + config.wormholeAccount);
+    //    console.log(
+    //      await wormholeAccount.functionCall({
+    //        contractId: config.wormholeAccount,
+    //        methodName: "migrate",
+    //        args: {},
+    //        attachedDeposit: new BN(1),
+    //        gas: new BN("100000000000000"),
+    //      })
+    //    );
+    //    console.log("done migrating " + config.tokenAccount);
   }
   }
 
 
   let tokenAccount: any;
   let tokenAccount: any;
@@ -170,19 +171,21 @@ async function initNear() {
     tokenAccount = new nearAPI.Account(near.connection, config.tokenAccount);
     tokenAccount = new nearAPI.Account(near.connection, config.tokenAccount);
     await tokenAccount.deployContract(tokenContract);
     await tokenAccount.deployContract(tokenContract);
 
 
-    console.log( await tokenAccount.viewFunction(config.tokenAccount, "emitter", {}));
-
-//    console.log("migrating " + config.tokenAccount);
-//    console.log(
-//      await tokenAccount.functionCall({
-//        contractId: config.tokenAccount,
-//        methodName: "migrate",
-//        args: {},
-//        attachedDeposit: new BN(1),
-//        gas: new BN("100000000000000"),
-//      })
-//    );
-//    console.log("done migrating " + config.tokenAccount);
+    console.log(
+      await tokenAccount.viewFunction(config.tokenAccount, "emitter", {})
+    );
+
+    //    console.log("migrating " + config.tokenAccount);
+    //    console.log(
+    //      await tokenAccount.functionCall({
+    //        contractId: config.tokenAccount,
+    //        methodName: "migrate",
+    //        args: {},
+    //        attachedDeposit: new BN(1),
+    //        gas: new BN("100000000000000"),
+    //      })
+    //    );
+    //    console.log("done migrating " + config.tokenAccount);
   }
   }
 
 
   let nftAccount: any;
   let nftAccount: any;
@@ -286,33 +289,33 @@ async function initNear() {
     });
     });
   }
   }
 
 
-//   for (const line of vaasNFT) {
-//     console.log("Submitting to " + config.nftAccount + ": " + line);
-// 
-//     try {
-//       await masterAccount.functionCall({
-//         contractId: config.nftAccount,
-//         methodName: "submit_vaa",
-//         args: {
-//           vaa: line,
-//         },
-//         attachedDeposit: new BN("30000000000000000000000"),
-//         gas: new BN("300000000000000"),
-//       });
-// 
-//       await masterAccount.functionCall({
-//         contractId: config.nftAccount,
-//         methodName: "submit_vaa",
-//         args: {
-//           vaa: line,
-//         },
-//         attachedDeposit: new BN("30000000000000000000000"),
-//         gas: new BN("300000000000000"),
-//       });
-//     } catch {
-//       console.log("Exception thrown.. ");
-//     }
-//   }
+  //   for (const line of vaasNFT) {
+  //     console.log("Submitting to " + config.nftAccount + ": " + line);
+  //
+  //     try {
+  //       await masterAccount.functionCall({
+  //         contractId: config.nftAccount,
+  //         methodName: "submit_vaa",
+  //         args: {
+  //           vaa: line,
+  //         },
+  //         attachedDeposit: new BN("30000000000000000000000"),
+  //         gas: new BN("300000000000000"),
+  //       });
+  //
+  //       await masterAccount.functionCall({
+  //         contractId: config.nftAccount,
+  //         methodName: "submit_vaa",
+  //         args: {
+  //           vaa: line,
+  //         },
+  //         attachedDeposit: new BN("30000000000000000000000"),
+  //         gas: new BN("300000000000000"),
+  //       });
+  //     } catch {
+  //       console.log("Exception thrown.. ");
+  //     }
+  //   }
 
 
   console.log("nft bridge booted");
   console.log("nft bridge booted");
 
 

+ 1 - 3
near/mainnet_deploy.ts

@@ -51,9 +51,7 @@ async function initNear() {
   keyStore.setKey(config.networkId, config.portalAccount, portalMasterKey);
   keyStore.setKey(config.networkId, config.portalAccount, portalMasterKey);
 
 
   let near = await nearAPI.connect({
   let near = await nearAPI.connect({
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: config.networkId,
     networkId: config.networkId,
     nodeUrl: config.nodeUrl,
     nodeUrl: config.nodeUrl,
   });
   });

+ 14 - 22
near/package-lock.json

@@ -18,6 +18,7 @@
         "env-cmd": "^10.1.0",
         "env-cmd": "^10.1.0",
         "ethers": "^5.6.5",
         "ethers": "^5.6.5",
         "near-api-js": "^0.43.1",
         "near-api-js": "^0.43.1",
+        "near-seed-phrase": "^0.2.0",
         "prop-types": "^15.7.2",
         "prop-types": "^15.7.2",
         "react": "^17.0.2",
         "react": "^17.0.2",
         "react-dom": "^17.0.2",
         "react-dom": "^17.0.2",
@@ -35,7 +36,6 @@
         "@types/prompt": "^1.1.2",
         "@types/prompt": "^1.1.2",
         "cssnano": "^5.0.7",
         "cssnano": "^5.0.7",
         "gh-pages": "^3.1.0",
         "gh-pages": "^3.1.0",
-        "near-seed-phrase": "^0.2.0",
         "parcel-bundler": "^1.12.5",
         "parcel-bundler": "^1.12.5",
         "postcss": "^8.3.6",
         "postcss": "^8.3.6",
         "prompt": "^1.3.0",
         "prompt": "^1.3.0",
@@ -44,11 +44,12 @@
     },
     },
     "../sdk/js": {
     "../sdk/js": {
       "name": "@certusone/wormhole-sdk",
       "name": "@certusone/wormhole-sdk",
-      "version": "0.6.2",
+      "version": "0.6.3",
       "license": "Apache-2.0",
       "license": "Apache-2.0",
       "dependencies": {
       "dependencies": {
-        "@certusone/wormhole-sdk-proto-web": "^0.0.3",
+        "@certusone/wormhole-sdk-proto-web": "^0.0.5",
         "@certusone/wormhole-sdk-wasm": "^0.0.1",
         "@certusone/wormhole-sdk-wasm": "^0.0.1",
+        "@injectivelabs/sdk-ts": "^1.0.75",
         "@solana/spl-token": "^0.1.8",
         "@solana/spl-token": "^0.1.8",
         "@solana/web3.js": "^1.24.0",
         "@solana/web3.js": "^1.24.0",
         "@terra-money/terra.js": "^3.1.3",
         "@terra-money/terra.js": "^3.1.3",
@@ -56,10 +57,12 @@
         "axios": "^0.24.0",
         "axios": "^0.24.0",
         "bech32": "^2.0.0",
         "bech32": "^2.0.0",
         "js-base64": "^3.6.1",
         "js-base64": "^3.6.1",
-        "near-api-js": "^0.45.1"
+        "near-api-js": "^0.44.2"
       },
       },
       "devDependencies": {
       "devDependencies": {
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
+        "@injectivelabs/networks": "^1.0.12",
+        "@injectivelabs/tx-ts": "^1.0.22",
         "@openzeppelin/contracts": "^4.2.0",
         "@openzeppelin/contracts": "^4.2.0",
         "@typechain/ethers-v5": "^7.0.1",
         "@typechain/ethers-v5": "^7.0.1",
         "@types/jest": "^27.0.2",
         "@types/jest": "^27.0.2",
@@ -3319,7 +3322,6 @@
       "version": "3.0.2",
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
       "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
       "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "@types/node": "11.11.6",
         "@types/node": "11.11.6",
         "create-hash": "^1.1.0",
         "create-hash": "^1.1.0",
@@ -3331,7 +3333,6 @@
       "version": "1.0.7",
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/bip39-light/-/bip39-light-1.0.7.tgz",
       "resolved": "https://registry.npmjs.org/bip39-light/-/bip39-light-1.0.7.tgz",
       "integrity": "sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==",
       "integrity": "sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "create-hash": "^1.1.0",
         "create-hash": "^1.1.0",
         "pbkdf2": "^3.0.9"
         "pbkdf2": "^3.0.9"
@@ -3340,8 +3341,7 @@
     "node_modules/bip39/node_modules/@types/node": {
     "node_modules/bip39/node_modules/@types/node": {
       "version": "11.11.6",
       "version": "11.11.6",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
-      "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==",
-      "dev": true
+      "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
     },
     },
     "node_modules/blakejs": {
     "node_modules/blakejs": {
       "version": "1.2.1",
       "version": "1.2.1",
@@ -9180,7 +9180,6 @@
       "version": "1.2.1",
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/near-hd-key/-/near-hd-key-1.2.1.tgz",
       "resolved": "https://registry.npmjs.org/near-hd-key/-/near-hd-key-1.2.1.tgz",
       "integrity": "sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==",
       "integrity": "sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "bip39": "3.0.2",
         "bip39": "3.0.2",
         "create-hmac": "1.1.7",
         "create-hmac": "1.1.7",
@@ -9191,7 +9190,6 @@
       "version": "0.2.0",
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/near-seed-phrase/-/near-seed-phrase-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/near-seed-phrase/-/near-seed-phrase-0.2.0.tgz",
       "integrity": "sha512-NpmrnejpY1AdlRpDZ0schJQJtfBaoUheRfiYtQpcq9TkwPgqKZCRULV5L3hHmLc0ep7KRtikbPQ9R2ztN/3cyQ==",
       "integrity": "sha512-NpmrnejpY1AdlRpDZ0schJQJtfBaoUheRfiYtQpcq9TkwPgqKZCRULV5L3hHmLc0ep7KRtikbPQ9R2ztN/3cyQ==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "bip39-light": "^1.0.7",
         "bip39-light": "^1.0.7",
         "bs58": "^4.0.1",
         "bs58": "^4.0.1",
@@ -9203,7 +9201,6 @@
       "version": "3.0.9",
       "version": "3.0.9",
       "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
       "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
       "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
       "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "safe-buffer": "^5.0.1"
         "safe-buffer": "^5.0.1"
       }
       }
@@ -9212,7 +9209,6 @@
       "version": "4.0.1",
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
       "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
       "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
       "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "base-x": "^3.0.2"
         "base-x": "^3.0.2"
       }
       }
@@ -16625,9 +16621,12 @@
     "@certusone/wormhole-sdk": {
     "@certusone/wormhole-sdk": {
       "version": "file:../sdk/js",
       "version": "file:../sdk/js",
       "requires": {
       "requires": {
-        "@certusone/wormhole-sdk-proto-web": "^0.0.3",
+        "@certusone/wormhole-sdk-proto-web": "^0.0.5",
         "@certusone/wormhole-sdk-wasm": "^0.0.1",
         "@certusone/wormhole-sdk-wasm": "^0.0.1",
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
+        "@injectivelabs/networks": "^1.0.12",
+        "@injectivelabs/sdk-ts": "^1.0.75",
+        "@injectivelabs/tx-ts": "^1.0.22",
         "@openzeppelin/contracts": "^4.2.0",
         "@openzeppelin/contracts": "^4.2.0",
         "@solana/spl-token": "^0.1.8",
         "@solana/spl-token": "^0.1.8",
         "@solana/web3.js": "^1.24.0",
         "@solana/web3.js": "^1.24.0",
@@ -16644,7 +16643,7 @@
         "ethers": "^5.6.8",
         "ethers": "^5.6.8",
         "jest": "^27.3.1",
         "jest": "^27.3.1",
         "js-base64": "^3.6.1",
         "js-base64": "^3.6.1",
-        "near-api-js": "^0.45.1",
+        "near-api-js": "^0.44.2",
         "prettier": "^2.3.2",
         "prettier": "^2.3.2",
         "ts-jest": "^27.0.7",
         "ts-jest": "^27.0.7",
         "tslint": "^6.1.3",
         "tslint": "^6.1.3",
@@ -17742,7 +17741,6 @@
       "version": "3.0.2",
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
       "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
       "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
-      "dev": true,
       "requires": {
       "requires": {
         "@types/node": "11.11.6",
         "@types/node": "11.11.6",
         "create-hash": "^1.1.0",
         "create-hash": "^1.1.0",
@@ -17753,8 +17751,7 @@
         "@types/node": {
         "@types/node": {
           "version": "11.11.6",
           "version": "11.11.6",
           "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
           "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
-          "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==",
-          "dev": true
+          "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
         }
         }
       }
       }
     },
     },
@@ -17762,7 +17759,6 @@
       "version": "1.0.7",
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/bip39-light/-/bip39-light-1.0.7.tgz",
       "resolved": "https://registry.npmjs.org/bip39-light/-/bip39-light-1.0.7.tgz",
       "integrity": "sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==",
       "integrity": "sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==",
-      "dev": true,
       "requires": {
       "requires": {
         "create-hash": "^1.1.0",
         "create-hash": "^1.1.0",
         "pbkdf2": "^3.0.9"
         "pbkdf2": "^3.0.9"
@@ -22478,7 +22474,6 @@
       "version": "1.2.1",
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/near-hd-key/-/near-hd-key-1.2.1.tgz",
       "resolved": "https://registry.npmjs.org/near-hd-key/-/near-hd-key-1.2.1.tgz",
       "integrity": "sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==",
       "integrity": "sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==",
-      "dev": true,
       "requires": {
       "requires": {
         "bip39": "3.0.2",
         "bip39": "3.0.2",
         "create-hmac": "1.1.7",
         "create-hmac": "1.1.7",
@@ -22489,7 +22484,6 @@
       "version": "0.2.0",
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/near-seed-phrase/-/near-seed-phrase-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/near-seed-phrase/-/near-seed-phrase-0.2.0.tgz",
       "integrity": "sha512-NpmrnejpY1AdlRpDZ0schJQJtfBaoUheRfiYtQpcq9TkwPgqKZCRULV5L3hHmLc0ep7KRtikbPQ9R2ztN/3cyQ==",
       "integrity": "sha512-NpmrnejpY1AdlRpDZ0schJQJtfBaoUheRfiYtQpcq9TkwPgqKZCRULV5L3hHmLc0ep7KRtikbPQ9R2ztN/3cyQ==",
-      "dev": true,
       "requires": {
       "requires": {
         "bip39-light": "^1.0.7",
         "bip39-light": "^1.0.7",
         "bs58": "^4.0.1",
         "bs58": "^4.0.1",
@@ -22501,7 +22495,6 @@
           "version": "3.0.9",
           "version": "3.0.9",
           "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
           "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
           "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
           "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
-          "dev": true,
           "requires": {
           "requires": {
             "safe-buffer": "^5.0.1"
             "safe-buffer": "^5.0.1"
           }
           }
@@ -22510,7 +22503,6 @@
           "version": "4.0.1",
           "version": "4.0.1",
           "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
           "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
           "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
           "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
-          "dev": true,
           "requires": {
           "requires": {
             "base-x": "^3.0.2"
             "base-x": "^3.0.2"
           }
           }

+ 1 - 1
near/package.json

@@ -21,6 +21,7 @@
     "env-cmd": "^10.1.0",
     "env-cmd": "^10.1.0",
     "ethers": "^5.6.5",
     "ethers": "^5.6.5",
     "near-api-js": "^0.43.1",
     "near-api-js": "^0.43.1",
+    "near-seed-phrase": "^0.2.0",
     "prop-types": "^15.7.2",
     "prop-types": "^15.7.2",
     "react": "^17.0.2",
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
     "react-dom": "^17.0.2",
@@ -38,7 +39,6 @@
     "@types/prompt": "^1.1.2",
     "@types/prompt": "^1.1.2",
     "cssnano": "^5.0.7",
     "cssnano": "^5.0.7",
     "gh-pages": "^3.1.0",
     "gh-pages": "^3.1.0",
-    "near-seed-phrase": "^0.2.0",
     "parcel-bundler": "^1.12.5",
     "parcel-bundler": "^1.12.5",
     "postcss": "^8.3.6",
     "postcss": "^8.3.6",
     "prompt": "^1.3.0",
     "prompt": "^1.3.0",

+ 21 - 17
near/test/attester.ts

@@ -18,14 +18,13 @@ import {
 } from "@certusone/wormhole-sdk/node_modules/near-api-js";
 } from "@certusone/wormhole-sdk/node_modules/near-api-js";
 
 
 import {
 import {
-  CHAIN_ID_ETH,
   CHAIN_ID_NEAR,
   CHAIN_ID_NEAR,
   CONTRACTS,
   CONTRACTS,
   attestTokenFromNear,
   attestTokenFromNear,
   getSignedVAAWithRetry,
   getSignedVAAWithRetry,
-  hexToUint8Array,
-  transferTokenFromNear,
   uint8ArrayToHex,
   uint8ArrayToHex,
+  parseSequenceFromLogNear,
+  getEmitterAddressNear,
 } from "@certusone/wormhole-sdk";
 } from "@certusone/wormhole-sdk";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 // @ts-ignore
 // @ts-ignore
@@ -75,17 +74,12 @@ async function transferTest() {
   // connect to near...
   // connect to near...
   let near = await nearConnect({
   let near = await nearConnect({
     headers: {},
     headers: {},
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: networkId as string,
     networkId: networkId as string,
     nodeUrl: nearNodeUrl as string,
     nodeUrl: nearNodeUrl as string,
   });
   });
 
 
-  console.log(
-    "Attesting",
-    NEAR_TOKEN_ADDRESS,
-  );
+  console.log("Attesting", NEAR_TOKEN_ADDRESS);
 
 
   prompt.message = "";
   prompt.message = "";
   const { input } = await prompt.get({
   const { input } = await prompt.get({
@@ -104,20 +98,30 @@ async function transferTest() {
     near.connection,
     near.connection,
     process.env.NEAR_ACCOUNT as string
     process.env.NEAR_ACCOUNT as string
   );
   );
+  const provider = near.connection.provider;
 
 
-  let [sequence, emitterAddress] = await attestTokenFromNear(
-    userAccount,
+  const attestMsgs = await attestTokenFromNear(
+    provider,
     CONTRACTS.MAINNET.near.core,
     CONTRACTS.MAINNET.near.core,
     CONTRACTS.MAINNET.near.token_bridge,
     CONTRACTS.MAINNET.near.token_bridge,
     NEAR_TOKEN_ADDRESS
     NEAR_TOKEN_ADDRESS
   );
   );
-
-  if (sequence === -1) {
+  let attestOutcome;
+  for (const msg of attestMsgs) {
+    attestOutcome = await userAccount.functionCall(msg);
+  }
+  const sequence = parseSequenceFromLogNear(attestOutcome);
+  if (sequence === null) {
     console.log("No sequence found, check above for error");
     console.log("No sequence found, check above for error");
     process.exit(1);
     process.exit(1);
   }
   }
 
 
-  console.log("emitterAddress:", emitterAddress, "sequence:", sequence);
+  console.log(
+    "emitterAddress:",
+    getEmitterAddressNear(CONTRACTS.MAINNET.near.token_bridge),
+    "sequence:",
+    sequence
+  );
 
 
   console.log(
   console.log(
     `If this script hangs, try https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/15/${emitterAddress}/${sequence.toString()}`
     `If this script hangs, try https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/15/${emitterAddress}/${sequence.toString()}`
@@ -126,8 +130,8 @@ async function transferTest() {
   const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
   const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     WORMHOLE_RPC_HOSTS,
     WORMHOLE_RPC_HOSTS,
     CHAIN_ID_NEAR,
     CHAIN_ID_NEAR,
-    emitterAddress,
-    sequence.toString(),
+    getEmitterAddressNear(CONTRACTS.MAINNET.near.token_bridge),
+    sequence,
     {
     {
       transport: NodeHttpTransport(),
       transport: NodeHttpTransport(),
     }
     }

+ 3 - 5
near/test/deposit.ts

@@ -81,9 +81,7 @@ async function transferTest() {
   // connect to near...
   // connect to near...
   let near = await nearConnect({
   let near = await nearConnect({
     headers: {},
     headers: {},
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: networkId as string,
     networkId: networkId as string,
     nodeUrl: nearNodeUrl as string,
     nodeUrl: nearNodeUrl as string,
   });
   });
@@ -129,8 +127,8 @@ async function transferTest() {
     console.log("account already registered");
     console.log("account already registered");
   }
   }
 
 
-    // like this
-    await redeemOnNear(userAccount, token_bridge, hexToUint8Array(trans))
+  // like this
+  await redeemOnNear(userAccount, token_bridge, hexToUint8Array(trans));
 }
 }
 
 
 transferTest();
 transferTest();

+ 33 - 46
near/test/foo.ts

@@ -1,46 +1,16 @@
 const nearAPI = require("near-api-js");
 const nearAPI = require("near-api-js");
-const BN = require("bn.js");
-const fs = require("fs");
-const fetch = require("node-fetch");
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 
 
 import {
 import {
-  CONTRACTS,
   attestNearFromNear,
   attestNearFromNear,
-  attestTokenFromNear,
-  attestFromAlgorand,
-  createWrappedOnAlgorand,
   tryNativeToUint8Array,
   tryNativeToUint8Array,
-  createWrappedOnNear,
-  getEmitterAddressAlgorand,
-  getForeignAssetAlgorand,
-  getForeignAssetNear,
-  getIsTransferCompletedNear,
-  getIsWrappedAssetNear,
-  getOriginalAssetNear,
   getSignedVAAWithRetry,
   getSignedVAAWithRetry,
-  redeemOnAlgorand,
-  redeemOnNear,
-  transferFromAlgorand,
   transferNearFromNear,
   transferNearFromNear,
-  transferTokenFromNear,
+  parseSequenceFromLogNear,
+  getEmitterAddressNear,
 } from "@certusone/wormhole-sdk";
 } from "@certusone/wormhole-sdk";
 
 
-const wh = require("@certusone/wormhole-sdk");
-
-import {
-  CHAIN_ID_ALGORAND,
-  CHAIN_ID_NEAR,
-  ChainId,
-  ChainName,
-  textToHexString,
-  textToUint8Array,
-} from "@certusone/wormhole-sdk/lib/cjs/utils";
-
-import {
-  _parseVAAAlgorand,
-} from "@certusone/wormhole-sdk/lib/cjs/algorand";
-
+import { _parseVAAAlgorand } from "@certusone/wormhole-sdk/lib/cjs/algorand";
 
 
 function getConfig(env: any) {
 function getConfig(env: any) {
   switch (env) {
   switch (env) {
@@ -77,7 +47,6 @@ async function initNear() {
   let masterKey = nearAPI.utils.KeyPair.fromString(
   let masterKey = nearAPI.utils.KeyPair.fromString(
     "ed25519:5dJ7Nsq4DQBdiGvZLPyjRVmhtRaScahsREpEPtaAyE9Z3CgyZFsaBwpybCRBMugiwhbFCUkqHk7PJ3BVcgZZ9Lgk"
     "ed25519:5dJ7Nsq4DQBdiGvZLPyjRVmhtRaScahsREpEPtaAyE9Z3CgyZFsaBwpybCRBMugiwhbFCUkqHk7PJ3BVcgZZ9Lgk"
   );
   );
-  let masterPubKey = masterKey.getPublicKey();
 
 
   let keyStore = new nearAPI.keyStores.InMemoryKeyStore();
   let keyStore = new nearAPI.keyStores.InMemoryKeyStore();
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
@@ -93,6 +62,7 @@ async function initNear() {
     near.connection,
     near.connection,
     config.masterAccount
     config.masterAccount
   );
   );
+  const provider = near.connection.provider;
 
 
   console.log(
   console.log(
     "Finish init NEAR masterAccount: " +
     "Finish init NEAR masterAccount: " +
@@ -114,13 +84,22 @@ async function initNear() {
   );
   );
 
 
   console.log("attesting Near itself");
   console.log("attesting Near itself");
-  let s = await attestNearFromNear(masterAccount, core_bridge, token_bridge);
+  const attestMsg = await attestNearFromNear(
+    provider,
+    core_bridge,
+    token_bridge
+  );
+  const attestOutcome = await masterAccount.functionCall(attestMsg);
+  const attestSeq = parseSequenceFromLogNear(attestOutcome);
+  if (attestSeq === null) {
+    throw new Error("attestSeq is null");
+  }
 
 
   const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
   const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     ["https://wormhole-v2-testnet-api.certus.one"],
     ["https://wormhole-v2-testnet-api.certus.one"],
-    CHAIN_ID_NEAR,
-    s[1],
-    s[0].toString(),
+    "near",
+    getEmitterAddressNear(token_bridge),
+    attestSeq,
     {
     {
       transport: NodeHttpTransport(),
       transport: NodeHttpTransport(),
     }
     }
@@ -128,21 +107,29 @@ async function initNear() {
 
 
   console.log("vaa: " + Buffer.from(signedVAA).toString("hex"));
   console.log("vaa: " + Buffer.from(signedVAA).toString("hex"));
 
 
-  s = await transferNearFromNear(
-    masterAccount,
+  const transferMsg = await transferNearFromNear(
+    provider,
     core_bridge,
     core_bridge,
     token_bridge,
     token_bridge,
     BigInt(1000000000000000000000000),
     BigInt(1000000000000000000000000),
-    tryNativeToUint8Array("0x3bC7f2e458aC4E55F941C458cfD8c6851a591B4F", "ethereum"),
+    tryNativeToUint8Array(
+      "0x3bC7f2e458aC4E55F941C458cfD8c6851a591B4F",
+      "ethereum"
+    ),
     2,
     2,
     BigInt(0)
     BigInt(0)
   );
   );
+  const transferOutcome = await masterAccount.functionCall(transferMsg);
+  const transferSeq = parseSequenceFromLogNear(transferOutcome);
+  if (transferSeq === null) {
+    throw new Error("transferSeq is null");
+  }
 
 
   const { vaaBytes: signedTrans } = await getSignedVAAWithRetry(
   const { vaaBytes: signedTrans } = await getSignedVAAWithRetry(
     ["https://wormhole-v2-testnet-api.certus.one"],
     ["https://wormhole-v2-testnet-api.certus.one"],
-    CHAIN_ID_NEAR,
-    s[1],
-    s[0].toString(),
+    "near",
+    getEmitterAddressNear(token_bridge),
+    transferSeq,
     {
     {
       transport: NodeHttpTransport(),
       transport: NodeHttpTransport(),
     }
     }
@@ -150,8 +137,8 @@ async function initNear() {
 
 
   console.log("vaa: " + Buffer.from(signedTrans).toString("hex"));
   console.log("vaa: " + Buffer.from(signedTrans).toString("hex"));
 
 
-    let p = _parseVAAAlgorand(signedTrans);
-    console.log(p);
+  let p = _parseVAAAlgorand(signedTrans);
+  console.log(p);
 }
 }
 
 
 initNear();
 initNear();

+ 38 - 69
near/test/p3.ts

@@ -1,39 +1,20 @@
 // npx pretty-quick
 // npx pretty-quick
 
 
-const sha256 = require("js-sha256");
 const nearAPI = require("near-api-js");
 const nearAPI = require("near-api-js");
-const fs = require("fs").promises;
-const assert = require("assert").strict;
 const fetch = require("node-fetch");
 const fetch = require("node-fetch");
-const elliptic = require("elliptic");
-const web3Utils = require("web3-utils");
-import { zeroPad } from "@ethersproject/bytes";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 
 
-import { Account as nearAccount } from "@certusone/wormhole-sdk/node_modules/near-api-js";
 const BN = require("bn.js");
 const BN = require("bn.js");
 
 
 import { TestLib } from "./testlib";
 import { TestLib } from "./testlib";
 
 
 import algosdk, {
 import algosdk, {
   Account,
   Account,
-  Algodv2,
-  OnApplicationComplete,
-  SuggestedParams,
-  bigIntToBytes,
   decodeAddress,
   decodeAddress,
-  getApplicationAddress,
-  makeApplicationCallTxnFromObject,
-  makePaymentTxnWithSuggestedParamsFromObject,
-  waitForConfirmation,
 } from "@certusone/wormhole-sdk/node_modules/algosdk";
 } from "@certusone/wormhole-sdk/node_modules/algosdk";
 
 
 import {
 import {
-  createAsset,
   getAlgoClient,
   getAlgoClient,
-  getBalance,
-  getBalances,
-  getForeignAssetFromVaaAlgorand,
   getTempAccounts,
   getTempAccounts,
   signSendAndConfirmAlgorand,
   signSendAndConfirmAlgorand,
 } from "./algoHelpers";
 } from "./algoHelpers";
@@ -42,44 +23,28 @@ import {
   CHAIN_ID_ALGORAND,
   CHAIN_ID_ALGORAND,
   CHAIN_ID_NEAR,
   CHAIN_ID_NEAR,
   ChainId,
   ChainId,
-  ChainName,
-  textToHexString,
-  textToUint8Array,
 } from "@certusone/wormhole-sdk/lib/cjs/utils";
 } from "@certusone/wormhole-sdk/lib/cjs/utils";
 
 
-import { safeBigIntToNumber } from "@certusone/wormhole-sdk/lib/cjs/utils/bigint";
-
 import {
 import {
   CONTRACTS,
   CONTRACTS,
-  attestNearFromNear,
-  attestTokenFromNear,
-  attestFromAlgorand,
   createWrappedOnAlgorand,
   createWrappedOnAlgorand,
   createWrappedOnNear,
   createWrappedOnNear,
   getEmitterAddressAlgorand,
   getEmitterAddressAlgorand,
   getForeignAssetAlgorand,
   getForeignAssetAlgorand,
-  getForeignAssetNear,
-  getIsTransferCompletedNear,
-  getIsWrappedAssetNear,
-  getOriginalAssetNear,
   getSignedVAAWithRetry,
   getSignedVAAWithRetry,
   redeemOnAlgorand,
   redeemOnAlgorand,
   redeemOnNear,
   redeemOnNear,
   transferFromAlgorand,
   transferFromAlgorand,
-  transferNearFromNear,
   transferTokenFromNear,
   transferTokenFromNear,
 } from "@certusone/wormhole-sdk";
 } from "@certusone/wormhole-sdk";
 
 
-const wh = require("@certusone/wormhole-sdk");
-
 import { parseSequenceFromLogAlgorand } from "@certusone/wormhole-sdk/lib/cjs/bridge";
 import { parseSequenceFromLogAlgorand } from "@certusone/wormhole-sdk/lib/cjs/bridge";
 
 
+import { _parseVAAAlgorand } from "@certusone/wormhole-sdk/lib/cjs/algorand";
 import {
 import {
-  getMessageFee,
-  optin,
-  TransactionSignerPair,
-  _parseVAAAlgorand,
-} from "@certusone/wormhole-sdk/lib/cjs/algorand";
+  getEmitterAddressNear,
+  parseSequenceFromLogNear,
+} from "@certusone/wormhole-sdk/src";
 
 
 export const uint8ArrayToHex = (a: Uint8Array): string =>
 export const uint8ArrayToHex = (a: Uint8Array): string =>
   Buffer.from(a).toString("hex");
   Buffer.from(a).toString("hex");
@@ -131,21 +96,6 @@ export function logNearGas(result: any, comment: string) {
   );
   );
 }
 }
 
 
-export function parseSequenceFromLogNear(result: any): [number, string] {
-  let sequence = "";
-  for (const o of result.receipts_outcome) {
-    for (const l of o.outcome.logs) {
-      if (l.startsWith("EVENT_JSON:")) {
-        const body = JSON.parse(l.slice(11));
-        if (body.standard == "wormhole" && body.event == "publish") {
-          return [body.seq, body.emitter];
-        }
-      }
-    }
-  }
-  return [-1, ""];
-}
-
 async function testNearSDK() {
 async function testNearSDK() {
   let config = getConfig(process.env.NEAR_ENV || "sandbox");
   let config = getConfig(process.env.NEAR_ENV || "sandbox");
 
 
@@ -157,7 +107,6 @@ async function testNearSDK() {
   let masterKey = nearAPI.utils.KeyPair.fromString(
   let masterKey = nearAPI.utils.KeyPair.fromString(
     keyFile.secret_key || keyFile.private_key
     keyFile.secret_key || keyFile.private_key
   );
   );
-  let masterPubKey = masterKey.getPublicKey();
 
 
   let keyStore = new nearAPI.keyStores.InMemoryKeyStore();
   let keyStore = new nearAPI.keyStores.InMemoryKeyStore();
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
   keyStore.setKey(config.networkId, config.masterAccount, masterKey);
@@ -197,6 +146,7 @@ async function testNearSDK() {
     new BN(10).pow(new BN(27))
     new BN(10).pow(new BN(27))
   );
   );
   const userAccount = new nearAPI.Account(near.connection, config.userAccount);
   const userAccount = new nearAPI.Account(near.connection, config.userAccount);
+  const provider = near.connection.provider;
 
 
   console.log(
   console.log(
     "creating a second user account: " +
     "creating a second user account: " +
@@ -223,13 +173,8 @@ async function testNearSDK() {
   let algoCore = BigInt(CONTRACTS.DEVNET.algorand.core);
   let algoCore = BigInt(CONTRACTS.DEVNET.algorand.core);
   let algoToken = BigInt(CONTRACTS.DEVNET.algorand.token_bridge);
   let algoToken = BigInt(CONTRACTS.DEVNET.algorand.token_bridge);
 
 
-  const tbAddr: string = getApplicationAddress(algoToken);
-  const decTbAddr: Uint8Array = decodeAddress(tbAddr).publicKey;
-  const aa: string = uint8ArrayToHex(decTbAddr);
-
   const algoClient: algosdk.Algodv2 = getAlgoClient();
   const algoClient: algosdk.Algodv2 = getAlgoClient();
   const tempAccts: Account[] = await getTempAccounts();
   const tempAccts: Account[] = await getTempAccounts();
-  const numAccts: number = tempAccts.length;
 
 
   const algoWallet: Account = tempAccts[0];
   const algoWallet: Account = tempAccts[0];
 
 
@@ -253,9 +198,16 @@ async function testNearSDK() {
 
 
   seq = seq + 1;
   seq = seq + 1;
 
 
-  let usdcp = _parseVAAAlgorand(usdcvaa);
-
-  let usdc = await createWrappedOnNear(userAccount, token_bridge, usdcvaa);
+  const createWrappedMsgs = await createWrappedOnNear(
+    provider,
+    token_bridge,
+    usdcvaa
+  );
+  let usdc;
+  for (const msg of createWrappedMsgs) {
+    const tx = await userAccount.functionCall(msg);
+    usdc = nearAPI.providers.getTransactionLastResult(tx);
+  }
   console.log(usdc);
   console.log(usdc);
 
 
   console.log("Creating USDC token on algorand");
   console.log("Creating USDC token on algorand");
@@ -298,7 +250,12 @@ async function testNearSDK() {
     console.log(trans);
     console.log(trans);
 
 
     console.log(
     console.log(
-      await redeemOnNear(userAccount, token_bridge, hexToUint8Array(trans))
+      await redeemOnNear(
+        provider,
+        userAccount.account_id,
+        token_bridge,
+        hexToUint8Array(trans)
+      )
     );
     );
   }
   }
   console.log(".. created some USDC on near");
   console.log(".. created some USDC on near");
@@ -306,8 +263,9 @@ async function testNearSDK() {
   let wrappedTransfer;
   let wrappedTransfer;
   {
   {
     console.log("transfer USDC from near to algorand");
     console.log("transfer USDC from near to algorand");
-    let s = await transferTokenFromNear(
-      userAccount,
+    const transferMsg = await transferTokenFromNear(
+      provider,
+      userAccount.account_id,
       core_bridge,
       core_bridge,
       token_bridge,
       token_bridge,
       usdc,
       usdc,
@@ -316,12 +274,18 @@ async function testNearSDK() {
       8,
       8,
       BigInt(0)
       BigInt(0)
     );
     );
+    const transferOutcome = await userAccount.functionCall(transferMsg);
+    const sequence = parseSequenceFromLogNear(transferOutcome);
+    if (sequence === null) {
+      console.log("sequence is null");
+      return;
+    }
 
 
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -407,7 +371,12 @@ async function testNearSDK() {
 
 
   console.log("redeeming P3 NEAR on Near");
   console.log("redeeming P3 NEAR on Near");
   console.log(
   console.log(
-    await redeemOnNear(user2Account, token_bridge, transferAlgoToNearP3)
+    await redeemOnNear(
+      provider,
+      user2Account.account_id,
+      token_bridge,
+      transferAlgoToNearP3
+    )
   );
   );
 
 
   console.log("transfering USDC from Algo To Near... getting the vaa");
   console.log("transfering USDC from Algo To Near... getting the vaa");

+ 155 - 98
near/test/sdk.ts

@@ -1,12 +1,6 @@
 // npx pretty-quick
 // npx pretty-quick
 
 
-const sha256 = require("js-sha256");
-const fs = require("fs").promises;
-const assert = require("assert").strict;
 const fetch = require("node-fetch");
 const fetch = require("node-fetch");
-const elliptic = require("elliptic");
-const web3Utils = require("web3-utils");
-import { zeroPad } from "@ethersproject/bytes";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
 
 
 import {
 import {
@@ -23,22 +17,12 @@ import { TestLib } from "./testlib";
 
 
 import algosdk, {
 import algosdk, {
   Account,
   Account,
-  Algodv2,
-  OnApplicationComplete,
-  SuggestedParams,
-  bigIntToBytes,
   decodeAddress,
   decodeAddress,
   getApplicationAddress,
   getApplicationAddress,
-  makeApplicationCallTxnFromObject,
-  makePaymentTxnWithSuggestedParamsFromObject,
-  waitForConfirmation,
 } from "@certusone/wormhole-sdk/node_modules/algosdk";
 } from "@certusone/wormhole-sdk/node_modules/algosdk";
 
 
 import {
 import {
   getAlgoClient,
   getAlgoClient,
-  getBalance,
-  getBalances,
-  getForeignAssetFromVaaAlgorand,
   getTempAccounts,
   getTempAccounts,
   signSendAndConfirmAlgorand,
   signSendAndConfirmAlgorand,
 } from "./algoHelpers";
 } from "./algoHelpers";
@@ -47,13 +31,8 @@ import {
   CHAIN_ID_ALGORAND,
   CHAIN_ID_ALGORAND,
   CHAIN_ID_NEAR,
   CHAIN_ID_NEAR,
   ChainId,
   ChainId,
-  ChainName,
-  textToHexString,
-  textToUint8Array,
 } from "@certusone/wormhole-sdk/lib/cjs/utils";
 } from "@certusone/wormhole-sdk/lib/cjs/utils";
 
 
-import { safeBigIntToNumber } from "@certusone/wormhole-sdk/lib/cjs/utils/bigint";
-
 import {
 import {
   CONTRACTS,
   CONTRACTS,
   attestNearFromNear,
   attestNearFromNear,
@@ -66,8 +45,6 @@ import {
   getForeignAssetAlgorand,
   getForeignAssetAlgorand,
   getForeignAssetNear,
   getForeignAssetNear,
   getIsTransferCompletedNear,
   getIsTransferCompletedNear,
-  getIsWrappedAssetNear,
-  getOriginalAssetNear,
   getSignedVAAWithRetry,
   getSignedVAAWithRetry,
   redeemOnAlgorand,
   redeemOnAlgorand,
   redeemOnNear,
   redeemOnNear,
@@ -76,19 +53,10 @@ import {
   transferTokenFromNear,
   transferTokenFromNear,
 } from "@certusone/wormhole-sdk";
 } from "@certusone/wormhole-sdk";
 
 
-const wh = require("@certusone/wormhole-sdk");
-
-import {
-  parseSequenceFromLogAlgorand,
-  parseSequenceFromLogNear,
-} from "@certusone/wormhole-sdk/lib/cjs/bridge";
+import { parseSequenceFromLogAlgorand } from "@certusone/wormhole-sdk/lib/cjs/bridge";
 
 
-import {
-  getMessageFee,
-  optin,
-  TransactionSignerPair,
-  _parseVAAAlgorand,
-} from "@certusone/wormhole-sdk/lib/cjs/algorand";
+import { _parseVAAAlgorand } from "@certusone/wormhole-sdk/lib/cjs/algorand";
+import { parseSequenceFromLogNear } from "@certusone/wormhole-sdk/src";
 
 
 export const uint8ArrayToHex = (a: Uint8Array): string =>
 export const uint8ArrayToHex = (a: Uint8Array): string =>
   Buffer.from(a).toString("hex");
   Buffer.from(a).toString("hex");
@@ -218,7 +186,6 @@ async function testNearSDK() {
   let masterKey = nearUtils.KeyPair.fromString(
   let masterKey = nearUtils.KeyPair.fromString(
     keyFile.secret_key || keyFile.private_key
     keyFile.secret_key || keyFile.private_key
   );
   );
-  let masterPubKey = masterKey.getPublicKey();
 
 
   let keyStore = new nearKeyStores.InMemoryKeyStore();
   let keyStore = new nearKeyStores.InMemoryKeyStore();
   keyStore.setKey(
   keyStore.setKey(
@@ -229,9 +196,7 @@ async function testNearSDK() {
 
 
   let near = await nearConnect({
   let near = await nearConnect({
     headers: {},
     headers: {},
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: config.networkId as string,
     networkId: config.networkId as string,
     nodeUrl: config.nodeUrl as string,
     nodeUrl: config.nodeUrl as string,
   });
   });
@@ -274,6 +239,7 @@ async function testNearSDK() {
     near.connection,
     near.connection,
     config.userAccount as string
     config.userAccount as string
   );
   );
+  const provider = near.connection.provider;
 
 
   console.log(
   console.log(
     "creating a second user account: " +
     "creating a second user account: " +
@@ -317,11 +283,9 @@ async function testNearSDK() {
 
 
   const tbAddr: string = getApplicationAddress(algoToken);
   const tbAddr: string = getApplicationAddress(algoToken);
   const decTbAddr: Uint8Array = decodeAddress(tbAddr).publicKey;
   const decTbAddr: Uint8Array = decodeAddress(tbAddr).publicKey;
-  const aa: string = uint8ArrayToHex(decTbAddr);
 
 
   const algoClient: algosdk.Algodv2 = getAlgoClient();
   const algoClient: algosdk.Algodv2 = getAlgoClient();
   const tempAccts: Account[] = await getTempAccounts();
   const tempAccts: Account[] = await getTempAccounts();
-  const numAccts: number = tempAccts.length;
 
 
   const algoWallet: Account = tempAccts[0];
   const algoWallet: Account = tempAccts[0];
 
 
@@ -353,12 +317,15 @@ async function testNearSDK() {
     { transport: NodeHttpTransport() }
     { transport: NodeHttpTransport() }
   );
   );
 
 
-  let noriumNear = await createWrappedOnNear(
-    userAccount,
+  for (const msg of await createWrappedOnNear(
+    provider,
     token_bridge,
     token_bridge,
     vaaBytes
     vaaBytes
-  );
-  console.log("for norium, createWrappedOnNear returned " + noriumNear);
+  )) {
+    await userAccount.functionCall(msg);
+  }
+
+  console.log("for norium, createWrappedOnNear returned");
 
 
   let account_hash = await userAccount.viewFunction(
   let account_hash = await userAccount.viewFunction(
     token_bridge,
     token_bridge,
@@ -455,14 +422,22 @@ async function testNearSDK() {
   console.log("calling createWrappedOnNear to create usdc");
   console.log("calling createWrappedOnNear to create usdc");
 
 
   if (
   if (
-    (await getIsTransferCompletedNear(userAccount, token_bridge, usdcvaa)) ==
-    true
+    (await getIsTransferCompletedNear(provider, token_bridge, usdcvaa)) == true
   ) {
   ) {
     console.log("getIsTransferCompleted returned incorrect value (true)");
     console.log("getIsTransferCompleted returned incorrect value (true)");
     process.exit(1);
     process.exit(1);
   }
   }
 
 
-  let usdc = await createWrappedOnNear(userAccount, token_bridge, usdcvaa);
+  const createWrappedMsgs = await createWrappedOnNear(
+    provider,
+    token_bridge,
+    usdcvaa
+  );
+  let usdc;
+  for (const msg of createWrappedMsgs) {
+    const tx = await userAccount.functionCall(msg);
+    usdc = nearProviders.getTransactionLastResult(tx);
+  }
   console.log("createWrappedOnNear returned " + usdc);
   console.log("createWrappedOnNear returned " + usdc);
 
 
   if (usdc === "") {
   if (usdc === "") {
@@ -471,15 +446,14 @@ async function testNearSDK() {
   }
   }
 
 
   if (
   if (
-    (await getIsTransferCompletedNear(userAccount, token_bridge, usdcvaa)) ==
-    false
+    (await getIsTransferCompletedNear(provider, token_bridge, usdcvaa)) == false
   ) {
   ) {
     console.log("getIsTransferCompleted returned incorrect value (false)");
     console.log("getIsTransferCompleted returned incorrect value (false)");
     process.exit(1);
     process.exit(1);
   }
   }
 
 
   let aname = await getForeignAssetNear(
   let aname = await getForeignAssetNear(
-    userAccount,
+    provider,
     token_bridge,
     token_bridge,
     usdcp.FromChain as ChainId,
     usdcp.FromChain as ChainId,
     usdcp.Contract as string
     usdcp.Contract as string
@@ -518,9 +492,15 @@ async function testNearSDK() {
     console.log(trans);
     console.log(trans);
 
 
     try {
     try {
-      console.log(
-        await redeemOnNear(userAccount, token_bridge, hexToUint8Array(trans))
+      const redeemMsgs = await redeemOnNear(
+        provider,
+        userAccount.accountId,
+        token_bridge,
+        hexToUint8Array(trans)
       );
       );
+      for (const msg of redeemMsgs) {
+        await userAccount.functionCall(msg);
+      }
       console.log("This should have thrown a exception..");
       console.log("This should have thrown a exception..");
       process.exit(1);
       process.exit(1);
     } catch (error) {
     } catch (error) {
@@ -541,30 +521,52 @@ async function testNearSDK() {
     );
     );
     console.log("myAddress: " + myAddress2);
     console.log("myAddress: " + myAddress2);
 
 
-    console.log(
-      await redeemOnNear(userAccount, token_bridge, hexToUint8Array(trans))
+    const redeemMsgs = await redeemOnNear(
+      provider,
+      userAccount.accountId,
+      token_bridge,
+      hexToUint8Array(trans)
     );
     );
+    for (const msg of redeemMsgs) {
+      await userAccount.functionCall(msg);
+    }
   }
   }
   console.log(".. created some USDC");
   console.log(".. created some USDC");
 
 
   console.log("Redeeming norium on near");
   console.log("Redeeming norium on near");
-  await redeemOnNear(userAccount, token_bridge, signedVaa.vaaBytes);
+  for (const msg of await redeemOnNear(
+    provider,
+    userAccount.accountId,
+    token_bridge,
+    signedVaa.vaaBytes
+  )) {
+    await userAccount.functionCall(msg);
+  }
 
 
   let nativeAttest;
   let nativeAttest;
   {
   {
     console.log("attesting: " + randoToken);
     console.log("attesting: " + randoToken);
-    let s = await attestTokenFromNear(
-      userAccount,
+    const attestMsgs = await attestTokenFromNear(
+      provider,
       core_bridge,
       core_bridge,
       token_bridge,
       token_bridge,
       randoToken
       randoToken
     );
     );
-    console.log(s);
+    let sequence;
+    for (const msg of attestMsgs) {
+      const tx = await userAccount.functionCall(msg);
+      sequence = parseSequenceFromLogNear(tx);
+    }
+    if (!sequence) {
+      console.log("sequence is null");
+      process.exit(1);
+    }
+    console.log(getEmitterAddressNear(token_bridge));
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -576,7 +578,7 @@ async function testNearSDK() {
     console.log(p.FromChain as ChainId, p.Contract as string);
     console.log(p.FromChain as ChainId, p.Contract as string);
 
 
     let a = await getForeignAssetNear(
     let a = await getForeignAssetNear(
-      userAccount,
+      provider,
       token_bridge,
       token_bridge,
       p.FromChain as ChainId,
       p.FromChain as ChainId,
       p.Contract as string
       p.Contract as string
@@ -592,13 +594,22 @@ async function testNearSDK() {
   let nearAttest;
   let nearAttest;
   {
   {
     console.log("attesting Near itself");
     console.log("attesting Near itself");
-    let s = await attestNearFromNear(userAccount, core_bridge, token_bridge);
-
+    const attestMsg = await attestNearFromNear(
+      provider,
+      core_bridge,
+      token_bridge
+    );
+    const tx = await userAccount.functionCall(attestMsg);
+    const sequence = parseSequenceFromLogNear(tx);
+    if (sequence === null) {
+      console.log("sequence is null");
+      process.exit(1);
+    }
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -607,7 +618,7 @@ async function testNearSDK() {
     console.log("vaa: " + Buffer.from(signedVAA).toString("hex"));
     console.log("vaa: " + Buffer.from(signedVAA).toString("hex"));
     let p = _parseVAAAlgorand(signedVAA);
     let p = _parseVAAAlgorand(signedVAA);
     let a = await getForeignAssetNear(
     let a = await getForeignAssetNear(
-      userAccount,
+      provider,
       token_bridge,
       token_bridge,
       p.FromChain as ChainId,
       p.FromChain as ChainId,
       p.Contract as string
       p.Contract as string
@@ -658,8 +669,9 @@ async function testNearSDK() {
       usdc
       usdc
     );
     );
 
 
-    let s = await transferTokenFromNear(
-      userAccount,
+    const transferMsgs = await transferTokenFromNear(
+      provider,
+      userAccount.accountId,
       core_bridge,
       core_bridge,
       token_bridge,
       token_bridge,
       usdc,
       usdc,
@@ -668,12 +680,21 @@ async function testNearSDK() {
       8,
       8,
       BigInt(0)
       BigInt(0)
     );
     );
+    let sequence;
+    for (const msg of transferMsgs) {
+      const tx = await userAccount.functionCall(msg);
+      sequence = parseSequenceFromLogNear(tx);
+    }
+    if (!sequence) {
+      console.log("sequence is null");
+      process.exit(1);
+    }
 
 
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -698,8 +719,9 @@ async function testNearSDK() {
   let randoTransfer;
   let randoTransfer;
   {
   {
     console.log("YYY transfer rando token from near to algorand");
     console.log("YYY transfer rando token from near to algorand");
-    let s = await transferTokenFromNear(
-      userAccount,
+    const transferMsgs = await transferTokenFromNear(
+      provider,
+      userAccount.accountId,
       core_bridge,
       core_bridge,
       token_bridge,
       token_bridge,
       randoToken,
       randoToken,
@@ -708,12 +730,21 @@ async function testNearSDK() {
       8,
       8,
       BigInt(0)
       BigInt(0)
     );
     );
+    let sequence;
+    for (const msg of transferMsgs) {
+      const tx = await userAccount.functionCall(msg);
+      sequence = parseSequenceFromLogNear(tx);
+    }
+    if (!sequence) {
+      console.log("sequence is null");
+      process.exit(1);
+    }
 
 
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -723,16 +754,6 @@ async function testNearSDK() {
     randoTransfer = signedVAA;
     randoTransfer = signedVAA;
 
 
     console.log(_parseVAAAlgorand(randoTransfer));
     console.log(_parseVAAAlgorand(randoTransfer));
-
-    if (s[1] != getEmitterAddressNear(token_bridge)) {
-      console.log(
-        "Unexpected emitter address: " +
-          s[1] +
-          "!=" +
-          getEmitterAddressNear(token_bridge)
-      );
-      process.exit(1);
-    }
   }
   }
 
 
   console.log(
   console.log(
@@ -750,8 +771,8 @@ async function testNearSDK() {
   let nearTransfer;
   let nearTransfer;
   {
   {
     console.log("transfer near from near to algorand");
     console.log("transfer near from near to algorand");
-    let s = await transferNearFromNear(
-      userAccount,
+    const transferMsg = await transferNearFromNear(
+      provider,
       core_bridge,
       core_bridge,
       token_bridge,
       token_bridge,
       BigInt(1000000000000000000000000),
       BigInt(1000000000000000000000000),
@@ -759,12 +780,18 @@ async function testNearSDK() {
       8,
       8,
       BigInt(0)
       BigInt(0)
     );
     );
+    const tx = await userAccount.functionCall(transferMsg);
+    const sequence = parseSequenceFromLogNear(tx);
+    if (sequence === null) {
+      console.log("sequence is null");
+      process.exit(1);
+    }
 
 
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
     const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
       ["http://localhost:7071"],
       ["http://localhost:7071"],
       CHAIN_ID_NEAR,
       CHAIN_ID_NEAR,
-      s[1],
-      s[0].toString(),
+      getEmitterAddressNear(token_bridge),
+      sequence,
       {
       {
         transport: NodeHttpTransport(),
         transport: NodeHttpTransport(),
       }
       }
@@ -944,9 +971,15 @@ async function testNearSDK() {
   }
   }
 
 
   console.log("redeeming USDC on Near");
   console.log("redeeming USDC on Near");
-  console.log(
-    await redeemOnNear(user2Account, token_bridge, transferAlgoToNearUSDC)
+  let redeemMsgs = await redeemOnNear(
+    provider,
+    user2Account.accountId,
+    token_bridge,
+    transferAlgoToNearUSDC
   );
   );
+  for (const msg of redeemMsgs) {
+    await userAccount.functionCall(msg);
+  }
 
 
   console.log(
   console.log(
     "YYY redeeming Rando on Near: " + uint8ArrayToHex(transferAlgoToNearRando)
     "YYY redeeming Rando on Near: " + uint8ArrayToHex(transferAlgoToNearRando)
@@ -964,9 +997,15 @@ async function testNearSDK() {
     })
     })
   );
   );
 
 
-  console.log(
-    await redeemOnNear(user2Account, token_bridge, transferAlgoToNearRando)
+  redeemMsgs = await redeemOnNear(
+    provider,
+    user2Account.accountId,
+    token_bridge,
+    transferAlgoToNearRando
   );
   );
+  for (const msg of redeemMsgs) {
+    await userAccount.functionCall(msg);
+  }
 
 
   console.log(
   console.log(
     await userAccount.viewFunction(randoToken, "ft_balance_of", {
     await userAccount.viewFunction(randoToken, "ft_balance_of", {
@@ -981,9 +1020,16 @@ async function testNearSDK() {
   );
   );
 
 
   console.log("redeeming NEAR on Near");
   console.log("redeeming NEAR on Near");
-  console.log(
-    await redeemOnNear(user2Account, token_bridge, transferAlgoToNearNEAR)
+
+  redeemMsgs = await redeemOnNear(
+    provider,
+    user2Account.accountId,
+    token_bridge,
+    transferAlgoToNearNEAR
   );
   );
+  for (const msg of redeemMsgs) {
+    await userAccount.functionCall(msg);
+  }
 
 
   let userAccount2Address = nearProviders.getTransactionLastResult(
   let userAccount2Address = nearProviders.getTransactionLastResult(
     await userAccount.functionCall({
     await userAccount.functionCall({
@@ -1032,7 +1078,12 @@ async function testNearSDK() {
   {
   {
     console.log("redeeming P3 NEAR on Near");
     console.log("redeeming P3 NEAR on Near");
     console.log(
     console.log(
-      await redeemOnNear(user2Account, token_bridge, transferAlgoToNearP3)
+      await redeemOnNear(
+        provider,
+        user2Account.accountId,
+        token_bridge,
+        transferAlgoToNearP3
+      )
     );
     );
 
 
     console.log(
     console.log(
@@ -1071,9 +1122,15 @@ async function testNearSDK() {
     }
     }
 
 
     console.log("YYY redeeming P3 random on Near");
     console.log("YYY redeeming P3 random on Near");
-    console.log(
-      await redeemOnNear(user2Account, token_bridge, transferAlgoToNearRandoP3)
+    const redeemMsgs = await redeemOnNear(
+      provider,
+      user2Account.accountId,
+      token_bridge,
+      transferAlgoToNearRandoP3
     );
     );
+    for (const msg of redeemMsgs) {
+      await user2Account.functionCall(msg);
+    }
   }
   }
 
 
   console.log(
   console.log(

+ 16 - 7
near/test/transferFromNear.ts

@@ -22,8 +22,10 @@ import {
   CHAIN_ID_NEAR,
   CHAIN_ID_NEAR,
   CONTRACTS,
   CONTRACTS,
   getEmitterAddressEth,
   getEmitterAddressEth,
+  getEmitterAddressNear,
   getSignedVAAWithRetry,
   getSignedVAAWithRetry,
   hexToUint8Array,
   hexToUint8Array,
+  parseSequenceFromLogNear,
   transferTokenFromNear,
   transferTokenFromNear,
   uint8ArrayToHex,
   uint8ArrayToHex,
 } from "@certusone/wormhole-sdk";
 } from "@certusone/wormhole-sdk";
@@ -85,9 +87,7 @@ async function transferTest() {
   // connect to near...
   // connect to near...
   let near = await nearConnect({
   let near = await nearConnect({
     headers: {},
     headers: {},
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: networkId as string,
     networkId: networkId as string,
     nodeUrl: nearNodeUrl as string,
     nodeUrl: nearNodeUrl as string,
   });
   });
@@ -120,9 +120,11 @@ async function transferTest() {
     near.connection,
     near.connection,
     process.env.NEAR_ACCOUNT as string
     process.env.NEAR_ACCOUNT as string
   );
   );
+  const provider = userAccount.connection.provider;
 
 
-  let [sequence, emitterAddress] = await transferTokenFromNear(
-    userAccount,
+  const transferMsgs = await transferTokenFromNear(
+    provider,
+    userAccount.accountId,
     CONTRACTS.MAINNET.near.core,
     CONTRACTS.MAINNET.near.core,
     CONTRACTS.MAINNET.near.token_bridge,
     CONTRACTS.MAINNET.near.token_bridge,
     NEAR_TOKEN_ADDRESS,
     NEAR_TOKEN_ADDRESS,
@@ -131,12 +133,19 @@ async function transferTest() {
     CHAIN_ID_ETH,
     CHAIN_ID_ETH,
     BigInt(0)
     BigInt(0)
   );
   );
-
-  if (sequence === -1) {
+  let transferOutcome;
+  for (const msg of transferMsgs) {
+    transferOutcome = await userAccount.functionCall(msg);
+  }
+  const sequence = parseSequenceFromLogNear(transferOutcome);
+  if (sequence === null) {
     console.log("No sequence found, check above for error");
     console.log("No sequence found, check above for error");
     process.exit(1);
     process.exit(1);
   }
   }
 
 
+  const emitterAddress = getEmitterAddressNear(
+    CONTRACTS.MAINNET.near.token_bridge
+  );
   console.log("emitterAddress:", emitterAddress, "sequence:", sequence);
   console.log("emitterAddress:", emitterAddress, "sequence:", sequence);
 
 
   console.log(
   console.log(

+ 7 - 5
near/test/transferToNear.ts

@@ -133,9 +133,7 @@ async function transferTest() {
   // connect to near...
   // connect to near...
   let near = await nearConnect({
   let near = await nearConnect({
     headers: {},
     headers: {},
-    deps: {
-      keyStore,
-    },
+    keyStore,
     networkId: networkId as string,
     networkId: networkId as string,
     nodeUrl: nearNodeUrl as string,
     nodeUrl: nearNodeUrl as string,
   });
   });
@@ -292,11 +290,15 @@ async function transferTest() {
   console.log("VAA received!");
   console.log("VAA received!");
   console.log(uint8ArrayToHex(signedVAA));
   console.log(uint8ArrayToHex(signedVAA));
 
 
-  await redeemOnNear(
-    userAccount,
+  const redeemMsgs = await redeemOnNear(
+    userAccount.connection.provider,
+    userAccount.accountId,
     CONTRACTS.MAINNET.near.token_bridge,
     CONTRACTS.MAINNET.near.token_bridge,
     signedVAA
     signedVAA
   );
   );
+  for (const msg of redeemMsgs) {
+    await userAccount.functionCall(msg);
+  }
 
 
   console.log("Redeemed!");
   console.log("Redeemed!");
 
 

+ 9 - 19
sdk/js/package-lock.json

@@ -19,7 +19,7 @@
         "axios": "^0.24.0",
         "axios": "^0.24.0",
         "bech32": "^2.0.0",
         "bech32": "^2.0.0",
         "js-base64": "^3.6.1",
         "js-base64": "^3.6.1",
-        "near-api-js": "^0.45.1"
+        "near-api-js": "^1.0.0"
       },
       },
       "devDependencies": {
       "devDependencies": {
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
         "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
@@ -10097,11 +10097,11 @@
       "dev": true
       "dev": true
     },
     },
     "node_modules/near-api-js": {
     "node_modules/near-api-js": {
-      "version": "0.45.1",
-      "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-0.45.1.tgz",
-      "integrity": "sha512-QyPO/vjvMFlcMO1DCpsqzmnSqPIyHsjK1Qi4B5ZR1cJCIWMkqugDF/TDf8FVQ85pmlcYeYwfiTqKanKz+3IG0A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-1.0.0.tgz",
+      "integrity": "sha512-OYItaQIYlKK27FG5PrqqtkTI8Vv9TEOCi7gXePYigS4o6WofXciAXNjr4sihDJ8Vzi6s7+eEkf3zTNP3042FBw==",
       "dependencies": {
       "dependencies": {
-        "bn.js": "5.2.0",
+        "bn.js": "5.2.1",
         "borsh": "^0.7.0",
         "borsh": "^0.7.0",
         "bs58": "^4.0.0",
         "bs58": "^4.0.0",
         "depd": "^2.0.0",
         "depd": "^2.0.0",
@@ -10114,11 +10114,6 @@
         "tweetnacl": "^1.0.1"
         "tweetnacl": "^1.0.1"
       }
       }
     },
     },
-    "node_modules/near-api-js/node_modules/bn.js": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
-      "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
-    },
     "node_modules/near-api-js/node_modules/borsh": {
     "node_modules/near-api-js/node_modules/borsh": {
       "version": "0.7.0",
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",
       "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",
@@ -21156,11 +21151,11 @@
       "dev": true
       "dev": true
     },
     },
     "near-api-js": {
     "near-api-js": {
-      "version": "0.45.1",
-      "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-0.45.1.tgz",
-      "integrity": "sha512-QyPO/vjvMFlcMO1DCpsqzmnSqPIyHsjK1Qi4B5ZR1cJCIWMkqugDF/TDf8FVQ85pmlcYeYwfiTqKanKz+3IG0A==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-1.0.0.tgz",
+      "integrity": "sha512-OYItaQIYlKK27FG5PrqqtkTI8Vv9TEOCi7gXePYigS4o6WofXciAXNjr4sihDJ8Vzi6s7+eEkf3zTNP3042FBw==",
       "requires": {
       "requires": {
-        "bn.js": "5.2.0",
+        "bn.js": "5.2.1",
         "borsh": "^0.7.0",
         "borsh": "^0.7.0",
         "bs58": "^4.0.0",
         "bs58": "^4.0.0",
         "depd": "^2.0.0",
         "depd": "^2.0.0",
@@ -21173,11 +21168,6 @@
         "tweetnacl": "^1.0.1"
         "tweetnacl": "^1.0.1"
       },
       },
       "dependencies": {
       "dependencies": {
-        "bn.js": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
-          "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
-        },
         "borsh": {
         "borsh": {
           "version": "0.7.0",
           "version": "0.7.0",
           "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",
           "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz",

+ 1 - 1
sdk/js/package.json

@@ -68,6 +68,6 @@
     "axios": "^0.24.0",
     "axios": "^0.24.0",
     "bech32": "^2.0.0",
     "bech32": "^2.0.0",
     "js-base64": "^3.6.1",
     "js-base64": "^3.6.1",
-    "near-api-js": "^0.45.1"
+    "near-api-js": "^1.0.0"
   }
   }
 }
 }

+ 8 - 3
sdk/js/src/bridge/getEmitterAddress.ts

@@ -1,10 +1,15 @@
 import { PublicKey } from "@solana/web3.js";
 import { PublicKey } from "@solana/web3.js";
 import { decodeAddress, getApplicationAddress } from "algosdk";
 import { decodeAddress, getApplicationAddress } from "algosdk";
 import { bech32 } from "bech32";
 import { bech32 } from "bech32";
-import { arrayify, BytesLike, Hexable, zeroPad } from "ethers/lib/utils";
+import {
+  arrayify,
+  sha256,
+  BytesLike,
+  Hexable,
+  zeroPad,
+} from "ethers/lib/utils";
 import { importTokenWasm } from "../solana/wasm";
 import { importTokenWasm } from "../solana/wasm";
 import { uint8ArrayToHex } from "../utils";
 import { uint8ArrayToHex } from "../utils";
-import { sha256 } from  "js-sha256";
 
 
 export function getEmitterAddressEth(
 export function getEmitterAddressEth(
   contractAddress: number | BytesLike | Hexable
   contractAddress: number | BytesLike | Hexable
@@ -35,5 +40,5 @@ export function getEmitterAddressAlgorand(appId: bigint): string {
 }
 }
 
 
 export function getEmitterAddressNear(programAddress: string): string {
 export function getEmitterAddressNear(programAddress: string): string {
-  return sha256.hex(programAddress);
+  return uint8ArrayToHex(arrayify(sha256(Buffer.from(programAddress, "utf8"))));
 }
 }

+ 11 - 7
sdk/js/src/bridge/parseSequenceFromLog.ts

@@ -1,6 +1,7 @@
 import { TransactionResponse } from "@solana/web3.js";
 import { TransactionResponse } from "@solana/web3.js";
 import { TxInfo } from "@terra-money/terra.js";
 import { TxInfo } from "@terra-money/terra.js";
 import { BigNumber, ContractReceipt } from "ethers";
 import { BigNumber, ContractReceipt } from "ethers";
+import { FinalExecutionOutcome } from "near-api-js/lib/providers";
 import { Implementation__factory } from "../ethers-contracts";
 import { Implementation__factory } from "../ethers-contracts";
 
 
 export function parseSequenceFromLogEth(
 export function parseSequenceFromLogEth(
@@ -123,17 +124,20 @@ export function parseSequenceFromLogAlgorand(
   return sequence;
   return sequence;
 }
 }
 
 
-export function parseSequenceFromLogNear(result: any): [number, string] {
-  let sequence = "";
-  for (const o of result.receipts_outcome) {
+const NEAR_EVENT_PREFIX = "EVENT_JSON:";
+
+export function parseSequenceFromLogNear(
+  outcome: FinalExecutionOutcome
+): string | null {
+  for (const o of outcome.receipts_outcome) {
     for (const l of o.outcome.logs) {
     for (const l of o.outcome.logs) {
-      if (l.startsWith("EVENT_JSON:")) {
-        const body = JSON.parse(l.slice(11));
+      if (l.startsWith(NEAR_EVENT_PREFIX)) {
+        const body = JSON.parse(l.slice(NEAR_EVENT_PREFIX.length));
         if (body.standard === "wormhole" && body.event === "publish") {
         if (body.standard === "wormhole" && body.event === "publish") {
-          return [body.seq, body.emitter];
+          return body.seq.toString();
         }
         }
       }
       }
     }
     }
   }
   }
-  return [-1, ""];
+  return null;
 }
 }

+ 1 - 1
sdk/js/src/nft_bridge/getIsTransferCompleted.ts

@@ -49,7 +49,7 @@ export async function getIsTransferCompletedTerra(
         gasPrices,
         gasPrices,
       }
       }
     );
     );
-  } catch (e) {
+  } catch (e: any) {
     // redeemed if the VAA was already executed
     // redeemed if the VAA was already executed
     return e.response.data.message.includes("VaaAlreadyExecuted");
     return e.response.data.message.includes("VaaAlreadyExecuted");
   }
   }

+ 2 - 0
sdk/js/src/token_bridge/__tests__/consts.ts

@@ -83,6 +83,8 @@ export const TERRA_HOST =
         isClassic: true,
         isClassic: true,
       };
       };
 
 
+export const NEAR_NODE_URL = ci ? "http://near:3030" : "http://localhost:3030";
+
 describe("consts should exist", () => {
 describe("consts should exist", () => {
   it("has Solana test token", () => {
   it("has Solana test token", () => {
     expect.assertions(1);
     expect.assertions(1);

+ 223 - 0
sdk/js/src/token_bridge/__tests__/near-integration.ts

@@ -0,0 +1,223 @@
+import { beforeAll, afterAll, expect, jest, test } from "@jest/globals";
+import { ethers } from "ethers";
+import { parseUnits } from "ethers/lib/utils";
+import {
+  createWrappedOnEth,
+  createWrappedOnNear,
+  getEmitterAddressEth,
+  getEmitterAddressNear,
+  getIsTransferCompletedEth,
+  getIsTransferCompletedNear,
+  hashAccount,
+  hexToUint8Array,
+  parseSequenceFromLogEth,
+  parseSequenceFromLogNear,
+  redeemOnEth,
+  redeemOnNear,
+  registerAccount,
+  setDefaultWasm,
+  tryNativeToUint8Array,
+  updateWrappedOnEth,
+} from "../..";
+import { CHAIN_ID_ETH, CHAIN_ID_NEAR, CONTRACTS } from "../../utils/consts";
+import { attestFromEth, attestNearFromNear } from "../attest";
+import { approveEth, transferFromEth, transferNearFromNear } from "../transfer";
+import {
+  ETH_NODE_URL,
+  ETH_PRIVATE_KEY5,
+  NEAR_NODE_URL,
+  TEST_ERC20,
+} from "./consts";
+import { getSignedVAABySequence } from "./helpers";
+import { Account, connect, KeyPair, keyStores, Near } from "near-api-js";
+import {
+  FinalExecutionOutcome,
+  getTransactionLastResult,
+  Provider,
+} from "near-api-js/lib/providers";
+import { parseNearAmount } from "near-api-js/lib/utils/format";
+
+setDefaultWasm("node");
+
+jest.setTimeout(60000);
+
+let near: Near;
+let nearProvider: Provider;
+let account: Account;
+const networkId = "sandbox";
+const accountId = "devnet.test.near";
+const PRIVATE_KEY =
+  "ed25519:nCW2EsTn91b7ettRqQX6ti8ZBNwo7tbMsenBu9nmSVG9aDhNB7hgw7S9w5M9CZu1bF23FbvhKZPfDmh2Gbs45Fs";
+
+const ethProvider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
+const signer = new ethers.Wallet(ETH_PRIVATE_KEY5, ethProvider);
+const ethEmitterAddress = getEmitterAddressEth(
+  CONTRACTS.DEVNET.ethereum.token_bridge
+);
+const nearEmitterAddress = getEmitterAddressNear(
+  CONTRACTS.DEVNET.near.token_bridge
+);
+const ethTransferAmount = parseUnits("1", 18);
+let ethWalletAddress: string;
+
+beforeAll(async () => {
+  const keyStore = new keyStores.InMemoryKeyStore();
+  await keyStore.setKey(networkId, accountId, KeyPair.fromString(PRIVATE_KEY));
+  const config = {
+    keyStore,
+    networkId,
+    nodeUrl: NEAR_NODE_URL,
+    headers: {},
+  };
+  near = await connect(config);
+  nearProvider = near.connection.provider;
+  account = await near.account(accountId);
+  ethWalletAddress = await signer.getAddress();
+});
+
+afterAll(async () => {
+  ethProvider.destroy();
+});
+
+const nearParseLogAndGetSignedVaa = async (outcome: FinalExecutionOutcome) => {
+  const sequence = parseSequenceFromLogNear(outcome);
+  if (sequence === null) {
+    throw new Error("sequence is null");
+  }
+  return await getSignedVAABySequence(
+    CHAIN_ID_NEAR,
+    sequence,
+    nearEmitterAddress
+  );
+};
+
+const ethParseLogAndGetSignedVaa = async (receipt: ethers.ContractReceipt) => {
+  const sequence = parseSequenceFromLogEth(
+    receipt,
+    CONTRACTS.DEVNET.ethereum.core
+  );
+  return await getSignedVAABySequence(
+    CHAIN_ID_ETH,
+    sequence,
+    ethEmitterAddress
+  );
+};
+
+test("Attest and transfer Near token from Near to Ethereum", async () => {
+  // Attest
+  const attestMsg = await attestNearFromNear(
+    account.connection.provider,
+    CONTRACTS.DEVNET.near.core,
+    CONTRACTS.DEVNET.near.token_bridge
+  );
+  const attestOutcome = await account.functionCall(attestMsg);
+  const attestSignedVaa = await nearParseLogAndGetSignedVaa(attestOutcome);
+  try {
+    await createWrappedOnEth(
+      CONTRACTS.DEVNET.ethereum.token_bridge,
+      signer,
+      attestSignedVaa
+    );
+  } catch {
+    await updateWrappedOnEth(
+      CONTRACTS.DEVNET.ethereum.token_bridge,
+      signer,
+      attestSignedVaa
+    );
+  }
+  // Transfer
+  const transferMsg = await transferNearFromNear(
+    account.connection.provider,
+    CONTRACTS.DEVNET.near.core,
+    CONTRACTS.DEVNET.near.token_bridge,
+    BigInt(parseNearAmount("1") || ""),
+    tryNativeToUint8Array(ethWalletAddress, "ethereum"),
+    "ethereum",
+    BigInt(0)
+  );
+  const transferOutcome = await account.functionCall(transferMsg);
+  const transferSignedVAA = await nearParseLogAndGetSignedVaa(transferOutcome);
+  await redeemOnEth(
+    CONTRACTS.DEVNET.ethereum.token_bridge,
+    signer,
+    transferSignedVAA
+  );
+  expect(
+    await getIsTransferCompletedEth(
+      CONTRACTS.DEVNET.ethereum.token_bridge,
+      ethProvider,
+      transferSignedVAA
+    )
+  ).toBe(true);
+});
+
+test("Attest and transfer token from Ethereum to Near", async () => {
+  // Attest
+  const attestReceipt = await attestFromEth(
+    CONTRACTS.DEVNET.ethereum.token_bridge,
+    signer,
+    TEST_ERC20
+  );
+  const attestSignedVaa = await ethParseLogAndGetSignedVaa(attestReceipt);
+  const createWrappedMsgs = await createWrappedOnNear(
+    nearProvider,
+    CONTRACTS.DEVNET.near.token_bridge,
+    attestSignedVaa
+  );
+  for (const msg of createWrappedMsgs) {
+    await account.functionCall(msg);
+  }
+  // Transfer
+  await approveEth(
+    CONTRACTS.DEVNET.ethereum.token_bridge,
+    TEST_ERC20,
+    signer,
+    ethTransferAmount
+  );
+  let { isRegistered, accountHash } = await hashAccount(
+    nearProvider,
+    CONTRACTS.DEVNET.near.token_bridge,
+    account.accountId
+  );
+  if (!isRegistered) {
+    const registerAccountMsg = registerAccount(
+      account.accountId,
+      CONTRACTS.DEVNET.near.token_bridge
+    );
+    accountHash = getTransactionLastResult(
+      await account.functionCall(registerAccountMsg)
+    );
+  }
+  const transferReceipt = await transferFromEth(
+    CONTRACTS.DEVNET.ethereum.token_bridge,
+    signer,
+    TEST_ERC20,
+    ethTransferAmount,
+    "near",
+    hexToUint8Array(accountHash)
+  );
+  const transferSignedVaa = await ethParseLogAndGetSignedVaa(transferReceipt);
+  const redeemMsgs = await redeemOnNear(
+    nearProvider,
+    account.accountId,
+    CONTRACTS.DEVNET.near.token_bridge,
+    transferSignedVaa
+  );
+  expect(
+    await getIsTransferCompletedNear(
+      nearProvider,
+      CONTRACTS.DEVNET.near.token_bridge,
+      transferSignedVaa
+    )
+  ).toBe(false);
+  for (const msg of redeemMsgs) {
+    await account.functionCall(msg);
+  }
+  expect(
+    await getIsTransferCompletedNear(
+      nearProvider,
+      CONTRACTS.DEVNET.near.token_bridge,
+      transferSignedVaa
+    )
+  ).toBe(true);
+});

+ 34 - 56
sdk/js/src/token_bridge/attest.ts

@@ -11,21 +11,26 @@ import {
   OnApplicationComplete,
   OnApplicationComplete,
   SuggestedParams,
   SuggestedParams,
 } from "algosdk";
 } from "algosdk";
-import { Account as nearAccount } from "near-api-js";
-const BN = require("bn.js");
+import BN from "bn.js";
 import { ethers, PayableOverrides } from "ethers";
 import { ethers, PayableOverrides } from "ethers";
 import { isNativeDenom } from "..";
 import { isNativeDenom } from "..";
 import { getMessageFee, optin, TransactionSignerPair } from "../algorand";
 import { getMessageFee, optin, TransactionSignerPair } from "../algorand";
 import { Bridge__factory } from "../ethers-contracts";
 import { Bridge__factory } from "../ethers-contracts";
 import { getBridgeFeeIx, ixFromRust } from "../solana";
 import { getBridgeFeeIx, ixFromRust } from "../solana";
 import { importTokenWasm } from "../solana/wasm";
 import { importTokenWasm } from "../solana/wasm";
-import { textToHexString, textToUint8Array, uint8ArrayToHex } from "../utils";
+import {
+  callFunctionNear,
+  hashAccount,
+  textToHexString,
+  textToUint8Array,
+  uint8ArrayToHex,
+} from "../utils";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { createNonce } from "../utils/createNonce";
 import { createNonce } from "../utils/createNonce";
-import { parseSequenceFromLogNear } from "../bridge/parseSequenceFromLog";
-
 import { getIsWrappedAssetNear } from ".";
 import { getIsWrappedAssetNear } from ".";
 import { isNativeDenomInjective } from "../cosmwasm";
 import { isNativeDenomInjective } from "../cosmwasm";
+import { Provider } from "near-api-js/lib/providers";
+import { FunctionCallOptions } from "near-api-js/lib/account";
 
 
 export async function attestFromEth(
 export async function attestFromEth(
   tokenBridgeAddress: string,
   tokenBridgeAddress: string,
@@ -240,37 +245,23 @@ export async function attestFromAlgorand(
   return txs;
   return txs;
 }
 }
 
 
-/**
- * Attest an already created asset
- * If you create a new asset on near and want to transfer it elsewhere,
- * you create an attestation for it on near... pass that vaa to the target chain..
- * submit it.. then you can transfer from near to that target chain
- * @param client An Near account client
- * @param coreBridge The account for the core bridge
- * @param tokenBridge The account for the token bridge
- * @param asset The account for the asset
- * @returns [sequenceNumber, emitter]
- */
 export async function attestTokenFromNear(
 export async function attestTokenFromNear(
-  client: nearAccount,
+  provider: Provider,
   coreBridge: string,
   coreBridge: string,
   tokenBridge: string,
   tokenBridge: string,
   asset: string
   asset: string
-): Promise<[number, string]> {
-  let message_fee = await client.viewFunction(coreBridge, "message_fee", {});
-  // Non-signing event
+): Promise<FunctionCallOptions[]> {
+  const options: FunctionCallOptions[] = [];
+  const messageFee = await callFunctionNear(
+    provider,
+    coreBridge,
+    "message_fee"
+  );
   if (!getIsWrappedAssetNear(tokenBridge, asset)) {
   if (!getIsWrappedAssetNear(tokenBridge, asset)) {
-    // Non-signing event that hits the RPC
-    let res = await client.viewFunction(tokenBridge, "hash_account", {
-      account: asset,
-    });
-
-    // if res[0] == false, the account has not been
-    // registered... The first user to attest a non-wormhole token
-    // is gonna have to pay for the space
-    if (!res[0]) {
-      // Signing event
-      await client.functionCall({
+    const { isRegistered } = await hashAccount(provider, tokenBridge, asset);
+    if (!isRegistered) {
+      // The account has not been registered. The first user to attest a non-wormhole token pays for the space
+      options.push({
         contractId: tokenBridge,
         contractId: tokenBridge,
         methodName: "register_account",
         methodName: "register_account",
         args: { account: asset },
         args: { account: asset },
@@ -279,41 +270,28 @@ export async function attestTokenFromNear(
       });
       });
     }
     }
   }
   }
-
-  // Signing event
-  let result = await client.functionCall({
+  options.push({
     contractId: tokenBridge,
     contractId: tokenBridge,
     methodName: "attest_token",
     methodName: "attest_token",
-    args: { token: asset, message_fee: message_fee },
-    attachedDeposit: new BN("3000000000000000000000").add(new BN(message_fee)), // 0.003 NEAR
+    args: { token: asset, message_fee: messageFee },
+    attachedDeposit: new BN("3000000000000000000000").add(new BN(messageFee)), // 0.003 NEAR
     gas: new BN("100000000000000"),
     gas: new BN("100000000000000"),
   });
   });
-
-  return parseSequenceFromLogNear(result);
+  return options;
 }
 }
 
 
-/**
- * Attest NEAR
- * @param client An Near account client
- * @param coreBridge The account for the core bridge
- * @param tokenBridge The account for the token bridge
- * @returns [sequenceNumber, emitter]
- */
 export async function attestNearFromNear(
 export async function attestNearFromNear(
-  client: nearAccount,
+  provider: Provider,
   coreBridge: string,
   coreBridge: string,
   tokenBridge: string
   tokenBridge: string
-): Promise<[number, string]> {
-  let message_fee =
-    (await client.viewFunction(coreBridge, "message_fee", {})) + 1;
-
-  let result = await client.functionCall({
+): Promise<FunctionCallOptions> {
+  const messageFee =
+    (await callFunctionNear(provider, coreBridge, "message_fee")) + 1;
+  return {
     contractId: tokenBridge,
     contractId: tokenBridge,
     methodName: "attest_near",
     methodName: "attest_near",
-    args: { message_fee: message_fee },
-    attachedDeposit: new BN(message_fee),
+    args: { message_fee: messageFee },
+    attachedDeposit: new BN(messageFee),
     gas: new BN("100000000000000"),
     gas: new BN("100000000000000"),
-  });
-
-  return parseSequenceFromLogNear(result);
+  };
 }
 }

+ 22 - 28
sdk/js/src/token_bridge/createWrapped.ts

@@ -8,11 +8,10 @@ import { Bridge__factory } from "../ethers-contracts";
 import { ixFromRust } from "../solana";
 import { ixFromRust } from "../solana";
 import { importTokenWasm } from "../solana/wasm";
 import { importTokenWasm } from "../solana/wasm";
 import { submitVAAOnInjective } from "./redeem";
 import { submitVAAOnInjective } from "./redeem";
-import {
-  Account as nearAccount,
-  providers as nearProviders,
-} from "near-api-js";
 import BN from "bn.js";
 import BN from "bn.js";
+import { FunctionCallOptions } from "near-api-js/lib/account";
+import { Provider } from "near-api-js/lib/providers";
+import { callFunctionNear } from "../utils";
 
 
 export async function createWrappedOnEth(
 export async function createWrappedOnEth(
   tokenBridgeAddress: string,
   tokenBridgeAddress: string,
@@ -80,30 +79,25 @@ export async function createWrappedOnAlgorand(
 }
 }
 
 
 export async function createWrappedOnNear(
 export async function createWrappedOnNear(
-  client: nearAccount,
+  provider: Provider,
   tokenBridge: string,
   tokenBridge: string,
   attestVAA: Uint8Array
   attestVAA: Uint8Array
-): Promise<string> {
-  // Could we just pass in the vaa already as hex?
-  let vaa = Buffer.from(attestVAA).toString("hex");
-
-  let res = await client.viewFunction(tokenBridge, "deposit_estimates", {});
-
-  let result = await client.functionCall({
-    contractId: tokenBridge,
-    methodName: "submit_vaa",
-    args: { vaa: vaa },
-    attachedDeposit: new BN(res[1]),
-    gas: new BN("150000000000000"),
-  });
-
-  result = await client.functionCall({
-    contractId: tokenBridge,
-    methodName: "submit_vaa",
-    args: { vaa: vaa },
-    attachedDeposit: new BN(res[1]),
-    gas: new BN("150000000000000"),
-  });
-
-  return nearProviders.getTransactionLastResult(result);
+): Promise<FunctionCallOptions[]> {
+  const vaa = Buffer.from(attestVAA).toString("hex");
+  const res = await callFunctionNear(
+    provider,
+    tokenBridge,
+    "deposit_estimates"
+  );
+  const msgs = [
+    {
+      contractId: tokenBridge,
+      methodName: "submit_vaa",
+      args: { vaa },
+      attachedDeposit: new BN(res[1]),
+      gas: new BN("150000000000000"),
+    },
+  ];
+  msgs.push({ ...msgs[0] });
+  return msgs;
 }
 }

+ 13 - 12
sdk/js/src/token_bridge/getForeignAsset.ts

@@ -1,7 +1,6 @@
 import { Connection, PublicKey } from "@solana/web3.js";
 import { Connection, PublicKey } from "@solana/web3.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
 import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
-import { getNetworkInfo, Network } from "@injectivelabs/networks";
 import { Algodv2 } from "algosdk";
 import { Algodv2 } from "algosdk";
 import { ethers } from "ethers";
 import { ethers } from "ethers";
 import { fromUint8Array } from "js-base64";
 import { fromUint8Array } from "js-base64";
@@ -13,13 +12,13 @@ import {
 import { Bridge__factory } from "../ethers-contracts";
 import { Bridge__factory } from "../ethers-contracts";
 import { importTokenWasm } from "../solana/wasm";
 import { importTokenWasm } from "../solana/wasm";
 import {
 import {
+  callFunctionNear,
   ChainId,
   ChainId,
   ChainName,
   ChainName,
   CHAIN_ID_ALGORAND,
   CHAIN_ID_ALGORAND,
   coalesceChainId,
   coalesceChainId,
 } from "../utils";
 } from "../utils";
-import { Account as nearAccount } from "near-api-js";
-const BN = require("bn.js");
+import { Provider } from "near-api-js/lib/providers";
 
 
 /**
 /**
  * Returns a foreign asset address on Ethereum for a provided native chain and asset address, AddressZero if it does not exist
  * Returns a foreign asset address on Ethereum for a provided native chain and asset address, AddressZero if it does not exist
@@ -165,17 +164,19 @@ export async function getForeignAssetAlgorand(
 }
 }
 
 
 export async function getForeignAssetNear(
 export async function getForeignAssetNear(
-  client: nearAccount,
+  provider: Provider,
   tokenAccount: string,
   tokenAccount: string,
   chain: ChainId | ChainName,
   chain: ChainId | ChainName,
   contract: string
   contract: string
 ): Promise<string | null> {
 ): Promise<string | null> {
-  const chainId = coalesceChainId(chain);
-
-  let ret = await client.viewFunction(tokenAccount, "get_foreign_asset", {
-    chain: chainId,
-    address: contract,
-  });
-  if (ret === "") return null;
-  else return ret;
+  const ret = await callFunctionNear(
+    provider,
+    tokenAccount,
+    "get_foreign_asset",
+    {
+      chain: coalesceChainId(chain),
+      address: contract,
+    }
+  );
+  return ret !== "" ? ret : null;
 }
 }

+ 7 - 15
sdk/js/src/token_bridge/getIsTransferCompleted.ts

@@ -2,7 +2,6 @@ import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
 import { Connection, PublicKey } from "@solana/web3.js";
 import { Connection, PublicKey } from "@solana/web3.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { Algodv2, bigIntToBytes } from "algosdk";
 import { Algodv2, bigIntToBytes } from "algosdk";
-import { Account as nearAccount } from "near-api-js";
 import axios from "axios";
 import axios from "axios";
 import { ethers } from "ethers";
 import { ethers } from "ethers";
 import { fromUint8Array } from "js-base64";
 import { fromUint8Array } from "js-base64";
@@ -14,10 +13,12 @@ import {
   MAX_BITS,
   MAX_BITS,
   _parseVAAAlgorand,
   _parseVAAAlgorand,
 } from "../algorand";
 } from "../algorand";
+import { callFunctionNear } from "../utils/near";
 import { getSignedVAAHash } from "../bridge";
 import { getSignedVAAHash } from "../bridge";
 import { Bridge__factory } from "../ethers-contracts";
 import { Bridge__factory } from "../ethers-contracts";
 import { importCoreWasm } from "../solana/wasm";
 import { importCoreWasm } from "../solana/wasm";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { safeBigIntToNumber } from "../utils/bigint";
+import { Provider } from "near-api-js/lib/providers";
 
 
 export async function getIsTransferCompletedEth(
 export async function getIsTransferCompletedEth(
   tokenBridgeAddress: string,
   tokenBridgeAddress: string,
@@ -220,24 +221,15 @@ export async function getIsTransferCompletedAlgorand(
   return retVal;
   return retVal;
 }
 }
 
 
-/**
- * <p>Returns true if this transfer was completed on Near</p>
- * @param near account
- * @param tokenAccount the Token bridge account
- * @param signedVAA VAA to check
- * @returns true if VAA has been redeemed, false otherwise
- */
 export async function getIsTransferCompletedNear(
 export async function getIsTransferCompletedNear(
-  client: nearAccount,
-  tokenAccount: string,
+  provider: Provider,
+  tokenBridge: string,
   signedVAA: Uint8Array
   signedVAA: Uint8Array
 ): Promise<boolean> {
 ): Promise<boolean> {
-  // Could we just pass in the vaa already as hex?
-  let vaa = Buffer.from(signedVAA).toString("hex");
-
+  const vaa = Buffer.from(signedVAA).toString("hex");
   return (
   return (
-    await client.viewFunction(tokenAccount, "is_transfer_completed", {
-      vaa: vaa,
+    await callFunctionNear(provider, tokenBridge, "is_transfer_completed", {
+      vaa,
     })
     })
   )[1];
   )[1];
 }
 }

+ 0 - 6
sdk/js/src/token_bridge/getIsWrappedAsset.ts

@@ -108,12 +108,6 @@ export async function getIsWrappedAssetAlgorand(
   return wormhole;
   return wormhole;
 }
 }
 
 
-/**
- * Returns whethor or not an asset on Near is a wormhole wrapped asset
- * @param tokenBridge token bridge account
- * @param asset Near asset account
- * @returns true if the asset is wrapped
- */
 export function getIsWrappedAssetNear(
 export function getIsWrappedAssetNear(
   tokenBridge: string,
   tokenBridge: string,
   asset: string
   asset: string

+ 17 - 14
sdk/js/src/token_bridge/getOriginalAsset.ts

@@ -1,17 +1,14 @@
-const sha256 = require("js-sha256");
-
-import { getNetworkInfo, Network } from "@injectivelabs/networks";
 import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
 import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
 import { Connection, PublicKey } from "@solana/web3.js";
 import { Connection, PublicKey } from "@solana/web3.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { LCDClient } from "@terra-money/terra.js";
 import { Algodv2 } from "algosdk";
 import { Algodv2 } from "algosdk";
 import { ethers } from "ethers";
 import { ethers } from "ethers";
-import { arrayify, zeroPad } from "ethers/lib/utils";
+import { arrayify, sha256, zeroPad } from "ethers/lib/utils";
 import { decodeLocalState } from "../algorand";
 import { decodeLocalState } from "../algorand";
 import { buildTokenId, isNativeCosmWasmDenom } from "../cosmwasm/address";
 import { buildTokenId, isNativeCosmWasmDenom } from "../cosmwasm/address";
 import { TokenImplementation__factory } from "../ethers-contracts";
 import { TokenImplementation__factory } from "../ethers-contracts";
 import { importTokenWasm } from "../solana/wasm";
 import { importTokenWasm } from "../solana/wasm";
-import { buildNativeId, isNativeDenom } from "../terra";
+import { buildNativeId } from "../terra";
 import { canonicalAddress } from "../cosmos";
 import { canonicalAddress } from "../cosmos";
 import {
 import {
   ChainId,
   ChainId,
@@ -27,6 +24,7 @@ import {
   hexToUint8Array,
   hexToUint8Array,
   coalesceCosmWasmChainId,
   coalesceCosmWasmChainId,
   tryHexToNativeAssetString,
   tryHexToNativeAssetString,
+  callFunctionNear,
 } from "../utils";
 } from "../utils";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { safeBigIntToNumber } from "../utils/bigint";
 import {
 import {
@@ -34,7 +32,7 @@ import {
   getIsWrappedAssetEth,
   getIsWrappedAssetEth,
   getIsWrappedAssetNear,
   getIsWrappedAssetNear,
 } from "./getIsWrappedAsset";
 } from "./getIsWrappedAsset";
-import { Account as nearAccount } from "near-api-js";
+import { Provider } from "near-api-js/lib/providers";
 
 
 // TODO: remove `as ChainId` and return number in next minor version as we can't ensure it will match our type definition
 // TODO: remove `as ChainId` and return number in next minor version as we can't ensure it will match our type definition
 export interface WormholeWrappedInfo {
 export interface WormholeWrappedInfo {
@@ -269,26 +267,31 @@ export async function getOriginalAssetAlgorand(
 }
 }
 
 
 export async function getOriginalAssetNear(
 export async function getOriginalAssetNear(
-  client: nearAccount,
+  provider: Provider,
   tokenAccount: string,
   tokenAccount: string,
   assetAccount: string
   assetAccount: string
 ): Promise<WormholeWrappedInfo> {
 ): Promise<WormholeWrappedInfo> {
-  let retVal: WormholeWrappedInfo = {
+  const retVal: WormholeWrappedInfo = {
     isWrapped: false,
     isWrapped: false,
     chainId: CHAIN_ID_NEAR,
     chainId: CHAIN_ID_NEAR,
     assetAddress: new Uint8Array(),
     assetAddress: new Uint8Array(),
   };
   };
   retVal.isWrapped = await getIsWrappedAssetNear(tokenAccount, assetAccount);
   retVal.isWrapped = await getIsWrappedAssetNear(tokenAccount, assetAccount);
   if (!retVal.isWrapped) {
   if (!retVal.isWrapped) {
-    retVal.assetAddress = sha256.sha256.hex(
-      Buffer.from(assetAccount).toString("hex")
-    );
+    retVal.assetAddress = assetAccount
+      ? arrayify(sha256(Buffer.from(assetAccount)))
+      : zeroPad(arrayify("0x"), 32);
     return retVal;
     return retVal;
   }
   }
 
 
-  let buf = await client.viewFunction(tokenAccount, "get_original_asset", {
-    token: assetAccount,
-  });
+  const buf = await callFunctionNear(
+    provider,
+    tokenAccount,
+    "get_original_asset",
+    {
+      token: assetAccount,
+    }
+  );
 
 
   retVal.chainId = buf[1];
   retVal.chainId = buf[1];
   retVal.assetAddress = hexToUint8Array(buf[0]);
   retVal.assetAddress = hexToUint8Array(buf[0]);

+ 49 - 53
sdk/js/src/token_bridge/redeem.ts

@@ -18,11 +18,12 @@ import {
   CHAIN_ID_NEAR,
   CHAIN_ID_NEAR,
   CHAIN_ID_SOLANA,
   CHAIN_ID_SOLANA,
   ChainId,
   ChainId,
-  ChainName,
   MAX_VAA_DECIMALS,
   MAX_VAA_DECIMALS,
   WSOL_ADDRESS,
   WSOL_ADDRESS,
   WSOL_DECIMALS,
   WSOL_DECIMALS,
   uint8ArrayToHex,
   uint8ArrayToHex,
+  callFunctionNear,
+  hashLookup,
 } from "../utils";
 } from "../utils";
 
 
 import { getForeignAssetNear } from ".";
 import { getForeignAssetNear } from ".";
@@ -31,10 +32,10 @@ import { _parseVAAAlgorand } from "../algorand";
 
 
 import { hexToNativeString } from "../utils/array";
 import { hexToNativeString } from "../utils/array";
 import { parseTransferPayload } from "../utils/parseVaa";
 import { parseTransferPayload } from "../utils/parseVaa";
-import { Account as nearAccount } from "near-api-js";
 import BN from "bn.js";
 import BN from "bn.js";
-import { providers as nearProviders } from "near-api-js";
 import { MsgExecuteContract as MsgExecuteContractInjective } from "@injectivelabs/sdk-ts";
 import { MsgExecuteContract as MsgExecuteContractInjective } from "@injectivelabs/sdk-ts";
+import { FunctionCallOptions } from "near-api-js/lib/account";
+import { Provider } from "near-api-js/lib/providers";
 
 
 export async function redeemOnEth(
 export async function redeemOnEth(
   tokenBridgeAddress: string,
   tokenBridgeAddress: string,
@@ -256,66 +257,63 @@ export async function redeemOnAlgorand(
   );
   );
 }
 }
 
 
-/**
- * This basically just submits the VAA to Near
- * @param client
- * @param tokenBridge Token bridge ID
- * @param vaa The VAA to be redeemed
- * @returns Transaction ID(s)
- */
 export async function redeemOnNear(
 export async function redeemOnNear(
-  client: nearAccount,
+  provider: Provider,
+  account: string,
   tokenBridge: string,
   tokenBridge: string,
   vaa: Uint8Array
   vaa: Uint8Array
-): Promise<String> {
-  let p = _parseVAAAlgorand(vaa);
+): Promise<FunctionCallOptions[]> {
+  const options: FunctionCallOptions[] = [];
+  const p = _parseVAAAlgorand(vaa);
 
 
   if (p.ToChain !== CHAIN_ID_NEAR) {
   if (p.ToChain !== CHAIN_ID_NEAR) {
     throw new Error("Not destined for NEAR");
     throw new Error("Not destined for NEAR");
   }
   }
 
 
-  let user = await client.viewFunction(tokenBridge, "hash_lookup", {
-    hash: uint8ArrayToHex(p.ToAddress as Uint8Array),
-  });
+  const { found, value: receiver } = await hashLookup(
+    provider,
+    tokenBridge,
+    uint8ArrayToHex(p.ToAddress as Uint8Array)
+  );
 
 
-  if (!user[0]) {
+  if (!found) {
     throw new Error(
     throw new Error(
       "Unregistered receiver (receiving account is not registered)"
       "Unregistered receiver (receiving account is not registered)"
     );
     );
   }
   }
 
 
-  user = user[1];
-
-  let token = await getForeignAssetNear(
-    client,
+  const token = await getForeignAssetNear(
+    provider,
     tokenBridge,
     tokenBridge,
     p.FromChain as ChainId,
     p.FromChain as ChainId,
     p.Contract as string
     p.Contract as string
   );
   );
 
 
-  if (token === "") {
-    throw new Error("Unregistered token (this been attested yet?)");
-  }
-
   if (
   if (
     (p.Contract as string) !==
     (p.Contract as string) !==
     "0000000000000000000000000000000000000000000000000000000000000000"
     "0000000000000000000000000000000000000000000000000000000000000000"
   ) {
   ) {
-    let bal = await client.viewFunction(token as string, "storage_balance_of", {
-      account_id: user,
-    });
+    if (token === "" || token === null) {
+      throw new Error("Unregistered token (has it been attested?)");
+    }
+
+    const bal = await callFunctionNear(
+      provider,
+      token as string,
+      "storage_balance_of",
+      {
+        account_id: receiver,
+      }
+    );
 
 
     if (bal === null) {
     if (bal === null) {
-      console.log("Registering ", user, " for ", token);
-      bal = nearProviders.getTransactionLastResult(
-        await client.functionCall({
-          contractId: token as string,
-          methodName: "storage_deposit",
-          args: { account_id: user, registration_only: true },
-          gas: new BN("100000000000000"),
-          attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
-        })
-      );
+      options.push({
+        contractId: token as string,
+        methodName: "storage_deposit",
+        args: { account_id: receiver, registration_only: true },
+        gas: new BN("100000000000000"),
+        attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
+      });
     }
     }
 
 
     if (
     if (
@@ -328,30 +326,28 @@ export async function redeemOnNear(
         )
         )
       ) !== 0
       ) !== 0
     ) {
     ) {
-      let bal = await client.viewFunction(
+      const bal = await callFunctionNear(
+        provider,
         token as string,
         token as string,
         "storage_balance_of",
         "storage_balance_of",
         {
         {
-          account_id: client.accountId,
+          account_id: account,
         }
         }
       );
       );
 
 
       if (bal === null) {
       if (bal === null) {
-        console.log("Registering ", client.accountId, " for ", token);
-        bal = nearProviders.getTransactionLastResult(
-          await client.functionCall({
-            contractId: token as string,
-            methodName: "storage_deposit",
-            args: { account_id: client.accountId, registration_only: true },
-            gas: new BN("100000000000000"),
-            attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
-          })
-        );
+        options.push({
+          contractId: token as string,
+          methodName: "storage_deposit",
+          args: { account_id: account, registration_only: true },
+          gas: new BN("100000000000000"),
+          attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
+        });
       }
       }
     }
     }
   }
   }
 
 
-  let result = await client.functionCall({
+  options.push({
     contractId: tokenBridge,
     contractId: tokenBridge,
     methodName: "submit_vaa",
     methodName: "submit_vaa",
     args: {
     args: {
@@ -361,7 +357,7 @@ export async function redeemOnNear(
     gas: new BN("150000000000000"),
     gas: new BN("150000000000000"),
   });
   });
 
 
-  result = await client.functionCall({
+  options.push({
     contractId: tokenBridge,
     contractId: tokenBridge,
     methodName: "submit_vaa",
     methodName: "submit_vaa",
     args: {
     args: {
@@ -371,5 +367,5 @@ export async function redeemOnNear(
     gas: new BN("150000000000000"),
     gas: new BN("150000000000000"),
   });
   });
 
 
-  return nearProviders.getTransactionLastResult(result);
+  return options;
 }
 }

+ 79 - 88
sdk/js/src/token_bridge/transfer.ts

@@ -20,7 +20,7 @@ import {
   Transaction as AlgorandTransaction,
   Transaction as AlgorandTransaction,
 } from "algosdk";
 } from "algosdk";
 import { ethers, Overrides, PayableOverrides } from "ethers";
 import { ethers, Overrides, PayableOverrides } from "ethers";
-import { isNativeDenom } from "..";
+import { getIsWrappedAssetNear, isNativeDenom } from "..";
 import {
 import {
   assetOptinCheck,
   assetOptinCheck,
   getMessageFee,
   getMessageFee,
@@ -44,16 +44,13 @@ import {
   textToUint8Array,
   textToUint8Array,
   uint8ArrayToHex,
   uint8ArrayToHex,
   CHAIN_ID_SOLANA,
   CHAIN_ID_SOLANA,
+  callFunctionNear,
 } from "../utils";
 } from "../utils";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { safeBigIntToNumber } from "../utils/bigint";
 import { isNativeDenomInjective } from "../cosmwasm";
 import { isNativeDenomInjective } from "../cosmwasm";
-import {
-  Account as nearAccount,
-  providers as nearProviders,
-} from "near-api-js";
-import { parseSequenceFromLogNear } from "../bridge/parseSequenceFromLog";
-
 const BN = require("bn.js");
 const BN = require("bn.js");
+import { FunctionCallOptions } from "near-api-js/lib/account";
+import { Provider } from "near-api-js/lib/providers";
 
 
 export async function getAllowanceEth(
 export async function getAllowanceEth(
   tokenBridgeAddress: string,
   tokenBridgeAddress: string,
@@ -725,21 +722,9 @@ export async function transferFromAlgorand(
   return txs;
   return txs;
 }
 }
 
 
-/**
- * Transfers an asset from Near to a receiver on another chain
- * @param client
- * @param coreBridge account
- * @param tokenBridge account of the token bridge
- * @param assetId account
- * @param qty Quantity to transfer
- * @param receiver Receiving account
- * @param chain Reeiving chain
- * @param fee Transfer fee
- * @param payload payload for payload3 transfers
- * @returns [Sequence number of confirmation, emitter]
- */
 export async function transferTokenFromNear(
 export async function transferTokenFromNear(
-  client: nearAccount,
+  provider: Provider,
+  account: string,
   coreBridge: string,
   coreBridge: string,
   tokenBridge: string,
   tokenBridge: string,
   assetId: string,
   assetId: string,
@@ -748,54 +733,70 @@ export async function transferTokenFromNear(
   chain: ChainId | ChainName,
   chain: ChainId | ChainName,
   fee: bigint,
   fee: bigint,
   payload: string = ""
   payload: string = ""
-): Promise<[number, string]> {
-  let wormhole = assetId.endsWith("." + tokenBridge);
+): Promise<FunctionCallOptions[]> {
+  const isWrapped = getIsWrappedAssetNear(tokenBridge, assetId);
 
 
-  let result;
+  const messageFee = await callFunctionNear(
+    provider,
+    coreBridge,
+    "message_fee",
+    {}
+  );
 
 
-  let message_fee = await client.viewFunction(coreBridge, "message_fee", {});
+  chain = coalesceChainId(chain);
 
 
-  if (wormhole) {
-    result = await client.functionCall({
-      contractId: tokenBridge,
-      methodName: "send_transfer_wormhole_token",
-      args: {
-        token: assetId,
-        amount: qty.toString(10),
-        receiver: uint8ArrayToHex(receiver),
-        chain: chain,
-        fee: fee.toString(10),
-        payload: payload,
-        message_fee: message_fee,
+  if (isWrapped) {
+    return [
+      {
+        contractId: tokenBridge,
+        methodName: "send_transfer_wormhole_token",
+        args: {
+          token: assetId,
+          amount: qty.toString(10),
+          receiver: uint8ArrayToHex(receiver),
+          chain,
+          fee: fee.toString(10),
+          payload: payload,
+          message_fee: messageFee,
+        },
+        attachedDeposit: new BN(messageFee + 1),
+        gas: new BN("100000000000000"),
       },
       },
-      attachedDeposit: new BN(message_fee + 1),
-      gas: new BN("100000000000000"),
-    });
+    ];
   } else {
   } else {
-    let bal = await client.viewFunction(assetId, "storage_balance_of", {
-      account_id: tokenBridge,
-    });
+    const options: FunctionCallOptions[] = [];
+    const bal = await callFunctionNear(
+      provider,
+      assetId,
+      "storage_balance_of",
+      {
+        account_id: tokenBridge,
+      }
+    );
     if (bal === null) {
     if (bal === null) {
       // Looks like we have to stake some storage for this asset
       // Looks like we have to stake some storage for this asset
       // for the token bridge...
       // for the token bridge...
-      nearProviders.getTransactionLastResult(
-        await client.functionCall({
-          contractId: assetId,
-          methodName: "storage_deposit",
-          args: { account_id: tokenBridge, registration_only: true },
-          gas: new BN("100000000000000"),
-          attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
-        })
-      );
+      options.push({
+        contractId: assetId,
+        methodName: "storage_deposit",
+        args: { account_id: tokenBridge, registration_only: true },
+        gas: new BN("100000000000000"),
+        attachedDeposit: new BN("2000000000000000000000"), // 0.002 NEAR
+      });
     }
     }
 
 
-    if (message_fee > 0) {
-      let bank = await client.viewFunction(tokenBridge, "bank_balance", {
-        acct: client.accountId,
-      });
+    if (messageFee > 0) {
+      const bank = await callFunctionNear(
+        provider,
+        tokenBridge,
+        "bank_balance",
+        {
+          acct: account,
+        }
+      );
 
 
       if (!bank[0]) {
       if (!bank[0]) {
-        await client.functionCall({
+        options.push({
           contractId: tokenBridge,
           contractId: tokenBridge,
           methodName: "register_bank",
           methodName: "register_bank",
           args: {},
           args: {},
@@ -804,18 +805,18 @@ export async function transferTokenFromNear(
         });
         });
       }
       }
 
 
-      if (bank[1] < message_fee) {
-        await client.functionCall({
+      if (bank[1] < messageFee) {
+        options.push({
           contractId: tokenBridge,
           contractId: tokenBridge,
           methodName: "fill_bank",
           methodName: "fill_bank",
           args: {},
           args: {},
           gas: new BN("100000000000000"),
           gas: new BN("100000000000000"),
-          attachedDeposit: new BN(message_fee),
+          attachedDeposit: new BN(messageFee),
         });
         });
       }
       }
     }
     }
 
 
-    result = await client.functionCall({
+    options.push({
       contractId: assetId,
       contractId: assetId,
       methodName: "ft_transfer_call",
       methodName: "ft_transfer_call",
       args: {
       args: {
@@ -823,34 +824,22 @@ export async function transferTokenFromNear(
         amount: qty.toString(10),
         amount: qty.toString(10),
         msg: JSON.stringify({
         msg: JSON.stringify({
           receiver: uint8ArrayToHex(receiver),
           receiver: uint8ArrayToHex(receiver),
-          chain: chain,
+          chain,
           fee: fee.toString(10),
           fee: fee.toString(10),
           payload: payload,
           payload: payload,
-          message_fee: message_fee,
+          message_fee: messageFee,
         }),
         }),
       },
       },
       attachedDeposit: new BN(1),
       attachedDeposit: new BN(1),
       gas: new BN("100000000000000"),
       gas: new BN("100000000000000"),
     });
     });
-  }
 
 
-  return parseSequenceFromLogNear(result);
+    return options;
+  }
 }
 }
 
 
-/**
- * Transfers NEAR from Near to a receiver on another chain
- * @param client
- * @param coreBridge account
- * @param tokenBridge account of the token bridge
- * @param qty Quantity to transfer
- * @param receiver Receiving account
- * @param chain Reeiving chain
- * @param fee Transfer fee
- * @param payload payload for payload3 transfers
- * @returns [Sequence number of confirmation, emitter]
- */
 export async function transferNearFromNear(
 export async function transferNearFromNear(
-  client: nearAccount,
+  provider: Provider,
   coreBridge: string,
   coreBridge: string,
   tokenBridge: string,
   tokenBridge: string,
   qty: bigint,
   qty: bigint,
@@ -858,22 +847,24 @@ export async function transferNearFromNear(
   chain: ChainId | ChainName,
   chain: ChainId | ChainName,
   fee: bigint,
   fee: bigint,
   payload: string = ""
   payload: string = ""
-): Promise<[number, string]> {
-  let message_fee = await client.viewFunction(coreBridge, "message_fee", {});
-
-  let result = await client.functionCall({
+): Promise<FunctionCallOptions> {
+  const messageFee = await callFunctionNear(
+    provider,
+    coreBridge,
+    "message_fee",
+    {}
+  );
+  return {
     contractId: tokenBridge,
     contractId: tokenBridge,
     methodName: "send_transfer_near",
     methodName: "send_transfer_near",
     args: {
     args: {
       receiver: uint8ArrayToHex(receiver),
       receiver: uint8ArrayToHex(receiver),
-      chain: chain,
+      chain: coalesceChainId(chain),
       fee: fee.toString(10),
       fee: fee.toString(10),
       payload: payload,
       payload: payload,
-      message_fee: message_fee,
+      message_fee: messageFee,
     },
     },
-    attachedDeposit: new BN(qty.toString(10)).add(new BN(message_fee)),
+    attachedDeposit: new BN(qty.toString(10)).add(new BN(messageFee)),
     gas: new BN("100000000000000"),
     gas: new BN("100000000000000"),
-  });
-
-  return parseSequenceFromLogNear(result);
+  };
 }
 }

+ 17 - 5
sdk/js/src/utils/array.ts

@@ -1,6 +1,7 @@
 import { arrayify, zeroPad } from "@ethersproject/bytes";
 import { arrayify, zeroPad } from "@ethersproject/bytes";
 import { PublicKey } from "@solana/web3.js";
 import { PublicKey } from "@solana/web3.js";
-import { hexValue, hexZeroPad, stripZeros } from "ethers/lib/utils";
+import { hexValue, hexZeroPad, sha256, stripZeros } from "ethers/lib/utils";
+import { Provider as NearProvider } from "near-api-js/lib/providers";
 import {
 import {
   hexToNativeAssetStringAlgorand,
   hexToNativeAssetStringAlgorand,
   nativeStringToHexAlgorand,
   nativeStringToHexAlgorand,
@@ -28,6 +29,7 @@ import {
   isTerraChain,
   isTerraChain,
   CHAIN_ID_PYTHNET,
   CHAIN_ID_PYTHNET,
 } from "./consts";
 } from "./consts";
+import { hashLookup } from "./near";
 
 
 /**
 /**
  *
  *
@@ -96,7 +98,7 @@ export const tryUint8ArrayToNative = (
     // wormhole-chain addresses are always 20 bytes.
     // wormhole-chain addresses are always 20 bytes.
     return humanAddress("wormhole", a.slice(-20));
     return humanAddress("wormhole", a.slice(-20));
   } else if (chainId === CHAIN_ID_NEAR) {
   } else if (chainId === CHAIN_ID_NEAR) {
-    throw Error("uint8ArrayToNative: Near not supported yet.");
+    throw Error("uint8ArrayToNative: Use tryHexToNativeStringNear instead.");
   } else if (chainId === CHAIN_ID_OSMOSIS) {
   } else if (chainId === CHAIN_ID_OSMOSIS) {
     throw Error("uint8ArrayToNative: Osmosis not supported yet.");
     throw Error("uint8ArrayToNative: Osmosis not supported yet.");
   } else if (chainId === CHAIN_ID_SUI) {
   } else if (chainId === CHAIN_ID_SUI) {
@@ -112,6 +114,18 @@ export const tryUint8ArrayToNative = (
   }
   }
 };
 };
 
 
+export const tryHexToNativeStringNear = async (
+  provider: NearProvider,
+  tokenBridge: string,
+  address: string
+): Promise<string> => {
+  const { found, value } = await hashLookup(provider, tokenBridge, address);
+  if (!found) {
+    throw new Error("Address not found");
+  }
+  return value;
+};
+
 /**
 /**
  *
  *
  * Convert an address in a wormhole's 32-byte hex representation into a chain's native
  * Convert an address in a wormhole's 32-byte hex representation into a chain's native
@@ -214,9 +228,7 @@ export const tryNativeToHexString = (
   } else if (chainId == CHAIN_ID_WORMHOLE_CHAIN) {
   } else if (chainId == CHAIN_ID_WORMHOLE_CHAIN) {
     return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
     return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
   } else if (chainId === CHAIN_ID_NEAR) {
   } else if (chainId === CHAIN_ID_NEAR) {
-    return uint8ArrayToHex(
-      zeroPad(new Uint8Array(Buffer.from(address, "ascii")), 32)
-    );
+    return uint8ArrayToHex(arrayify(sha256(Buffer.from(address))));
   } else if (chainId === CHAIN_ID_OSMOSIS) {
   } else if (chainId === CHAIN_ID_OSMOSIS) {
     throw Error("hexToNativeString: Osmosis not supported yet.");
     throw Error("hexToNativeString: Osmosis not supported yet.");
   } else if (chainId === CHAIN_ID_SUI) {
   } else if (chainId === CHAIN_ID_SUI) {

+ 69 - 0
sdk/js/src/utils/near.ts

@@ -1,4 +1,7 @@
 import nearAPI from "near-api-js";
 import nearAPI from "near-api-js";
+import BN from "bn.js";
+import { Provider } from "near-api-js/lib/providers";
+import { CodeResult } from "near-api-js/lib/providers/provider";
 
 
 export function logNearGas(result: any, comment: string) {
 export function logNearGas(result: any, comment: string) {
   const { totalGasBurned, totalTokensBurned } = result.receipts_outcome.reduce(
   const { totalGasBurned, totalTokensBurned } = result.receipts_outcome.reduce(
@@ -24,3 +27,69 @@ export function logNearGas(result: any, comment: string) {
     totalTokensBurned
     totalTokensBurned
   );
   );
 }
 }
+
+export async function hashAccount(
+  provider: Provider,
+  tokenBridge: string,
+  account: string
+): Promise<{ isRegistered: boolean; accountHash: string }> {
+  // Near can have account names up to 64 bytes, but wormhole only supports 32
+  // As a result, we have to hash our account names with sha256
+  const [isRegistered, accountHash] = await callFunctionNear(
+    provider,
+    tokenBridge,
+    "hash_account",
+    { account }
+  );
+  return {
+    isRegistered,
+    accountHash,
+  };
+}
+
+export async function hashLookup(
+  provider: Provider,
+  tokenBridge: string,
+  hash: string
+): Promise<{ found: boolean; value: string }> {
+  const [found, value] = await callFunctionNear(
+    provider,
+    tokenBridge,
+    "hash_lookup",
+    {
+      hash,
+    }
+  );
+  return {
+    found,
+    value,
+  };
+}
+
+export function registerAccount(account: string, tokenBridge: string) {
+  return {
+    contractId: tokenBridge,
+    methodName: "register_account",
+    args: { account },
+    gas: new BN("100000000000000"),
+    attachedDeposit: new BN("2000000000000000000000"),
+  };
+}
+
+export async function callFunctionNear(
+  provider: Provider,
+  accountId: string,
+  methodName: string,
+  args?: any
+) {
+  const response = await provider.query<CodeResult>({
+    request_type: "call_function",
+    account_id: accountId,
+    method_name: methodName,
+    args_base64: args
+      ? Buffer.from(JSON.stringify(args)).toString("base64")
+      : "",
+    finality: "final",
+  });
+  return JSON.parse(Buffer.from(response.result).toString());
+}

+ 1 - 0
solana/devnet_setup.sh

@@ -101,6 +101,7 @@ node build/main.js submit -c solana -n devnet "$REGISTER_TERRA_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_BSC_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_BSC_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_ALGO_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_ALGO_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_TERRA2_TOKEN_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_TERRA2_TOKEN_BRIDGE_VAA"
+node build/main.js submit -c solana -n devnet "$REGISTER_NEAR_TOKEN_BRIDGE_VAA"
 # Register the NFT Bridge Endpoint on ETH
 # Register the NFT Bridge Endpoint on ETH
 node build/main.js submit -c solana -n devnet "$REGISTER_ETH_NFT_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_ETH_NFT_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_TERRA_NFT_BRIDGE_VAA"
 node build/main.js submit -c solana -n devnet "$REGISTER_TERRA_NFT_BRIDGE_VAA"

+ 2 - 0
terra/tools/deploy.js

@@ -268,6 +268,8 @@ const contract_registrations = {
     process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA,
     process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA,
     // TERRA2
     // TERRA2
     process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA,
     process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA,
+    // NEAR
+    process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA,
   ],
   ],
   "nft_bridge.wasm": [
   "nft_bridge.wasm": [
     // Solana
     // Solana