ci: switch from ganache to anvil

This commit is contained in:
Evan Gray 2024-04-04 11:44:02 -04:00 committed by Evan Gray
parent fcabf0c99e
commit 77b4ddc812
36 changed files with 352 additions and 422 deletions

View File

@ -34,8 +34,7 @@ jobs:
kubectl config set-context ci --namespace=$DEPLOY_NS
kubectl config use-context ci
# temporarily set --guardiand_loglevel=info to debug https://github.com/wormhole-foundation/wormhole/issues/3052
- run: tilt ci --timeout 45m0s -- --ci --namespace=$DEPLOY_NS --num=2 --guardiand_loglevel=info
- run: tilt ci --timeout 45m0s -- --ci --namespace=$DEPLOY_NS --num=2
timeout-minutes: 60
# Clean up k8s resources

View File

@ -37,7 +37,7 @@ Launch the devnet:
tilt up
By default this runs a network consisting of one guardian, two ganache (Eth) chains, a Solana test validator, an Algorand sandbox, and LocalTerra for both Terra Classic and Terra 2. If you want to work on non-consensus parts of the code, running with a single guardian is easiest since you won't have to wait for k8s to restart all pods. See the usage guide below for arguments to customize the tilt network.
By default this runs a network consisting of one guardian, two anvil (Eth) chains, a Solana test validator, an Algorand sandbox, and LocalTerra for both Terra Classic and Terra 2. If you want to work on non-consensus parts of the code, running with a single guardian is easiest since you won't have to wait for k8s to restart all pods. See the usage guide below for arguments to customize the tilt network.
## Usage
@ -140,28 +140,40 @@ To re-generate these files run `rm -rf node/pkg/proto && docker build --target g
### Call gRPC services
<!-- cspell:disable-next-line -->
<!-- cspell:disable -->
tools/bin/grpcurl -protoset <(tools/bin/buf build -o -) -plaintext localhost:7072 spy.v1.SpyRPCService/SubscribeSignedVAA
<!-- cspell:enable -->
With parameters (using proto json encoding):
<!-- cspell:disable-next-line -->
<!-- cspell:disable -->
tools/bin/grpcurl -protoset <(tools/bin/buf build -o -) \
-d '{"filters": [{"emitter_filter": {"emitter_address": "574108aed69daf7e625a361864b1f74d13702f2ca56de9660e566d1d8691848d", "chain_id": "CHAIN_ID_SOLANA"}}]}' \
-plaintext localhost:7072 spy.v1.SpyRPCService/SubscribeSignedVAA
<!-- cspell:enable -->
### Post messages
To Solana:
<!-- cspell:disable-next-line -->
<!-- cspell:disable -->
kubectl exec solana-devnet-0 -c setup -- client post-message Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o 1 confirmed ffff
<!-- cspell:enable -->
To Solana as CPI instruction:
<!-- cspell:disable-next-line -->
<!-- cspell:disable -->
kubectl exec solana-devnet-0 -c setup -- client post-message --proxy CP1co2QMMoDPbsmV7PGcUTLFwyhgCgTXt25gLQ5LewE1 Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o 1 confirmed ffff
<!-- cspell:enable -->
### Observation Requests
kubectl exec -it guardian-0 -- /guardiand admin send-observation-request --socket /tmp/admin.sock 1 4636d8f7593c78a5092bed13dec765cc705752653db5eb1498168c92345cd389

View File

@ -534,7 +534,7 @@ k8s_yaml_with_ns("devnet/eth-devnet.yaml")
k8s_resource(
"eth-devnet",
port_forwards = [
port_forward(8545, name = "Ganache RPC [:8545]", host = webHost),
port_forward(8545, name = "Anvil RPC [:8545]", host = webHost),
],
labels = ["evm"],
trigger_mode = trigger_mode,
@ -546,7 +546,7 @@ if evm2:
k8s_resource(
"eth-devnet2",
port_forwards = [
port_forward(8546, name = "Ganache RPC [:8546]", host = webHost),
port_forward(8546, 8545, name = "Anvil RPC [:8546]", host = webHost),
],
labels = ["evm"],
trigger_mode = trigger_mode,

View File

@ -31,19 +31,16 @@ spec:
spec:
terminationGracePeriodSeconds: 1
containers:
- name: ganache
- name: anvil
image: eth-node
command:
- npx
- ganache-cli
- --logging.quiet
- --wallet.defaultBalance=10000
- --wallet.deterministic
- --chain.time="1970-01-01T00:00:00+00:00"
- anvil
- --silent
- --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
- --block-time=1
- --host=0.0.0.0
- --wallet.totalAccounts=13
- --chain.chainId=1337
- --chain.asyncRequestProcessing=false
- --accounts=13
- --chain-id=1337
ports:
- containerPort: 8545
name: rpc
@ -64,11 +61,5 @@ spec:
initialDelaySeconds: 90
tcpSocket:
port: 2000
- name: mine
image: eth-node
command:
- /bin/sh
- -c
- "cd ../../ethereum && npx truffle exec mine.js"
---

View File

@ -32,19 +32,16 @@ spec:
spec:
terminationGracePeriodSeconds: 1
containers:
- name: ganache
- name: anvil
image: eth-node
command:
- npx
- ganache-cli
- --logging.quiet
- --wallet.defaultBalance=10000
- --wallet.deterministic
- --chain.time="1970-01-01T00:00:00+00:00"
- anvil
- --silent
- --mnemonic=myth like bonus scare over problem client lizard pioneer submit female collect
- --block-time=1
- --host=0.0.0.0
- --wallet.totalAccounts=13
- --chain.chainId=1397
- --chain.asyncRequestProcessing=false
- --accounts=13
- --chain-id=1397
ports:
- containerPort: 8545
name: rpc
@ -65,9 +62,3 @@ spec:
initialDelaySeconds: 90
tcpSocket:
port: 2000
- name: mine
image: eth-node
command:
- /bin/sh
- -c
- "cd ../../ethereum && npx truffle exec mine.js"

View File

@ -14,6 +14,7 @@ RUN $HOME/.foundry/bin/foundryup
RUN ls $HOME/.foundry/bin
# Run as user, otherwise, npx explodes.
RUN mv /root/.foundry/bin/anvil /bin/anvil
RUN mv /root/.foundry/bin/forge /bin/forge
USER 1000

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bash
# This script copies package{-lock}.json from a running container.
set -e
kubectl cp -c ganache eth-devnet-0:package.json package.json
kubectl cp -c ganache eth-devnet-0:package-lock.json package-lock.json

View File

@ -1,36 +0,0 @@
/*
This script advances Ganache network state. It runs as a sidecar pod alongside the devnet and
ensures that manual token transfers triggered through the web UI will be able to be confirmed.
*/
advanceBlock = () => {
return new Promise((resolve, reject) => {
web3.currentProvider.send({
jsonrpc: "2.0",
method: "evm_mine",
id: new Date().getTime()
}, (err, result) => {
if (err) {
return reject(err);
}
const newBlockHash = web3.eth.getBlock('latest').hash;
return resolve(newBlockHash)
});
});
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
module.exports = function(callback) {
const fn = async () => {
while (true) {
await advanceBlock();
await sleep(1000);
}
}
fn().catch(reason => console.error(reason))
}

View File

@ -19,6 +19,9 @@ type (
// maxCacheSize is used to trim the cache.
maxCacheSize int
// unsafeDevMode is used to suppress warnings in dev mode.
unsafeDevMode bool
// mutex is used to protect the cache.
mutex sync.Mutex
}
@ -32,10 +35,11 @@ type (
)
// NewBlocksByTimestamp creates an empty cache of blocks by timestamp.
func NewBlocksByTimestamp(maxCacheSize int) *BlocksByTimestamp {
func NewBlocksByTimestamp(maxCacheSize int, unsafeDevMode bool) *BlocksByTimestamp {
return &BlocksByTimestamp{
cache: Blocks{},
maxCacheSize: maxCacheSize,
cache: Blocks{},
maxCacheSize: maxCacheSize,
unsafeDevMode: unsafeDevMode,
}
}
@ -55,12 +59,15 @@ func (bts *BlocksByTimestamp) AddLatest(logger *zap.Logger, timestamp uint64, bl
}
}
logger.Warn("rollback detected in timestamp cache",
zap.Uint64("oldLatestBlockNum", bts.cache[l-1].BlockNum),
zap.Uint64("oldLatestTimestamp", bts.cache[l-1].Timestamp),
zap.Uint64("newLatestBlockNum", blockNum),
zap.Uint64("newLatestTimestamp", timestamp),
)
// Anvil trips this when using `anvil_mine`
if !bts.unsafeDevMode {
logger.Warn("rollback detected in timestamp cache",
zap.Uint64("oldLatestBlockNum", bts.cache[l-1].BlockNum),
zap.Uint64("oldLatestTimestamp", bts.cache[l-1].Timestamp),
zap.Uint64("newLatestBlockNum", blockNum),
zap.Uint64("newLatestTimestamp", timestamp),
)
}
bts.cache = bts.cache[:idx+1]
}

View File

@ -24,7 +24,7 @@ func cacheIsValid(t *testing.T, bts *BlocksByTimestamp) bool {
}
func TestBlocksByTimestamp_TestCacheIsValid(t *testing.T) {
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS)
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS, false)
// Empty cache is valid.
assert.True(t, cacheIsValid(t, bts))
@ -61,7 +61,7 @@ func TestBlocksByTimestamp_TestCacheIsValid(t *testing.T) {
func TestBlocksByTimestamp_AddLatest(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS)
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS, false)
bts.AddLatest(logger, 1698621628, 420)
bts.AddLatest(logger, 1698621628, 421)
@ -89,7 +89,7 @@ func TestBlocksByTimestamp_AddLatest(t *testing.T) {
func TestBlocksByTimestamp_AddLatestRollbackEverything(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS)
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS, false)
bts.AddLatest(logger, 1698621628, 420)
require.Equal(t, 1, len(bts.cache))
@ -138,7 +138,7 @@ func TestBlocksByTimestamp_AddLatestRollbackEverything(t *testing.T) {
func TestBlocksByTimestamp_AddLatestShouldTrimTheCache(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(5)
bts := NewBlocksByTimestamp(5, false)
bts.AddLatest(logger, 1698621628, 420)
bts.AddLatest(logger, 1698621628, 421)
@ -161,7 +161,7 @@ func TestBlocksByTimestamp_AddLatestShouldTrimTheCache(t *testing.T) {
func TestBlocksByTimestamp_AddBatch(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS)
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS, false)
// First create a cache with some gaps in it.
bts.AddLatest(logger, 1698621628, 420)
@ -192,7 +192,7 @@ func TestBlocksByTimestamp_AddBatch(t *testing.T) {
func TestBlocksByTimestamp_AddBatchShouldTrim(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(8)
bts := NewBlocksByTimestamp(8, false)
// First create a cache with some gaps in it.
bts.AddLatest(logger, 1698621628, 420)
@ -249,7 +249,7 @@ func TestBlocksByTimestamp_SearchForTimestamp(t *testing.T) {
func TestBlocksByTimestamp_LookUp(t *testing.T) {
logger := zap.NewNop()
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS)
bts := NewBlocksByTimestamp(BTS_MAX_BLOCKS, false)
// Empty cache.
prev, next, found := bts.LookUp(1698621627)

View File

@ -260,7 +260,7 @@ func (w *Watcher) Run(parentCtx context.Context) error {
}
if w.ccqConfig.TimestampCacheSupported {
w.ccqTimestampCache = NewBlocksByTimestamp(BTS_MAX_BLOCKS)
w.ccqTimestampCache = NewBlocksByTimestamp(BTS_MAX_BLOCKS, w.unsafeDevMode)
}
errC := make(chan error)
@ -702,7 +702,6 @@ func (w *Watcher) getFinality(ctx context.Context) (bool, bool, error) {
finalized := false
safe := false
if w.unsafeDevMode {
// Devnet supports finalized and safe (although they returns the same value as latest).
finalized = true
safe = true
} else if w.chainID == vaa.ChainIDAcala ||

View File

@ -1,3 +1,13 @@
process.env.CI = true;
const warn = console.warn;
console.warn = function (x) {
if (
x !==
"bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)"
) {
warn(x);
}
};
module.exports = {};

View File

@ -1,34 +1,26 @@
import {
afterAll,
beforeAll,
describe,
expect,
jest,
test,
} from "@jest/globals";
import { beforeAll, describe, expect, jest, test } from "@jest/globals";
import axios, { AxiosResponse } from "axios";
import Web3, { ETH_DATA_FORMAT } from "web3";
import axios from "axios";
import { AxiosResponse } from "axios";
import {
ChainQueryType,
EthCallByTimestampQueryRequest,
EthCallByTimestampQueryResponse,
EthCallData,
EthCallQueryRequest,
EthCallByTimestampQueryRequest,
EthCallQueryResponse,
EthCallWithFinalityQueryRequest,
EthCallWithFinalityQueryResponse,
PerChainQueryRequest,
QueryRequest,
sign,
QueryResponse,
EthCallQueryResponse,
EthCallByTimestampQueryResponse,
EthCallWithFinalityQueryResponse,
sign,
} from "..";
jest.setTimeout(125000);
const CI = process.env.CI;
const ENV = "DEVNET";
const ETH_NODE_URL = CI ? "ws://eth-devnet:8545" : "ws://localhost:8545";
const ETH_NODE_URL = CI ? "http://eth-devnet:8545" : "http://localhost:8545";
const SERVER_URL = CI ? "http://query-server:" : "http://localhost:";
const CCQ_SERVER_URL = SERVER_URL + "6069/v1";
@ -44,10 +36,6 @@ beforeAll(() => {
web3 = new Web3(ETH_NODE_URL);
});
afterAll(() => {
web3.provider?.disconnect();
});
function createTestEthCallData(
to: string,
name: string,
@ -162,7 +150,7 @@ describe("eth call", () => {
);
const ecr = queryResponse.responses[0].response as EthCallQueryResponse;
expect(ecr.blockNumber).toEqual(BigInt(blockNumber));
expect(ecr.blockNumber.toString()).toEqual(BigInt(blockNumber).toString());
expect(ecr.blockHash).toEqual(
(await web3.eth.getBlock(BigInt(blockNumber))).hash
);
@ -176,8 +164,7 @@ describe("eth call", () => {
"0x0000000000000000000000000000000000000000000000000000000000000012"
);
});
// TODO: This test works in Goerli testnet but not devnet. Try it again after PR #3395 lands.
test.skip("get block by hash should work", async () => {
test("get block by hash should work", async () => {
const nameCallData = createTestEthCallData(WETH_ADDRESS, "name", "string");
const decimalsCallData = createTestEthCallData(
WETH_ADDRESS,
@ -461,11 +448,15 @@ describe("eth call", () => {
const ecr = queryResponse.responses[0]
.response as EthCallByTimestampQueryResponse;
expect(ecr.targetBlockNumber).toEqual(BigInt(targetBlockNumber));
expect(ecr.targetBlockNumber.toString()).toEqual(
BigInt(targetBlockNumber).toString()
);
expect(ecr.targetBlockHash).toEqual(
(await web3.eth.getBlock(BigInt(targetBlockNumber))).hash
);
expect(ecr.followingBlockNumber).toEqual(BigInt(followingBlockNumber));
expect(ecr.followingBlockNumber.toString()).toEqual(
BigInt(followingBlockNumber).toString()
);
expect(ecr.followingBlockHash).toEqual(
(await web3.eth.getBlock(BigInt(followingBlockNumber))).hash
);
@ -523,11 +514,15 @@ describe("eth call", () => {
const ecr = queryResponse.responses[0]
.response as EthCallByTimestampQueryResponse;
expect(ecr.targetBlockNumber).toEqual(BigInt(targetBlockNumber));
expect(ecr.targetBlockNumber.toString()).toEqual(
BigInt(targetBlockNumber).toString()
);
expect(ecr.targetBlockHash).toEqual(
(await web3.eth.getBlock(BigInt(targetBlockNumber))).hash
);
expect(ecr.followingBlockNumber).toEqual(BigInt(followingBlockNumber));
expect(ecr.followingBlockNumber.toString()).toEqual(
BigInt(followingBlockNumber).toString()
);
expect(ecr.followingBlockHash).toEqual(
(await web3.eth.getBlock(BigInt(followingBlockNumber))).hash
);
@ -703,9 +698,9 @@ describe("eth call", () => {
"decimals",
"uint8"
);
// Jump into the future a bit so the watcher has to wait for finality.
const blockNumber =
Number(await web3.eth.getBlockNumber(ETH_DATA_FORMAT)) + 10;
const blockNumber = Number(
(await web3.eth.getBlock("finalized", false, ETH_DATA_FORMAT)).number
);
const ethCall = new EthCallWithFinalityQueryRequest(
blockNumber.toString(16),
"finalized",
@ -740,7 +735,7 @@ describe("eth call", () => {
const ecr = queryResponse.responses[0]
.response as EthCallWithFinalityQueryResponse;
expect(ecr.blockNumber).toEqual(BigInt(blockNumber));
expect(ecr.blockNumber.toString()).toEqual(BigInt(blockNumber).toString());
expect(ecr.blockHash).toEqual(
(await web3.eth.getBlock(BigInt(blockNumber))).hash
);
@ -881,7 +876,9 @@ describe("eth call", () => {
);
const ecr = queryResponse.responses[0].response as EthCallQueryResponse;
expect(ecr.blockNumber).toEqual(BigInt(blockNumber));
expect(ecr.blockNumber.toString()).toEqual(
BigInt(blockNumber).toString()
);
expect(ecr.blockHash).toEqual(
(await web3.eth.getBlock(BigInt(blockNumber))).hash
);

View File

@ -1,3 +1,28 @@
process.env.CI = true;
const info = console.info;
console.info = function (x) {
if (x !== "secp256k1 unavailable, reverting to browser version") {
info(x);
}
};
const warn = console.warn;
console.warn = function (x) {
if (
x !==
"bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)" &&
!(
typeof x === "object" &&
x
.toString()
.includes(
"RPC Validation Error: The response returned from RPC server does not match the TypeScript definition. This is likely because the SDK version is not compatible with the RPC server."
)
)
) {
warn(x);
}
};
export default {};

View File

@ -5,5 +5,5 @@
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"testPathIgnorePatterns": ["__tests__/utils"],
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
"testTimeout": 60000
"testTimeout": 300000
}

View File

@ -18,10 +18,10 @@
"build-lib": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json && node scripts/copyEthersTypes.js",
"build-all": "npm run build-deps && npm run build-lib",
"docs": "typedoc src/index.ts",
"test": "DEV=true NETWORK=DEVNET jest --config jestconfig.json --verbose",
"test-ci": "NETWORK=DEVNET NEAR_NO_LOGS=true jest --config jestconfig.json --verbose --setupFiles ./ci-config.js --forceExit",
"test-relayer-mainnet": "ENV=mainnet NETWORK=MAINNET npx jest --config jestconfig.json --verbose ./src/relayer/",
"test-relayer-testnet": "ENV=testnet NETWORK=TESTNET npx jest --config jestconfig.json --verbose ./src/relayer/",
"test": "DEV=true NETWORK=DEVNET jest --verbose",
"test-ci": "NETWORK=DEVNET NEAR_NO_LOGS=true jest --verbose --setupFiles ./ci-config.js --forceExit",
"test-relayer-mainnet": "ENV=mainnet NETWORK=MAINNET npx jest --verbose ./src/relayer/",
"test-relayer-testnet": "ENV=testnet NETWORK=TESTNET npx jest --verbose ./src/relayer/",
"build": "npm run build-all",
"format": "echo \"disabled: prettier --write \"src/**/*.ts\"\"",
"lint": "tslint -p tsconfig.json",

View File

@ -27,8 +27,6 @@ import { PopulateData, TmplSig } from "../TmplSig";
const CORE_ID = BigInt(1004);
const TOKEN_BRIDGE_ID = BigInt(1006);
jest.setTimeout(120000);
describe("Unit Tests", () => {
describe("Algorand unit tests", () => {
test("Test TmplSig populate()", (done) => {

View File

@ -16,7 +16,7 @@ import {
getSignedVAABySequence,
waitForTerraExecution,
} from "../../token_bridge/__tests__/utils/helpers";
import { CHAIN_ID_SEI, CHAIN_ID_TERRA2 } from "../../utils/consts";
import { CHAIN_ID_SEI } from "../../utils/consts";
const TERRA2_PRIVATE_KEY_4 =
"bounce success option birth apple portion aunt rural episode solution hockey pencil lend session cause hedgehog slender journey system canvas decorate razor catch empty";
@ -58,7 +58,6 @@ const terraBroadcastTxAndGetSignedVaa = async (
if (!txSequence) {
throw new Error("tx sequence not found");
}
console.log(`${CHAIN_ID_SEI}/${emitter}/${txSequence}`);
return await getSignedVAABySequence(CHAIN_ID_SEI, txSequence, emitter);
};
@ -79,6 +78,5 @@ describe("IBC Watcher Integration Tests", () => {
terraWallet,
await getEmitterAddressTerra(terraWalletAddress)
);
console.log(postedVaa);
});
});

View File

@ -55,8 +55,6 @@ import {
getSignedVaaSolana,
} from "./utils/getSignedVaa";
jest.setTimeout(120000);
const APTOS_NFT_BRIDGE_ADDRESS = CONTRACTS.DEVNET.aptos.nft_bridge;
const ETH_NFT_BRIDGE_ADDRESS = CONTRACTS.DEVNET.ethereum.nft_bridge;
const SOLANA_NFT_BRIDGE_ADDRESS = CONTRACTS.DEVNET.solana.nft_bridge;
@ -69,7 +67,7 @@ let faucet: FaucetClient;
// ethereum setup
const web3 = new Web3(ETH_NODE_URL);
const ethProvider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const ethProvider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const ethSigner = new ethers.Wallet(ETH_PRIVATE_KEY8, ethProvider);
// solana setup
@ -86,7 +84,6 @@ beforeEach(async () => {
afterAll(async () => {
(web3.currentProvider as any).disconnect();
await ethProvider.destroy();
});
describe("Aptos NFT SDK tests", () => {
@ -112,6 +109,7 @@ describe("Aptos NFT SDK tests", () => {
CHAIN_ID_APTOS,
aptosAccount.address().toUint8Array()
);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// observe tx and get vaa
const ethTransferVaa = await getSignedVaaEthereum(ethTransferTx);
@ -313,6 +311,7 @@ describe("Aptos NFT SDK tests", () => {
tryNativeToUint8Array(aptosAccount.address().toString(), CHAIN_ID_APTOS)
);
expect(ethTransferTx.status).toBe(1);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// observe tx and get vaa
const ethTransferVaa = await getSignedVaaEthereum(ethTransferTx);
@ -455,6 +454,7 @@ describe("Aptos NFT SDK tests", () => {
CHAIN_ID_APTOS,
aptosAccount.address().toUint8Array()
);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// observe txs and get vaas
const ethTransferVaa1 = await getSignedVaaEthereum(ethTransferTx1);

View File

@ -1,11 +1,4 @@
import {
afterEach,
beforeEach,
describe,
expect,
jest,
test,
} from "@jest/globals";
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
import { getAssociatedTokenAddress } from "@solana/spl-token";
import {
Connection,
@ -16,10 +9,10 @@ import {
import { BigNumberish, ethers } from "ethers";
import Web3 from "web3";
import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CONTRACTS,
ChainId,
nft_bridge,
} from "../..";
import { postVaaSolanaWithRetry } from "../../solana";
@ -34,11 +27,9 @@ import {
} from "./utils/consts";
import { getSignedVaaEthereum, getSignedVaaSolana } from "./utils/getSignedVaa";
jest.setTimeout(120000);
// ethereum setup
const web3 = new Web3(ETH_NODE_URL);
let provider: ethers.providers.WebSocketProvider;
let provider: ethers.providers.JsonRpcProvider;
let signer: ethers.Wallet;
// solana setup
@ -47,14 +38,10 @@ const keypair = Keypair.fromSecretKey(SOLANA_PRIVATE_KEY);
const payerAddress = keypair.publicKey.toString();
beforeEach(() => {
provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider); // corresponds to accounts[1]
});
afterEach(() => {
provider.destroy();
});
describe("Integration Tests", () => {
test("Send Solana SPL to Ethereum and back", (done) => {
(async () => {
@ -93,6 +80,7 @@ describe("Integration Tests", () => {
fromAddress.toString(),
CHAIN_ID_SOLANA
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
signedVAA = await getSignedVaaEthereum(transaction3);
const { name, symbol } = parseNftTransferVaa(signedVAA);

View File

@ -4,7 +4,9 @@ import { Connection, PublicKey } from "@solana/web3.js";
const ci = !!process.env.CI;
// see devnet.md
export const ETH_NODE_URL = ci ? "ws://eth-devnet:8545" : "ws://localhost:8545";
export const ETH_NODE_URL = ci
? "http://eth-devnet:8545"
: "http://localhost:8545";
export const ETH_PRIVATE_KEY =
"0x6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1"; // account 1
export const ETH_PRIVATE_KEY8 =

View File

@ -1,34 +1,33 @@
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
import { describe, expect, test } from "@jest/globals";
import { ContractReceipt, ethers } from "ethers";
import {
getNetwork,
isCI,
waitForRelay,
PRIVATE_KEY,
getGuardianRPC,
GUARDIAN_KEYS,
GUARDIAN_SET_INDEX,
GOVERNANCE_EMITTER_ADDRESS,
getArbitraryBytes32,
} from "./utils/utils";
import { getAddressInfo } from "../consts";
import { getDefaultProvider } from "../relayer/helpers";
import {
relayer,
ethers_contracts,
ethers_relayer_contracts,
tryNativeToUint8Array,
ChainId,
CHAINS,
CONTRACTS,
ChainId,
ChainName,
Network,
ethers_relayer_contracts,
relayer,
tryNativeToUint8Array,
} from "../../../";
import { GovernanceEmitter, MockGuardians } from "../../../src/mock";
import { Implementation__factory } from "../../ethers-contracts";
import { getAddressInfo } from "../consts";
import { manualDelivery } from "../relayer";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
import { getDefaultProvider } from "../relayer/helpers";
import { packEVMExecutionInfoV1 } from "../structs";
import {
GOVERNANCE_EMITTER_ADDRESS,
GUARDIAN_KEYS,
GUARDIAN_SET_INDEX,
PRIVATE_KEY,
getArbitraryBytes32,
getGuardianRPC,
getNetwork,
isCI,
waitForRelay,
} from "./utils/utils";
const network: Network = getNetwork();
const ci: boolean = isCI();
@ -42,7 +41,7 @@ const testIfNotDevnet = () => (network != "DEVNET" ? test : test.skip);
type TestChain = {
chainId: ChainId;
name: ChainName;
provider: ethers.providers.Provider;
provider: ethers.providers.StaticJsonRpcProvider;
wallet: ethers.Wallet;
wormholeRelayerAddress: string;
mockIntegrationAddress: string;
@ -160,7 +159,7 @@ const testSend = async (
notEnoughValue ? TOO_LOW_GAS_LIMIT : REASONABLE_GAS_LIMIT,
optionalParams
);
console.log(`Quoted gas delivery fee: ${value}`);
!ci && console.log(`Quoted gas delivery fee: ${value}`);
const tx = await source.mockIntegration.sendMessage(
payload,
sendToSourceChain ? source.chainId : target.chainId,
@ -168,9 +167,9 @@ const testSend = async (
0,
{ value, gasLimit: REASONABLE_GAS_LIMIT }
);
console.log(`Sent delivery request! Transaction hash ${tx.hash}`);
!ci && console.log(`Sent delivery request! Transaction hash ${tx.hash}`);
await tx.wait();
console.log("Message confirmed!");
!ci && console.log("Message confirmed!");
return tx.wait();
};
@ -178,20 +177,20 @@ const testSend = async (
describe("Wormhole Relayer Tests", () => {
test("Executes a Delivery Success", async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const rx = await testSend(arbitraryPayload);
await waitForRelay();
console.log("Checking if message was relayed");
!ci && console.log("Checking if message was relayed");
const message = await target.mockIntegration.getMessage();
expect(message).toBe(arbitraryPayload);
});
test("Executes a Delivery Success With Additional VAAs", async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const wormhole = Implementation__factory.connect(
CONTRACTS[network][sourceChain].core || "",
@ -207,7 +206,7 @@ describe("Wormhole Relayer Tests", () => {
REASONABLE_GAS_LIMIT * 2,
optionalParams
);
console.log(`Quoted gas delivery fee: ${value}`);
!ci && console.log(`Quoted gas delivery fee: ${value}`);
const tx = await source.mockIntegration.sendMessageWithAdditionalVaas(
[],
@ -224,13 +223,13 @@ describe("Wormhole Relayer Tests", () => {
{ value }
);
console.log(`Sent tx hash: ${tx.hash}`);
!ci && console.log(`Sent tx hash: ${tx.hash}`);
const rx = await tx.wait();
await waitForRelay();
console.log("Checking if message was relayed");
!ci && console.log("Checking if message was relayed");
const message = (await target.mockIntegration.getDeliveryData())
.additionalVaas[0];
const parsedMessage = await wormhole.parseVM(message);
@ -241,7 +240,7 @@ describe("Wormhole Relayer Tests", () => {
"Executes a Delivery Success with manual delivery",
async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const deliverySeq = await Implementation__factory.connect(
CONTRACTS[network][sourceChain].core || "",
@ -286,7 +285,10 @@ describe("Wormhole Relayer Tests", () => {
}
);
console.log(`Price: ${priceInfo.quote} of ${priceInfo.targetChain} wei`);
!ci &&
console.log(
`Price: ${priceInfo.quote} of ${priceInfo.targetChain} wei`
);
const deliveryRx = await manualDelivery(
sourceChain,
@ -310,9 +312,9 @@ describe("Wormhole Relayer Tests", () => {
},
target.wallet
);
console.log("Manual delivery tx hash", deliveryRx.txHash);
!ci && console.log("Manual delivery tx hash", deliveryRx.txHash);
console.log("Checking if message was relayed");
!ci && console.log("Checking if message was relayed");
const message = await target.mockIntegration.getMessage();
expect(message).toBe(arbitraryPayload);
}
@ -330,14 +332,14 @@ describe("Wormhole Relayer Tests", () => {
test("Executes a delivery with a Cross Chain Refund", async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const value = await relayer.getPrice(
sourceChain,
targetChain,
REASONABLE_GAS_LIMIT,
optionalParams
);
console.log(`Quoted gas delivery fee: ${value}`);
!ci && console.log(`Quoted gas delivery fee: ${value}`);
const startingBalance = await source.wallet.getBalance();
const tx = await relayer.sendToEvm(
@ -350,11 +352,13 @@ describe("Wormhole Relayer Tests", () => {
{ value, gasLimit: REASONABLE_GAS_LIMIT },
optionalParams
);
console.log("Sent delivery request!");
!ci && console.log("Sent delivery request!");
await tx.wait();
console.log("Message confirmed!");
!ci && console.log("Message confirmed!");
const endingBalance = await source.wallet.getBalance();
await source.provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
await waitForRelay();
const info = (await relayer.getWormholeRelayerInfo(sourceChain, tx.hash, {
@ -362,30 +366,34 @@ describe("Wormhole Relayer Tests", () => {
...optionalParams,
})) as relayer.DeliveryInfo;
await target.provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
await waitForRelay();
const newEndingBalance = await source.wallet.getBalance();
console.log(`Quoted gas delivery fee: ${value}`);
console.log(
`Cost (including gas) ${startingBalance.sub(endingBalance).toString()}`
);
!ci && console.log(`Quoted gas delivery fee: ${value}`);
!ci &&
console.log(
`Cost (including gas) ${startingBalance.sub(endingBalance).toString()}`
);
const refund = newEndingBalance.sub(endingBalance);
console.log(`Refund: ${refund.toString()}`);
console.log(
`As a percentage of original value: ${newEndingBalance
.sub(endingBalance)
.mul(100)
.div(value)
.toString()}%`
);
console.log("Confirming refund is nonzero");
!ci && console.log(`Refund: ${refund.toString()}`);
!ci &&
console.log(
`As a percentage of original value: ${newEndingBalance
.sub(endingBalance)
.mul(100)
.div(value)
.toString()}%`
);
!ci && console.log("Confirming refund is nonzero");
expect(refund.gt(0)).toBe(true);
});
test("Executes a Receiver Failure", async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const rx = await testSend(arbitraryPayload, false, true);
@ -397,7 +405,7 @@ describe("Wormhole Relayer Tests", () => {
test("Executes a receiver failure and then redelivery through SDK", async () => {
const arbitraryPayload = getArbitraryBytes32();
console.log(`Sent message: ${arbitraryPayload}`);
!ci && console.log(`Sent message: ${arbitraryPayload}`);
const rx = await testSend(arbitraryPayload, false, true);
@ -419,7 +427,7 @@ describe("Wormhole Relayer Tests", () => {
{ wormholeRelayerAddresses, ...optionalParams }
)) as relayer.DeliveryInfo;
console.log("Redelivering message");
!ci && console.log("Redelivering message");
const redeliveryReceipt = await relayer.resend(
source.wallet,
sourceChain,
@ -444,13 +452,13 @@ describe("Wormhole Relayer Tests", () => {
{ wormholeRelayerAddress: source.wormholeRelayerAddress }
);
console.log("redelivery tx:", redeliveryReceipt.hash);
!ci && console.log("redelivery tx:", redeliveryReceipt.hash);
await redeliveryReceipt.wait();
await waitForRelay();
console.log("Checking if message was relayed after redelivery");
!ci && console.log("Checking if message was relayed after redelivery");
const message2 = await target.mockIntegration.getMessage();
expect(message2).toBe(arbitraryPayload);
@ -464,9 +472,10 @@ describe("Wormhole Relayer Tests", () => {
const currentAddress =
await source.wormholeRelayer.getRegisteredWormholeRelayerContract(chain);
console.log(
`For Chain ${source.chainId}, registered chain ${chain} address: ${currentAddress}`
);
!ci &&
console.log(
`For Chain ${source.chainId}, registered chain ${chain} address: ${currentAddress}`
);
const expectedNewRegisteredAddress =
"0x0000000000000000000000001234567890123456789012345678901234567892";
@ -501,9 +510,10 @@ describe("Wormhole Relayer Tests", () => {
async () => {
const currentAddress =
await source.wormholeRelayer.getDefaultDeliveryProvider();
console.log(
`For Chain ${source.chainId}, default relay provider: ${currentAddress}`
);
!ci &&
console.log(
`For Chain ${source.chainId}, default relay provider: ${currentAddress}`
);
const expectedNewDefaultDeliveryProvider =
"0x1234567890123456789012345678901234567892";
@ -567,9 +577,10 @@ describe("Wormhole Relayer Tests", () => {
IMPLEMENTATION_STORAGE_SLOT
);
console.log(
`Current Implementation address: ${await getImplementationAddress()}`
);
!ci &&
console.log(
`Current Implementation address: ${await getImplementationAddress()}`
);
const wormholeAddress = CONTRACTS[network][sourceChain].core || "";
@ -579,10 +590,11 @@ describe("Wormhole Relayer Tests", () => {
.then((x) => x.deployed())
).address;
console.log(`Deployed!`);
console.log(
`New core relayer implementation: ${newWormholeRelayerImplementationAddress}`
);
!ci && console.log(`Deployed!`);
!ci &&
console.log(
`New core relayer implementation: ${newWormholeRelayerImplementationAddress}`
);
const timestamp = (await source.wallet.provider.getBlock("latest"))
.timestamp;
@ -598,6 +610,7 @@ describe("Wormhole Relayer Tests", () => {
);
let tx = await source.wormholeRelayer.submitContractUpgrade(firstSignedVaa);
await tx.wait();
expect(
ethers.utils.getAddress((await getImplementationAddress()).substring(26))
@ -613,7 +626,7 @@ describe("Wormhole Relayer Tests", () => {
const info = await relayer.getWormholeRelayerInfo(mySourceChain, txHash, {
environment,
});
console.log(info.stringified);
!ci && console.log(info.stringified);
});
testIfNotDevnet()("Tests custom manual delivery", async () => {
@ -626,7 +639,7 @@ describe("Wormhole Relayer Tests", () => {
const info = await relayer.getWormholeRelayerInfo(mySourceChain, txHash, {
environment,
});
console.log(info.stringified);
!ci && console.log(info.stringified);
const priceInfo = await manualDelivery(
mySourceChain,
@ -634,7 +647,7 @@ describe("Wormhole Relayer Tests", () => {
{ environment },
true
);
console.log(`Price info: ${JSON.stringify(priceInfo)}`);
!ci && console.log(`Price info: ${JSON.stringify(priceInfo)}`);
const signer = new ethers.Wallet(
PRIVATE_KEY,
@ -643,17 +656,19 @@ describe("Wormhole Relayer Tests", () => {
: getDefaultProvider(environment, priceInfo.targetChain)
);
console.log(
`Price: ${ethers.utils.formatEther(priceInfo.quote)} of ${
priceInfo.targetChain
} currency`
);
!ci &&
console.log(
`Price: ${ethers.utils.formatEther(priceInfo.quote)} of ${
priceInfo.targetChain
} currency`
);
const balance = await signer.getBalance();
console.log(
`My balance: ${ethers.utils.formatEther(balance)} of ${
priceInfo.targetChain
} currency`
);
!ci &&
console.log(
`My balance: ${ethers.utils.formatEther(balance)} of ${
priceInfo.targetChain
} currency`
);
const deliveryRx = await manualDelivery(
mySourceChain,
@ -663,7 +678,7 @@ describe("Wormhole Relayer Tests", () => {
undefined,
signer
);
console.log("Manual delivery tx hash", deliveryRx.txHash);
!ci && console.log("Manual delivery tx hash", deliveryRx.txHash);
});
});

View File

@ -3,20 +3,21 @@ import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport"
import { describe, expect, jest, test } from "@jest/globals";
import algosdk, {
Account,
OnApplicationComplete,
decodeAddress,
getApplicationAddress,
makeApplicationCallTxnFromObject,
OnApplicationComplete,
waitForConfirmation,
} from "algosdk";
import { BigNumber, ethers, utils } from "ethers";
import {
approveEth,
attestFromAlgorand,
attestFromEth,
CHAIN_ID_ALGORAND,
CHAIN_ID_ETH,
CONTRACTS,
WormholeWrappedInfo,
approveEth,
attestFromAlgorand,
attestFromEth,
createWrappedOnAlgorand,
createWrappedOnEth,
getEmitterAddressAlgorand,
@ -36,9 +37,7 @@ import {
transferFromEth,
uint8ArrayToHex,
updateWrappedOnEth,
WormholeWrappedInfo,
} from "../..";
import { TokenImplementation__factory } from "../../ethers-contracts";
import { _parseVAAAlgorand } from "../../algorand";
import {
createAsset,
@ -49,6 +48,7 @@ import {
getTempAccounts,
signSendAndConfirmAlgorand,
} from "../../algorand/__tests__/testHelpers";
import { TokenImplementation__factory } from "../../ethers-contracts";
import getSignedVAAWithRetry from "../../rpc/getSignedVAAWithRetry";
import { safeBigIntToNumber } from "../../utils/bigint";
import {
@ -61,8 +61,6 @@ import {
const CORE_ID = BigInt(1004);
const TOKEN_BRIDGE_ID = BigInt(1006);
jest.setTimeout(120000);
describe("Algorand tests", () => {
test("Algorand transfer native ALGO to Eth and back again", (done) => {
(async () => {
@ -115,7 +113,7 @@ describe("Algorand tests", () => {
{ transport: NodeHttpTransport() }
);
const pvaa = _parseVAAAlgorand(vaaBytes);
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY7, provider);
@ -262,6 +260,7 @@ describe("Algorand tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
@ -297,8 +296,6 @@ describe("Algorand tests", () => {
if (!secondFinalAlgoBal) {
throw new Error("secondFinalAlgoBal is undefined");
}
provider.destroy();
} catch (e) {
console.error("Algorand ALGO transfer error:", e);
done("Algorand ALGO transfer error");
@ -358,7 +355,7 @@ describe("Algorand tests", () => {
attestSn,
{ transport: NodeHttpTransport() }
);
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY7, provider);
@ -501,6 +498,7 @@ describe("Algorand tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
@ -537,7 +535,6 @@ describe("Algorand tests", () => {
throw new Error("secondFinalAlgoBal is undefined");
}
expect(secondFinalAlgoBal - finalAlgoBal).toBe(parseInt(Amount) * 100);
provider.destroy();
} catch (e) {
console.error("Algorand chuckNorium transfer error:", e);
done("Algorand chuckNorium transfer error");
@ -559,7 +556,7 @@ describe("Algorand tests", () => {
const algoWallet: Account = tempAccts[0];
const Amount = "10";
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY7, provider);
// attest the test token
const attestReceipt = await attestFromEth(
@ -575,6 +572,7 @@ describe("Algorand tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: attestSignedVaa } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -651,6 +649,7 @@ describe("Algorand tests", () => {
receipt,
CONTRACTS.DEVNET.ethereum.core
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: transferSignedVaa } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -776,7 +775,6 @@ describe("Algorand tests", () => {
);
expect(info.chainId).toBe(CHAIN_ID_ETH);
expect(info.isWrapped).toBe(true);
provider.destroy();
} catch (e) {
console.error("Eth <=> Algorand error:", e);
done("Eth <=> Algorand error");
@ -809,7 +807,7 @@ describe("Algorand tests", () => {
// ETH setup to transfer LUNA to Algorand
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY7, provider);
// attest the test token
const receipt = await attestFromEth(
@ -825,6 +823,7 @@ describe("Algorand tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -880,6 +879,7 @@ describe("Algorand tests", () => {
const ethEmitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: firstHalfVaa } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -925,6 +925,7 @@ describe("Algorand tests", () => {
secondHalfReceipt,
CONTRACTS.DEVNET.ethereum.core
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: secondHalfVaa } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -952,7 +953,6 @@ describe("Algorand tests", () => {
secondHalfVaa
)
).toBe(true);
provider.destroy();
} catch (e) {
console.error("new test error:", e);
done("new test error");

View File

@ -10,13 +10,13 @@ import {
import { ethers } from "ethers";
import { parseUnits } from "ethers/lib/utils";
import {
approveEth,
APTOS_TOKEN_BRIDGE_EMITTER_ADDRESS,
attestFromAptos,
attestFromEth,
CHAIN_ID_APTOS,
CHAIN_ID_ETH,
CONTRACTS,
approveEth,
attestFromAptos,
attestFromEth,
createWrappedOnAptos,
createWrappedOnEth,
createWrappedTypeOnAptos,
@ -56,8 +56,6 @@ import {
WORMHOLE_RPC_HOSTS,
} from "./utils/consts";
jest.setTimeout(120000);
describe("Aptos SDK tests", () => {
test("Transfer native token from Aptos to Ethereum", async () => {
const APTOS_TOKEN_BRIDGE = CONTRACTS.DEVNET.aptos.token_bridge;
@ -99,7 +97,7 @@ describe("Aptos SDK tests", () => {
expect(attestVAA).toBeTruthy();
// setup ethereum
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const recipient = new ethers.Wallet(ETH_PRIVATE_KEY6, provider);
const recipientAddress = await recipient.getAddress();
const ethTokenBridge = CONTRACTS.DEVNET.ethereum.token_bridge;
@ -196,13 +194,10 @@ describe("Aptos SDK tests", () => {
expect(
balanceAfterTransferEth.sub(balanceBeforeTransferEth).toNumber()
).toEqual(10_000_000);
// clean up
provider.destroy();
});
test("Transfer native ERC-20 from Ethereum to Aptos", async () => {
// setup ethereum
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const sender = new ethers.Wallet(ETH_PRIVATE_KEY6, provider);
const ethTokenBridge = CONTRACTS.DEVNET.ethereum.token_bridge;
const ethCoreBridge = CONTRACTS.DEVNET.ethereum.core;
@ -218,6 +213,7 @@ describe("Aptos SDK tests", () => {
let sequence = parseSequenceFromLogEth(attestReceipt, ethCoreBridge);
expect(sequence).toBeTruthy();
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const { vaaBytes: attestVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
CHAIN_ID_ETH,
@ -322,6 +318,7 @@ describe("Aptos SDK tests", () => {
sequence = parseSequenceFromLogEth(transferReceipt, ethCoreBridge);
expect(sequence).toBeTruthy();
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const { vaaBytes: transferVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
CHAIN_ID_ETH,
@ -367,9 +364,6 @@ describe("Aptos SDK tests", () => {
expect(
balanceBeforeTransferEth.sub(balanceAfterTransferEth).toString()
).toEqual(amount.toString());
// clean up
provider.destroy();
});
test("Transfer native token with payload from Aptos to Ethereum", async () => {
const APTOS_TOKEN_BRIDGE = CONTRACTS.DEVNET.aptos.token_bridge;
@ -411,7 +405,7 @@ describe("Aptos SDK tests", () => {
expect(attestVAA).toBeTruthy();
// setup ethereum
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const recipient = new ethers.Wallet(ETH_PRIVATE_KEY6, provider);
const recipientAddress = await recipient.getAddress();
const ethTokenBridge = CONTRACTS.DEVNET.ethereum.token_bridge;
@ -513,9 +507,6 @@ describe("Aptos SDK tests", () => {
expect(
balanceAfterTransferEth.sub(balanceBeforeTransferEth).toNumber()
).toEqual(10_000_000);
// clean up
provider.destroy();
});
});

View File

@ -2,10 +2,9 @@ import { formatUnits, parseUnits } from "@ethersproject/units";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
import { describe, expect, jest, test } from "@jest/globals";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
getAssociatedTokenAddress,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import {
Connection,
@ -16,11 +15,11 @@ import {
} from "@solana/web3.js";
import { ethers } from "ethers";
import {
approveEth,
attestFromEth,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CONTRACTS,
approveEth,
attestFromEth,
createWrappedOnSolana,
getEmitterAddressEth,
getForeignAssetSolana,
@ -43,8 +42,6 @@ import {
WORMHOLE_RPC_HOSTS,
} from "./utils/consts";
jest.setTimeout(120000);
async function transferFromEthToSolana(): Promise<string> {
// create a keypair for Solana
const connection = new Connection(SOLANA_HOST, "confirmed");
@ -82,7 +79,7 @@ async function transferFromEthToSolana(): Promise<string> {
await connection.confirmTransaction(txid);
}
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider);
const amount = parseUnits("1", 18);
// approve the bridge to spend tokens
@ -106,7 +103,6 @@ async function transferFromEthToSolana(): Promise<string> {
receipt,
CONTRACTS.DEVNET.ethereum.core
);
provider.destroy();
return sequence;
}
@ -115,7 +111,7 @@ describe("Ethereum to Solana and Back", () => {
(async () => {
try {
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider);
// attest the test token
const receipt = await attestFromEth(
@ -131,6 +127,7 @@ describe("Ethereum to Solana and Back", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -174,7 +171,6 @@ describe("Ethereum to Solana and Back", () => {
} catch (e) {
// this could fail because the token is already attested (in an unclean env)
}
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -238,7 +234,7 @@ describe("Ethereum to Solana and Back", () => {
await connection.confirmTransaction(txid);
}
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider);
const amount = parseUnits("1", DECIMALS);
@ -294,6 +290,7 @@ describe("Ethereum to Solana and Back", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -373,7 +370,6 @@ describe("Ethereum to Solana and Back", () => {
}
}
expect(finalSolanaBalance - initialSolanaBalance === 1).toBe(true);
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -393,6 +389,8 @@ describe("Ethereum to Solana and Back", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -466,6 +464,8 @@ describe("Ethereum to Solana and Back", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,

View File

@ -1,6 +1,13 @@
import { beforeAll, afterAll, expect, jest, test } from "@jest/globals";
import { beforeAll, expect, jest, test } from "@jest/globals";
import { ethers } from "ethers";
import { parseUnits } from "ethers/lib/utils";
import { Account, KeyPair, Near, connect, keyStores } from "near-api-js";
import {
FinalExecutionOutcome,
Provider,
getTransactionLastResult,
} from "near-api-js/lib/providers";
import { parseNearAmount } from "near-api-js/lib/utils/format";
import {
createWrappedOnEth,
createWrappedOnNear,
@ -28,15 +35,6 @@ import {
TEST_ERC20,
} from "./utils/consts";
import { getSignedVAABySequence } from "./utils/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";
jest.setTimeout(120000);
let near: Near;
let nearProvider: Provider;
@ -46,7 +44,7 @@ const accountId = "devnet.test.near";
const PRIVATE_KEY =
"ed25519:nCW2EsTn91b7ettRqQX6ti8ZBNwo7tbMsenBu9nmSVG9aDhNB7hgw7S9w5M9CZu1bF23FbvhKZPfDmh2Gbs45Fs";
const ethProvider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const ethProvider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY5, ethProvider);
const ethEmitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
@ -72,10 +70,6 @@ beforeAll(async () => {
ethWalletAddress = await signer.getAddress();
});
afterAll(async () => {
ethProvider.destroy();
});
const nearParseLogAndGetSignedVaa = async (outcome: FinalExecutionOutcome) => {
const sequence = parseSequenceFromLogNear(outcome);
if (sequence === null) {
@ -155,6 +149,7 @@ test("Attest and transfer token from Ethereum to Near", async () => {
signer,
TEST_ERC20
);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const attestSignedVaa = await ethParseLogAndGetSignedVaa(attestReceipt);
const createWrappedMsgs = await createWrappedOnNear(
nearProvider,
@ -193,6 +188,7 @@ test("Attest and transfer token from Ethereum to Near", async () => {
"near",
hexToUint8Array(accountHash)
);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const transferSignedVaa = await ethParseLogAndGetSignedVaa(transferReceipt);
const redeemMsgs = await redeemOnNear(
nearProvider,

View File

@ -2,10 +2,9 @@ import { formatUnits, parseUnits } from "@ethersproject/units";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
import { describe, expect, jest, test } from "@jest/globals";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
getAssociatedTokenAddress,
NATIVE_MINT,
TOKEN_PROGRAM_ID,
getAssociatedTokenAddress,
} from "@solana/spl-token";
import {
Connection,
@ -15,10 +14,11 @@ import {
} from "@solana/web3.js";
import { ethers } from "ethers";
import {
attestFromSolana,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CONTRACTS,
WSOL_ADDRESS,
attestFromSolana,
createWrappedOnEth,
getEmitterAddressSolana,
getForeignAssetEth,
@ -30,7 +30,6 @@ import {
transferNativeSol,
tryNativeToHexString,
tryNativeToUint8Array,
WSOL_ADDRESS,
} from "../..";
import { TokenImplementation__factory } from "../../ethers-contracts";
import getSignedVAAWithRetry from "../../rpc/getSignedVAAWithRetry";
@ -43,8 +42,6 @@ import {
WORMHOLE_RPC_HOSTS,
} from "./utils/consts";
jest.setTimeout(120000);
describe("Solana to Ethereum", () => {
test("Attest Solana SPL to Ethereum", (done) => {
(async () => {
@ -89,7 +86,7 @@ describe("Solana to Ethereum", () => {
}
);
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY3, provider);
try {
await createWrappedOnEth(
@ -100,7 +97,6 @@ describe("Solana to Ethereum", () => {
} catch (e) {
// this could fail because the token is already attested (in an unclean env)
}
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -111,7 +107,7 @@ describe("Solana to Ethereum", () => {
})();
});
test("Solana SPL is attested on Ethereum", async () => {
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const address = getForeignAssetEth(
CONTRACTS.DEVNET.ethereum.token_bridge,
provider,
@ -120,13 +116,12 @@ describe("Solana to Ethereum", () => {
);
expect(address).toBeTruthy();
expect(address).not.toBe(ethers.constants.AddressZero);
provider.destroy();
});
test("Send Solana SPL to Ethereum", (done) => {
(async () => {
try {
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY3, provider);
const targetAddress = await signer.getAddress();
// create a keypair for Solana
@ -267,7 +262,6 @@ describe("Solana to Ethereum", () => {
parseInt(initialBalOnEthFormatted) ===
1
).toBe(true);
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -318,7 +312,7 @@ describe("Solana to Ethereum", () => {
}
);
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY3, provider);
try {
await createWrappedOnEth(
@ -329,7 +323,6 @@ describe("Solana to Ethereum", () => {
} catch (e) {
// this could fail because the token is already attested (in an unclean env)
}
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -343,7 +336,7 @@ describe("Solana to Ethereum", () => {
(async () => {
try {
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY3, provider);
const targetAddress = await signer.getAddress();
// create a keypair for Solana
@ -443,7 +436,6 @@ describe("Solana to Ethereum", () => {
parseInt(initialBalOnEthFormatted) ===
1
).toBe(true);
provider.destroy();
done();
} catch (e) {
console.error(e);

View File

@ -1,12 +1,5 @@
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
import {
afterAll,
beforeAll,
describe,
expect,
jest,
test,
} from "@jest/globals";
import { beforeAll, describe, expect, jest, test } from "@jest/globals";
import {
Connection,
Ed25519Keypair,
@ -35,9 +28,7 @@ import {
getSignedVAAWithRetry,
parseAttestMetaVaa,
parseSequenceFromLogEth,
parseTokenTransferPayload,
parseTokenTransferVaa,
parseVaa,
redeemOnEth,
redeemOnSui,
transferFromEth,
@ -52,14 +43,12 @@ import {
getInnerType,
getPackageId,
getWrappedCoinType,
newEmitterCap,
} from "../../sui";
import {
CHAIN_ID_ETH,
CHAIN_ID_SUI,
CONTRACTS,
hexToUint8Array,
parseTransferPayload,
tryNativeToHexString,
tryNativeToUint8Array,
} from "../../utils";
@ -78,8 +67,6 @@ import {
mintAndTransferCoinSui,
} from "./utils/helpers";
jest.setTimeout(120000);
// Sui constants
const SUI_CORE_BRIDGE_STATE_OBJECT_ID = CONTRACTS.DEVNET.sui.core;
const SUI_TOKEN_BRIDGE_STATE_OBJECT_ID = CONTRACTS.DEVNET.sui.token_bridge;
@ -101,7 +88,7 @@ const suiSigner: RawSigner = new RawSigner(suiKeypair, suiProvider);
const ETH_CORE_BRIDGE_ADDRESS = CONTRACTS.DEVNET.ethereum.core;
const ETH_TOKEN_BRIDGE_ADDRESS = CONTRACTS.DEVNET.ethereum.token_bridge;
const ethProvider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const ethProvider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const ethSigner = new ethers.Wallet(ETH_PRIVATE_KEY10, ethProvider);
let suiCoreBridgePackageId: string;
@ -118,10 +105,6 @@ beforeAll(async () => {
);
});
afterAll(async () => {
await ethProvider.destroy();
});
// Modify the VAA to only have 1 guardian signature
// TODO: remove this when we can deploy the devnet core contract
// deterministically with multiple guardians in the initial guardian set
@ -165,6 +148,7 @@ describe("Sui SDK tests", () => {
ETH_CORE_BRIDGE_ADDRESS
);
expect(attestSequence).toBeTruthy();
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
let { vaaBytes: attestVAA }: { vaaBytes: Uint8Array } =
await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -176,7 +160,6 @@ describe("Sui SDK tests", () => {
}
);
const slicedAttestVAA = sliceVAASignatures(attestVAA);
console.log(Buffer.from(slicedAttestVAA).toString("hex"));
expect(slicedAttestVAA).toBeTruthy();
// Start create wrapped on Sui
@ -331,6 +314,7 @@ describe("Sui SDK tests", () => {
transferReceipt,
ETH_CORE_BRIDGE_ADDRESS
);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
let { vaaBytes: transferFromEthVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
CHAIN_ID_ETH,
@ -381,7 +365,6 @@ describe("Sui SDK tests", () => {
coinType: coinType,
})
).data;
console.log({ coins, coinType });
const suiTransferTxPayload = await transferFromSui(
suiProvider,
SUI_CORE_BRIDGE_STATE_OBJECT_ID,
@ -495,7 +478,6 @@ describe("Sui SDK tests", () => {
transport: NodeHttpTransport(),
}
);
console.log(parseAttestMetaVaa(attestVAA));
expect(attestVAA).toBeTruthy();
// // Create wrapped on Ethereum

View File

@ -10,12 +10,12 @@ import {
} from "@terra-money/terra.js";
import { ethers } from "ethers";
import {
approveEth,
attestFromEth,
attestFromTerra,
CHAIN_ID_ETH,
CHAIN_ID_TERRA,
CONTRACTS,
approveEth,
attestFromEth,
attestFromTerra,
createWrappedOnEth,
createWrappedOnTerra,
getEmitterAddressEth,
@ -53,8 +53,6 @@ import {
waitForTerraExecution,
} from "./utils/helpers";
jest.setTimeout(120000);
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@ -106,7 +104,7 @@ describe("Terra Classic Integration Tests", () => {
});
await broadcastAndWait(lcd, tx);
}
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
// attempt to transfer more than we've deposited
const transfer = new MsgExecuteContract(
@ -186,7 +184,6 @@ describe("Terra Classic Integration Tests", () => {
fee: feeEstimate,
});
await broadcastAndWait(lcd, tx);
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -202,7 +199,7 @@ describe("Terra Classic Integration Tests", () => {
(async () => {
try {
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
// attest the test token
const receipt = await attestFromEth(
@ -218,6 +215,7 @@ describe("Terra Classic Integration Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -265,7 +263,6 @@ describe("Terra Classic Integration Tests", () => {
} catch (e) {
// this could fail because the token is already attested (in an unclean env)
}
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -293,7 +290,7 @@ describe("Terra Classic Integration Tests", () => {
(async () => {
try {
// create a signer for Eth
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
@ -381,6 +378,7 @@ describe("Terra Classic Integration Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -451,7 +449,6 @@ describe("Terra Classic Integration Tests", () => {
tokenDefinition.decimals
);
// let finalCW20BalOnTerra: number = parseInt(balAmount);
provider.destroy();
done();
} catch (e) {
console.error(e);
@ -516,7 +513,7 @@ describe("Terra Classic Integration Tests", () => {
sequence,
emitterAddress
);
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
@ -538,7 +535,6 @@ describe("Terra Classic Integration Tests", () => {
);
success = true;
}
provider.destroy();
} catch (e) {
console.error("Attestation failure: ", e);
}
@ -567,7 +563,7 @@ describe("Terra Classic Integration Tests", () => {
// const initialFeeBalance: number = await queryBalanceOnTerra(FeeAsset);
// Get initial balance of wrapped luna on Eth
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
@ -678,7 +674,6 @@ describe("Terra Classic Integration Tests", () => {
expect(initialLunaBalOnEthInt + 1e6 === lunaBalOnEthAfterInt).toBe(
true
);
provider.destroy();
} catch (e) {
console.error("Terra to Ethereum failure: ", e);
done("Terra to Ethereum Failure");
@ -701,7 +696,7 @@ describe("Terra Classic Integration Tests", () => {
});
const Asset: string = "uluna";
const initialTerraBalance: number = await queryBalanceOnTerra(Asset);
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
@ -755,7 +750,7 @@ describe("Terra Classic Integration Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -813,7 +808,6 @@ describe("Terra Classic Integration Tests", () => {
true
);
// const uusdBal = await queryBalanceOnTerra("uusd");
provider.destroy();
} catch (e) {
console.error("Transfer back failure: ", e);
done("Transfer back Failure");
@ -890,7 +884,7 @@ describe("Terra Classic Integration Tests", () => {
sequence,
emitterAddress
);
const provider = new ethers.providers.WebSocketProvider(
const provider = new ethers.providers.JsonRpcProvider(
ETH_NODE_URL
) as any;
const signer = new ethers.Wallet(ETH_PRIVATE_KEY4, provider);
@ -1070,7 +1064,7 @@ describe("Terra Classic Integration Tests", () => {
emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
@ -1132,7 +1126,6 @@ describe("Terra Classic Integration Tests", () => {
finalCW20BalOnTerra = parseInt(amount);
expect(finalCW20BalOnTerra - initialCW20BalOnTerra === 1).toBe(true);
// Done checking wallet balances
provider.destroy();
} catch (e) {
console.error("CW20 Transfer failure: ", e);
done("CW20 Transfer Failure");

View File

@ -1,10 +1,10 @@
import { beforeAll, afterAll, describe, expect, test } from "@jest/globals";
import { beforeAll, describe, expect, test } from "@jest/globals";
import {
isTxError,
LCDClient,
MnemonicKey,
Msg,
Wallet,
isTxError,
} from "@terra-money/terra.js";
import { ethers } from "ethers";
import { parseUnits } from "ethers/lib/utils";
@ -61,7 +61,7 @@ const terraClassicWallet = lcdClassic.wallet(
);
const terraClassicWalletAddress = terraClassicWallet.key.accAddress;
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
const provider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
const signer = new ethers.Wallet(ETH_PRIVATE_KEY2, provider);
const ethEmitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
@ -78,10 +78,6 @@ beforeAll(async () => {
);
});
afterAll(async () => {
provider.destroy();
});
const terraBroadcastAndWaitForExecution = async (
msgs: Msg[],
wallet: Wallet,
@ -179,6 +175,7 @@ describe("Terra Integration Tests", () => {
signer,
TEST_ERC20
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const attestSignedVaa = await ethParseLogAndGetSignedVaa(attestReceipt);
const createWrappedMsg = await createWrappedOnTerra(
CONTRACTS.DEVNET.terra2.token_bridge,
@ -201,6 +198,7 @@ describe("Terra Integration Tests", () => {
CHAIN_ID_TERRA2,
tryNativeToUint8Array(terraWalletAddress, CHAIN_ID_TERRA2)
);
await provider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
const transferSignedVaa = await ethParseLogAndGetSignedVaa(transferReceipt);
const redeemMsg = await redeemOnTerra(
CONTRACTS.DEVNET.terra2.token_bridge,

View File

@ -1,10 +1,9 @@
import { describe, expect, it } from "@jest/globals";
import { Connection, PublicKey } from "@solana/web3.js";
const ci = !!process.env.CI;
// see devnet.md
export const ETH_NODE_URL = ci ? "ws://eth-devnet:8545" : "ws://localhost:8545";
export const ETH_NODE_URL = ci
? "http://eth-devnet:8545"
: "http://localhost:8545";
export const ETH_PRIVATE_KEY =
"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"; // account 0
// account 1 used by NFT tests

View File

@ -52,8 +52,8 @@ const ci = !!process.env.CI;
const GUARDIAN_HOST = ci ? "guardian" : "localhost";
const GUARDIAN_RPCS = [`http://${GUARDIAN_HOST}:7071`];
const GUARDIAN_METRICS = `http://${GUARDIAN_HOST}:6060/metrics`;
const ETH_NODE_URL = ci ? "ws://eth-devnet:8545" : "ws://localhost:8545";
const BSC_NODE_URL = ci ? "ws://eth-devnet2:8545" : "ws://localhost:8546";
const ETH_NODE_URL = ci ? "http://eth-devnet:8545" : "http://localhost:8545";
const BSC_NODE_URL = ci ? "http://eth-devnet2:8545" : "http://localhost:8546";
const ETH_PRIVATE_KEY9 =
"0xb0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773";
const ETH_GA_TEST_TOKEN =
@ -70,25 +70,23 @@ function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
let ethProvider: ethers.providers.WebSocketProvider;
let ethProvider: ethers.providers.JsonRpcProvider;
let ethSigner: ethers.Wallet;
let bscProvider: ethers.providers.WebSocketProvider;
let bscProvider: ethers.providers.JsonRpcProvider;
let bscSigner: ethers.Wallet;
let cosmWasmClient: CosmWasmClient;
beforeAll(async () => {
// create a signer for Eth
ethProvider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
ethProvider = new ethers.providers.JsonRpcProvider(ETH_NODE_URL);
ethSigner = new ethers.Wallet(ETH_PRIVATE_KEY9, ethProvider);
// create a signer for BSC
bscProvider = new ethers.providers.WebSocketProvider(BSC_NODE_URL);
bscProvider = new ethers.providers.JsonRpcProvider(BSC_NODE_URL);
bscSigner = new ethers.Wallet(ETH_PRIVATE_KEY9, bscProvider);
cosmWasmClient = await CosmWasmClient.connect(TENDERMINT_URL);
});
afterAll(async () => {
await ethProvider.destroy();
await bscProvider.destroy();
cosmWasmClient.disconnect();
});
@ -165,9 +163,8 @@ describe("Global Accountant Tests", () => {
tryNativeToUint8Array(ETH_GA_TEST_TOKEN, CHAIN_ID_ETH)
);
if (attestedAddress && attestedAddress !== ethers.constants.AddressZero) {
console.log("already attested");
// already attested
} else {
console.log("attesting...");
// attest the test token
const receipt = await attestFromEth(
CONTRACTS.DEVNET.ethereum.token_bridge,
@ -182,7 +179,7 @@ describe("Global Accountant Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
console.log(`fetching vaa ${sequence}...`);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
GUARDIAN_RPCS,
@ -193,7 +190,6 @@ describe("Global Accountant Tests", () => {
transport: NodeHttpTransport(),
}
);
console.log("creating...");
await createWrappedOnEth(
CONTRACTS.DEVNET.bsc.token_bridge,
bscSigner,
@ -225,7 +221,6 @@ describe("Global Accountant Tests", () => {
);
const amount = parseUnits("1", DECIMALS);
// approve the bridge to spend tokens
console.log("approving...");
await approveEth(
CONTRACTS.DEVNET.ethereum.token_bridge,
ETH_GA_TEST_TOKEN,
@ -233,7 +228,6 @@ describe("Global Accountant Tests", () => {
amount
);
// transfer tokens out
console.log("transferring...");
const receipt = await transferFromEth(
CONTRACTS.DEVNET.ethereum.token_bridge,
ethSigner,
@ -250,7 +244,7 @@ describe("Global Accountant Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.ethereum.token_bridge
);
console.log(`fetching vaa ${sequence}...`);
await ethProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
GUARDIAN_RPCS,
@ -261,18 +255,12 @@ describe("Global Accountant Tests", () => {
transport: NodeHttpTransport(),
}
);
console.log("redeeming...");
await redeemOnEth(
CONTRACTS.DEVNET.bsc.token_bridge,
bscSigner,
signedVAA
);
const afterMetrics = await fetchGlobalAccountantMetrics();
console.log(
"approved b/a:",
beforeMetrics.global_accountant_transfer_vaas_submitted_and_approved,
afterMetrics.global_accountant_transfer_vaas_submitted_and_approved
);
if (
afterMetrics.global_accountant_events_received <=
beforeMetrics.global_accountant_events_received ||
@ -333,7 +321,6 @@ describe("Global Accountant Tests", () => {
);
const amount = parseUnits("1", DECIMALS);
// approve the bridge to spend tokens
console.log("approving...");
await approveEth(
CONTRACTS.DEVNET.bsc.token_bridge,
attestedAddress,
@ -341,7 +328,6 @@ describe("Global Accountant Tests", () => {
amount
);
// transfer tokens out
console.log("transferring...");
const receipt = await transferFromEth(
CONTRACTS.DEVNET.bsc.token_bridge,
bscSigner,
@ -358,7 +344,7 @@ describe("Global Accountant Tests", () => {
const emitterAddress = getEmitterAddressEth(
CONTRACTS.DEVNET.bsc.token_bridge
);
console.log(`fetching vaa ${sequence}...`);
await bscProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
// poll until the guardian(s) witness and sign the vaa
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
GUARDIAN_RPCS,
@ -369,18 +355,12 @@ describe("Global Accountant Tests", () => {
transport: NodeHttpTransport(),
}
);
console.log("redeeming...");
await redeemOnEth(
CONTRACTS.DEVNET.ethereum.token_bridge,
ethSigner,
signedVAA
);
const afterMetrics = await fetchGlobalAccountantMetrics();
console.log(
"approved b/a:",
beforeMetrics.global_accountant_transfer_vaas_submitted_and_approved,
afterMetrics.global_accountant_transfer_vaas_submitted_and_approved
);
if (
afterMetrics.global_accountant_events_received <=
beforeMetrics.global_accountant_events_received ||
@ -428,7 +408,6 @@ describe("Global Accountant Tests", () => {
// STEP 3a - redeem spoofed tokens
//
{
console.log("redeeming spoofed tokens");
let vaa: VAA<TokenBridgeTransfer> = {
version: 1,
guardianSetIndex: 0,
@ -471,7 +450,6 @@ describe("Global Accountant Tests", () => {
const beforeMetrics = await fetchGlobalAccountantMetrics();
const amount = parseUnits("9000", DECIMALS);
// approve the bridge to spend tokens
console.log("approving...");
await approveEth(
CONTRACTS.DEVNET.bsc.token_bridge,
attestedAddress,
@ -479,7 +457,6 @@ describe("Global Accountant Tests", () => {
amount
);
// transfer tokens out
console.log("transferring...");
const receipt = await transferFromEth(
CONTRACTS.DEVNET.bsc.token_bridge,
bscSigner,
@ -492,14 +469,9 @@ describe("Global Accountant Tests", () => {
receipt,
CONTRACTS.DEVNET.bsc.core
);
console.log("waiting 30s to fetch metrics...");
await bscProvider.send("anvil_mine", ["0x40"]); // 64 blocks should get the above block to `finalized`
await sleep(30 * 1000); // give the guardian a few seconds to pick up the transfers and attempt to submit them
const afterMetrics = await fetchGlobalAccountantMetrics();
console.log(
"balance errors b/a:",
beforeMetrics.global_accountant_total_balance_errors,
afterMetrics.global_accountant_total_balance_errors
);
if (
afterMetrics.global_accountant_error_events_received <=
beforeMetrics.global_accountant_error_events_received ||
@ -529,6 +501,5 @@ describe("Global Accountant Tests", () => {
).rejects.toThrow();
}
}
console.log("success!");
});
});

View File

@ -1506,7 +1506,7 @@ describe("NTT Global Accountant Tests", () => {
`0x${mockTransferPayload(8, 10, SPOKE_CHAIN_A)}`,
0,
{ value },
relayerOptionalParameters
{ ...relayerOptionalParameters, consistencyLevel: 200 }
);
const receipt = await tx.wait();
// get the sequence from the logs (needed to fetch the vaa)

View File

@ -0,0 +1,18 @@
process.env.CI = true;
const info = console.info;
console.info = function (x) {
if (x !== "secp256k1 unavailable, reverting to browser version") {
info(x);
}
};
const warn = console.warn;
console.warn = function (x) {
if (
x !==
"bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)"
) {
warn(x);
}
};

View File

@ -5,8 +5,8 @@
"main": "deploy_wormchain.ts",
"scripts": {
"deploy-wormchain": "ts-node deploy_wormchain.ts",
"test-accountant": "jest test_accountant.ts --verbose",
"test-ntt-accountant": "jest test_ntt_accountant.ts --verbose",
"test-accountant": "jest test_accountant.ts --verbose --setupFiles ./ci-config.js",
"test-ntt-accountant": "jest test_ntt_accountant.ts --verbose --setupFiles ./ci-config.js",
"test-wormchain": "ts-node test_wormchain.ts",
"deploy-and-test": "npm run deploy-wormchain && npm run test-wormchain"
},

View File

@ -9,7 +9,6 @@ export async function getWallet(
mnemonic: string,
options?: DirectSecp256k1HdWalletOptions
): Promise<DirectSecp256k1HdWallet> {
console.log("wallet");
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
prefix: ADDRESS_PREFIX,
});