wormchain - contract deploy + test
This commit is contained in:
parent
1f939ea2dd
commit
220a869b7b
|
@ -253,7 +253,7 @@ jobs:
|
|||
node-version: "16"
|
||||
- run: cd clients/js && make test
|
||||
|
||||
# Verify wormhole chain unit tests
|
||||
# Verify wormchain tests
|
||||
wormchain:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
@ -261,11 +261,14 @@ jobs:
|
|||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: "1.19.3"
|
||||
- run: |
|
||||
- name: make proto -B && make test
|
||||
run: |
|
||||
cd wormchain
|
||||
make proto -B
|
||||
git diff --name-only --exit-code && echo "✅ Generated proto matches committed proto" || (echo "❌ Generated proto differs from committed proto, run \`make proto -B\` and commit the result" >&2 && exit 1)
|
||||
make test
|
||||
- name: deploy-test
|
||||
run: cd wormchain && make contracts-deploy-test
|
||||
|
||||
# Verify go sdk unit tests
|
||||
sdk_vaa:
|
||||
|
|
|
@ -13,6 +13,8 @@ venv
|
|||
.env
|
||||
.env.hex
|
||||
.env.0x
|
||||
devnet-consts.json
|
||||
!/scripts/devnet-consts.json
|
||||
bigtable-admin.json
|
||||
bigtable-writer.json
|
||||
**/cert.pem
|
||||
|
|
|
@ -37,6 +37,9 @@ ENV NUM_GUARDIANS=$num_guardians
|
|||
# run guardian-set-init.sh to create env files with the init state for NUM_GUARDIANS
|
||||
RUN ./scripts/guardian-set-init.sh $NUM_GUARDIANS
|
||||
|
||||
# run distribute-devnet-consts.sh to copy devnet-consts.json to chain dirs for use
|
||||
RUN ./scripts/distribute-devnet-consts.sh
|
||||
|
||||
FROM scratch AS const-export
|
||||
COPY --from=const-build /scripts/.env.0x ethereum/.env
|
||||
COPY --from=const-build /scripts/.env.hex solana/.env
|
||||
|
@ -45,3 +48,6 @@ COPY --from=const-build /scripts/.env.hex cosmwasm/deployment/terra2/tools/.env
|
|||
COPY --from=const-build /scripts/.env.hex algorand/.env
|
||||
COPY --from=const-build /scripts/.env.hex near/.env
|
||||
COPY --from=const-build /scripts/.env.hex aptos/.env
|
||||
COPY --from=const-build /scripts/.env.hex wormchain/contracts/tools/.env
|
||||
|
||||
COPY --from=const-build /scripts/devnet-consts.json wormchain/contracts/tools/
|
||||
|
|
18
Tiltfile
18
Tiltfile
|
@ -756,6 +756,12 @@ if wormchain:
|
|||
ignore = ["./wormchain/testing", "./wormchain/ts-sdk", "./wormchain/design", "./wormchain/vue", "./wormchain/build/wormchaind"],
|
||||
)
|
||||
|
||||
docker_build(
|
||||
ref = "wormchain-deploy",
|
||||
context = "./wormchain/contracts",
|
||||
dockerfile = "./cosmwasm/Dockerfile.deploy",
|
||||
)
|
||||
|
||||
def build_wormchain_yaml(yaml_path, num_instances):
|
||||
wormchain_yaml = read_yaml_stream(yaml_path)
|
||||
|
||||
|
@ -795,6 +801,7 @@ if wormchain:
|
|||
else:
|
||||
k8s_yaml_with_ns(wormchain_path)
|
||||
|
||||
|
||||
k8s_resource(
|
||||
"wormchain",
|
||||
port_forwards = [
|
||||
|
@ -802,7 +809,14 @@ if wormchain:
|
|||
port_forward(9090, container_port = 9090, name = "GRPC", host = webHost),
|
||||
port_forward(26659, container_port = 26657, name = "TENDERMINT [:26659]", host = webHost)
|
||||
],
|
||||
resource_deps = [],
|
||||
resource_deps = ["const-gen"],
|
||||
labels = ["wormchain"],
|
||||
trigger_mode = trigger_mode,
|
||||
)
|
||||
|
||||
k8s_resource(
|
||||
"wormchain-deploy",
|
||||
resource_deps = ["wormchain"],
|
||||
labels = ["wormchain"],
|
||||
trigger_mode = trigger_mode,
|
||||
)
|
||||
|
@ -823,7 +837,7 @@ if ibc_relayer:
|
|||
port_forwards = [
|
||||
port_forward(7597, name = "HTTPDEBUG [:7597]", host = webHost),
|
||||
],
|
||||
resource_deps = ["guardian-validator", "terra2-terrad"],
|
||||
resource_deps = ["wormchain", "terra2-terrad"],
|
||||
labels = ["ibc-relayer"],
|
||||
trigger_mode = trigger_mode,
|
||||
)
|
||||
|
|
|
@ -222,8 +222,6 @@ const contract_registrations = {
|
|||
process.env.REGISTER_TERRA_TOKEN_BRIDGE_VAA,
|
||||
// NEAR
|
||||
process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA,
|
||||
// Wormhole Chain
|
||||
process.env.REGISTER_WORMCHAIN_TOKEN_BRIDGE_VAA,
|
||||
// APTOS
|
||||
process.env.REGISTER_APTOS_TOKEN_BRIDGE_VAA,
|
||||
],
|
||||
|
|
|
@ -59,7 +59,7 @@ spec:
|
|||
- key: wormchainKey0
|
||||
path: wormchainKey0
|
||||
- key: wormchainKey1
|
||||
path: wormchainKey1
|
||||
path: wormchainKey1
|
||||
containers:
|
||||
- name: guardiand
|
||||
image: guardiand-image
|
||||
|
@ -104,19 +104,19 @@ spec:
|
|||
- --neonRPC
|
||||
- ws://eth-devnet:8545
|
||||
# - --wormchainWS
|
||||
# - ws://guardian-validator:26657/websocket
|
||||
# - ws://wormchain:26657/websocket
|
||||
# - --wormchainLCD
|
||||
# - http://guardian-validator:1317
|
||||
# - http://wormchain:1317
|
||||
# - --wormchainURL
|
||||
# - guardian-validator:9090
|
||||
# - wormchain:9090
|
||||
# - --wormchainKeyPath
|
||||
# - /tmp/mounted-keys/wormchain/wormchainKey
|
||||
# - --wormchainKeyPassPhrase
|
||||
# - test0000
|
||||
# - --accountantWS
|
||||
# - http://guardian-validator:26657
|
||||
# - http://wormchain:26657
|
||||
# - --accountantContract
|
||||
# - wormhole1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjq4lyjmh
|
||||
# - wormhole1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq0kdhcj
|
||||
# - --accountantCheckEnabled=true
|
||||
# - --terraWS
|
||||
# - ws://terra-terrad:26657/websocket
|
||||
|
@ -199,5 +199,5 @@ metadata:
|
|||
name: node-wormchain-key
|
||||
type: Opaque
|
||||
data:
|
||||
wormchainKey0: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNDc2ODc2NkE3OEZEN0ZBQjMwMUJGOTM5MUYwQ0Y2M0YKdHlwZTogc2VjcDI1NmsxCgpkbEZuN1ZqRk02RnJjYkdaVDRWeE5yRlE3SUhQS2RyVVBCRTYraW8yK0w0VFZqcis5emNIQTF3dzNubWtqNVFlCnVSekJWMjQyeUdTc3hNTTJZckI2Q1ZXdzlaWXJJY3JFeks1c0FuST0KPXB2aHkKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
wormchainKey0: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogNDc2ODc2NkE3OEZEN0ZBQjMwMUJGOTM5MUYwQ0Y2M0YKdHlwZTogc2VjcDI1NmsxCgpkbEZuN1ZqRk02RnJjYkdaVDRWeE5yRlE3SUhQS2RyVVBCRTYraW8yK0w0VFZqcis5emNIQTF3dzNubWtqNVFlCnVSekJWMjQyeUdTc3hNTTJZckI2Q1ZXdzlaWXJJY3JFeks1c0FuST0KPXB2aHkKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0t
|
||||
wormchainKey1: LS0tLS1CRUdJTiBURU5ERVJNSU5UIFBSSVZBVEUgS0VZLS0tLS0Ka2RmOiBiY3J5cHQKc2FsdDogMjMyRTU2NDMyMjBBNTcwRkVEQjFFMTFFOTNFM0E4NEIKdHlwZTogc2VjcDI1NmsxCgpBZjJ3aXNLdlBDOW4vaExYcDZaS1k5S091aVNYZG1lb3VvSzd3QVJ3cmNtTDV3MGs0YjFDSE5xTEp3ZXU1OEFGCkdTWGJsU3oySzNuWEl1V2hJZWtSNXE5WGRuUko4cGhSRWltbFNZST0KPU1vY1QKLS0tLS1FTkQgVEVOREVSTUlOVCBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
|
|
|
@ -90,5 +90,40 @@ spec:
|
|||
httpGet:
|
||||
port: 26657
|
||||
path: /
|
||||
periodSeconds: 1
|
||||
restartPolicy: Always
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
app: wormchain-deploy
|
||||
name: wormchain-deploy
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wormchain-deploy
|
||||
replicas: 1
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wormchain-deploy
|
||||
spec:
|
||||
containers:
|
||||
- name: wormchain-deploy
|
||||
image: wormchain-deploy
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "npm run deploy-wormchain --prefix=/app/tools && touch /app/tools/success && sleep infinity"
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- test
|
||||
- -e
|
||||
- "/app/tools/success"
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
restartPolicy: Always
|
||||
|
|
|
@ -14,7 +14,6 @@ const terra2TokenBridgeVAA = process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA;
|
|||
const bscTokenBridgeVAA = process.env.REGISTER_BSC_TOKEN_BRIDGE_VAA;
|
||||
const algoTokenBridgeVAA = process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA;
|
||||
const nearTokenBridgeVAA = process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA;
|
||||
const wormchainTokenBridgeVAA = process.env.REGISTER_WORMCHAIN_TOKEN_BRIDGE_VAA;
|
||||
const aptosTokenBridgeVAA = process.env.REGISTER_APTOS_TOKEN_BRIDGE_VAA;
|
||||
|
||||
module.exports = async function(callback) {
|
||||
|
@ -91,16 +90,6 @@ module.exports = async function(callback) {
|
|||
gasLimit: 2000000,
|
||||
});
|
||||
|
||||
// Register the wormhole token bridge endpoint
|
||||
console.log("Registering Wormchain...");
|
||||
await tokenBridge.methods
|
||||
.registerChain("0x" + wormchainTokenBridgeVAA)
|
||||
.send({
|
||||
value: 0,
|
||||
from: accounts[0],
|
||||
gasLimit: 2000000,
|
||||
});
|
||||
|
||||
// Register the APTOS endpoint
|
||||
console.log("Registering Aptos...");
|
||||
await tokenBridge.methods.registerChain("0x" + aptosTokenBridgeVAA).send({
|
||||
|
|
|
@ -34,7 +34,7 @@ func main() {
|
|||
|
||||
wormchainURL := string("localhost:9090")
|
||||
wormchainKeyPath := string("./dev.wormchain.key")
|
||||
contract := "wormhole1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjq4lyjmh"
|
||||
contract := "wormhole1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq0kdhcj"
|
||||
guardianKeyPath := string("./dev.guardian.key")
|
||||
|
||||
wormchainKey, err := wormconn.LoadWormchainPrivKey(wormchainKeyPath, "test0000")
|
||||
|
|
|
@ -238,12 +238,61 @@
|
|||
"3104": {
|
||||
"rpcUrlTilt": "http://wormchain:1317",
|
||||
"rpcUrlLocal": "http://localhost:1319",
|
||||
"rpcPort": "1319",
|
||||
"tendermintUrlTilt": "http://wormchain:26657",
|
||||
"tendermintUrlLocal": "http://localhost:26659",
|
||||
"rpcPort": "1317",
|
||||
"tendermintPort": "26657",
|
||||
"contracts": {
|
||||
"coreEmitterAddress": "wormhole1ap5vgur5zlgys8whugfegnn43emka567dtq0jl",
|
||||
"coreNativeAddress": "wormhole1ap5vgur5zlgys8whugfegnn43emka567dtq0jl",
|
||||
"tokenBridgeEmitterAddress": "wormhole1zugu6cajc4z7ue29g9wnes9a5ep9cs7yu7rn3z",
|
||||
"tokenBridgeNativeAddress": "wormhole1zugu6cajc4z7ue29g9wnes9a5ep9cs7yu7rn3z"
|
||||
"accountingNativeAddress": "wormhole1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq0kdhcj"
|
||||
},
|
||||
"accounts": {
|
||||
"wormchainNodeOfGuardian0": {
|
||||
"address": "C10820983F33456CE7BEB3A046F5A83FA34F027D",
|
||||
"addressBase64": "wQggmD8zRWznvrOgRvWoP6NPAn0=",
|
||||
"addressWormhole": "000000000000000000000000c10820983f33456ce7beb3a046f5a83fa34f027d",
|
||||
"public": "wormhole1cyyzpxplxdzkeea7kwsydadg87357qna3zg3tq",
|
||||
"privateHex": "48d23cc417a30674e907a2403f109f082d92e197823d02e6a423c6aeb8e41204",
|
||||
"cosmos.crypto.secp256k1.PubKey": "AuwYyCUBxQiBGSUWebU46c+OrlApVsyGLHd4qhSDZeiG",
|
||||
"tendermint/PrivKeyEd25519": "DONGe0wxovG1ZuCQ1iMbyBCW/hG5UeKz6ZFfhdZYznRSC48Lc1nwhUwXzHtXfwAOY0mO3mhTy4CMwPeYFvBZ1A==",
|
||||
"mnemonic": "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius"
|
||||
},
|
||||
"wormchainValidator0": {
|
||||
"public": "wormholevaloper1cyyzpxplxdzkeea7kwsydadg87357qna87hzv8",
|
||||
"tendermint/PubKeyEd25519": "fnfoo/C+i+Ng1J8vct6wfvrTS9JeNIG5UeO87ZHKMkY=",
|
||||
"tendermint/PrivKeyEd25519": "Zb3gQZSd8qNMyXUQdKmeqM/SSYeVDD80S4XPEsCAgPN+d+ij8L6L42DUny9y3rB++tNL0l40gblR47ztkcoyRg=="
|
||||
},
|
||||
"wormchainNodeOfGuardian1": {
|
||||
"address": "701C475B19A3F68D3FDEBF09591487FACEF2D636",
|
||||
"addressWormhole": "000000000000000000000000701c475b19a3f68d3fdebf09591487facef2d636",
|
||||
"addressBase64": "cBxHWxmj9o0/3r8JWRSH+s7y1jY=",
|
||||
"public": "wormhole1wqwywkce50mg6077huy4j9y8lt80943ks5udzr",
|
||||
"privateHex": "7095b73fa951fd117d54f3bca130b8088625db2d60d94d4f064791dc1a792b29",
|
||||
"cosmos.crypto.secp256k1.PubKey": "ApJi/CY2RGyzA5cQtDwU9c+o7T8OE+SjrgcG5PwLMjTP",
|
||||
"tendermint/PrivKeyEd25519": "TTdzb3XLJbSXP/5VhzPJCWysCDDH2hEXTqdvLI6RYk7rxPwzCXTprp2ZEfSCfQswYgUUQgO9JKzbAtfyeK2G1A==",
|
||||
"mnemonic": "maple pudding enjoy pole real rabbit soft make square city wrestle area aisle dwarf spike voice over still post lend genius bitter exit shoot"
|
||||
},
|
||||
"wormchainValidator1": {
|
||||
"public": "wormholevaloper1wqwywkce50mg6077huy4j9y8lt80943kxgr79y",
|
||||
"tendermint/PubKeyEd25519": "Zcujkt1sXRWWLfhgxLAm/Q+ioLn4wFim0OnGPLlCG0I=",
|
||||
"tendermint/PrivKeyEd25519": "SGWIYI3BgC/dxNOk1gYx6LpChAKqWGtAfZSx0SDFWuhly6OS3WxdFZYt+GDEsCb9D6KgufjAWKbQ6cY8uUIbQg=="
|
||||
}
|
||||
},
|
||||
"addresses": {
|
||||
"native": {
|
||||
"address": "uworm",
|
||||
"addressWormhole": "010c0ded78f1b69ec7b79b9ee592fbbcacebc97db1c695220a833135bfa74824",
|
||||
"denom": "uworm",
|
||||
"name": "worm",
|
||||
"symbol": "worm",
|
||||
"decimals": 0
|
||||
},
|
||||
"testToken": {
|
||||
"address": "wormhole1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqhnev3f",
|
||||
"addressWormhole": "003f822e9066cfea09b9ce1247e8f79a86a24dda2d8b3d76a608ae7583220411",
|
||||
"name": "MOCK",
|
||||
"symbol": "MCK",
|
||||
"decimals": 6
|
||||
}
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# copy devnet-consts.json to chain dirs for local use, so we can keep docker
|
||||
# build contexts scoped to the chain, rather than the root just to read this file.
|
||||
file="./scripts/devnet-consts.json"
|
||||
paths=(
|
||||
./terra2/tools/
|
||||
./wormchain/contracts/tools/
|
||||
)
|
||||
|
||||
for dest in "${paths[@]}"; do
|
||||
dirname=$(dirname $dest)
|
||||
if [[ -d "$dirname" ]]; then
|
||||
echo "copying $file to $dest"
|
||||
cp $file $dest
|
||||
fi
|
||||
done
|
||||
|
||||
echo "distribute devnet consts complete!"
|
|
@ -90,7 +90,6 @@ bscTokenBridge=$(jq --raw-output '.chains."4".contracts.tokenBridgeEmitterAddres
|
|||
algoTokenBridge=$(jq --raw-output '.chains."8".contracts.tokenBridgeEmitterAddress' $addressesJson)
|
||||
nearTokenBridge=$(jq --raw-output '.chains."15".contracts.tokenBridgeEmitterAddress' $addressesJson)
|
||||
terra2TokenBridge=$(jq --raw-output '.chains."18".contracts.tokenBridgeEmitterAddress' $addressesJson)
|
||||
wormchainTokenBridge=$(jq --raw-output '.chains."3104".contracts.tokenBridgeEmitterAddress' $addressesJson)
|
||||
aptosTokenBridge=$(jq --raw-output '.chains."22".contracts.tokenBridgeEmitterAddress' $addressesJson)
|
||||
|
||||
solNFTBridge=$(jq --raw-output '.chains."1".contracts.nftBridgeEmitterAddress' $addressesJson)
|
||||
|
@ -108,7 +107,6 @@ bscTokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m Tok
|
|||
algoTokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m TokenBridge -c algorand -a ${algoTokenBridge} -g ${guardiansPrivateCSV})
|
||||
nearTokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m TokenBridge -c near -a ${nearTokenBridge} -g ${guardiansPrivateCSV})
|
||||
terra2TokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m TokenBridge -c terra2 -a ${terra2TokenBridge} -g ${guardiansPrivateCSV})
|
||||
wormchainTokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m TokenBridge -c wormchain -a ${wormchainTokenBridge} -g ${guardiansPrivateCSV})
|
||||
aptosTokenBridgeVAA=$(node ./clients/js/build/main.js generate registration -m TokenBridge -c aptos -a ${aptosTokenBridge} -g ${guardiansPrivateCSV})
|
||||
|
||||
|
||||
|
@ -131,7 +129,6 @@ bscTokenBridge="REGISTER_BSC_TOKEN_BRIDGE_VAA"
|
|||
algoTokenBridge="REGISTER_ALGO_TOKEN_BRIDGE_VAA"
|
||||
terra2TokenBridge="REGISTER_TERRA2_TOKEN_BRIDGE_VAA"
|
||||
nearTokenBridge="REGISTER_NEAR_TOKEN_BRIDGE_VAA"
|
||||
wormchainTokenBridge="REGISTER_WORMCHAIN_TOKEN_BRIDGE_VAA"
|
||||
aptosTokenBridge="REGISTER_APTOS_TOKEN_BRIDGE_VAA"
|
||||
|
||||
solNFTBridge="REGISTER_SOL_NFT_BRIDGE_VAA"
|
||||
|
@ -193,10 +190,6 @@ upsert_env_file $envFile $nearTokenBridge $nearTokenBridgeVAA
|
|||
upsert_env_file $ethFile $nearNFTBridge $nearNFTBridgeVAA
|
||||
upsert_env_file $envFile $nearNFTBridge $nearNFTBridgeVAA
|
||||
|
||||
# wormchain token bridge
|
||||
upsert_env_file $ethFile $wormchainTokenBridge $wormchainTokenBridgeVAA
|
||||
upsert_env_file $envFile $wormchainTokenBridge $wormchainTokenBridgeVAA
|
||||
|
||||
# 7) copy the local .env file to the solana & terra dirs, if the script is running on the host machine
|
||||
# chain dirs will not exist if running in docker for Tilt, only if running locally. check before copying.
|
||||
# copy ethFile to ethereum
|
||||
|
@ -212,6 +205,7 @@ paths=(
|
|||
./solana/.env
|
||||
./terra/tools/.env
|
||||
./cosmwasm/deployment/terra2/tools/.env
|
||||
./wormchain/contracts/tools/.env
|
||||
)
|
||||
|
||||
for envDest in "${paths[@]}"; do
|
||||
|
|
|
@ -538,8 +538,8 @@ const DEVNET = {
|
|||
nft_bridge: undefined,
|
||||
},
|
||||
wormchain: {
|
||||
core: "wormhole1ap5vgur5zlgys8whugfegnn43emka567dtq0jl",
|
||||
token_bridge: "wormhole1zugu6cajc4z7ue29g9wnes9a5ep9cs7yu7rn3z",
|
||||
core: "wormhole14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srrg465",
|
||||
token_bridge: "wormhole1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq0kdhcj",
|
||||
nft_bridge: undefined,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -274,8 +274,6 @@ const contract_registrations = {
|
|||
process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA,
|
||||
// NEAR
|
||||
process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA,
|
||||
// Wormhole Chain
|
||||
process.env.REGISTER_WORMCHAIN_TOKEN_BRIDGE_VAA,
|
||||
// APTOS
|
||||
process.env.REGISTER_APTOS_TOKEN_BRIDGE_VAA,
|
||||
],
|
||||
|
|
|
@ -14,6 +14,7 @@ devnet/wormchain-*/config/addrbook.json
|
|||
devnet/wormchain-*/config/genesis.json
|
||||
ts-sdk/node_modules
|
||||
ts-sdk/lib
|
||||
contracts/artifacts
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
|
|
|
@ -43,6 +43,31 @@ ts-sdk: vue
|
|||
run: build/wormchaind
|
||||
./$< start --home build --log_level="debug"
|
||||
|
||||
# get npm packages for contracts/tools
|
||||
contracts-tools-deps: contracts/tools/package-lock.json
|
||||
npm ci --prefix=contracts/tools
|
||||
|
||||
# get .env and devnet-consts.json for contracts/tools
|
||||
contracts-devnet-env:
|
||||
cd .. && ./scripts/guardian-set-init.sh 1
|
||||
cd .. && ./scripts/distribute-devnet-consts.sh
|
||||
|
||||
# get wasm artifacts for cosmwasm contracts
|
||||
contracts-artifacts:
|
||||
cd ../cosmwasm && $(MAKE) artifacts
|
||||
cp -r ../cosmwasm/artifacts contracts
|
||||
|
||||
# get everything needed to
|
||||
contracts-deploy-setup: contracts-tools-deps contracts-devnet-env contracts-artifacts
|
||||
|
||||
# runs the contract deployment script
|
||||
contracts-deploy-local: contracts-deploy-setup
|
||||
npm run deploy-wormchain --prefix=contracts/tools
|
||||
|
||||
# starts wormchaind in a container, deploys contracts, tests contract interaction
|
||||
contracts-deploy-test: client contracts-deploy-setup
|
||||
./contracts/run_deploy_test.sh
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -v ./...
|
||||
|
|
|
@ -1,58 +1,208 @@
|
|||
halt-height = 0
|
||||
halt-time = 0
|
||||
index-events = []
|
||||
inter-block-cache = true
|
||||
min-retain-blocks = 0
|
||||
minimum-gas-prices = "0stake"
|
||||
pruning = "default"
|
||||
pruning-interval = "0"
|
||||
pruning-keep-every = "0"
|
||||
pruning-keep-recent = "0"
|
||||
# Cosmos Node config
|
||||
|
||||
###############################################################################
|
||||
### Base Configuration ###
|
||||
###############################################################################
|
||||
|
||||
chain-id = "wormchain"
|
||||
|
||||
[api]
|
||||
address = "tcp://localhost:1317"
|
||||
enable = true
|
||||
enabled-unsafe-cors = true
|
||||
max-open-connections = 1000
|
||||
rpc-max-body-bytes = 1000000
|
||||
rpc-read-timeout = 10
|
||||
rpc-write-timeout = 0
|
||||
swagger = false
|
||||
# The minimum gas prices a validator is willing to accept for processing a
|
||||
# transaction. A transaction's fees must meet the minimum of any denomination
|
||||
# specified in this config (e.g. 0.25token1;0.0001token2).
|
||||
minimum-gas-prices = "0uworm"
|
||||
|
||||
[grpc]
|
||||
address = "0.0.0.0:9090"
|
||||
enable = true
|
||||
# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals
|
||||
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
|
||||
# everything: all saved states will be deleted, storing only the current and previous state; pruning at 10 block intervals
|
||||
# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval'
|
||||
pruning = "default"
|
||||
|
||||
[grpc-web]
|
||||
address = "0.0.0.0:9091"
|
||||
enable = true
|
||||
enable-unsafe-cors = false
|
||||
# These are applied if and only if the pruning strategy is custom.
|
||||
pruning-keep-recent = "0"
|
||||
pruning-keep-every = "0"
|
||||
pruning-interval = "0"
|
||||
|
||||
[rosetta]
|
||||
address = ":8080"
|
||||
blockchain = "app"
|
||||
enable = false
|
||||
network = "network"
|
||||
offline = false
|
||||
retries = 3
|
||||
# HaltHeight contains a non-zero block height at which a node will gracefully
|
||||
# halt and shutdown that can be used to assist upgrades and testing.
|
||||
#
|
||||
# Note: Commitment of state will be attempted on the corresponding block.
|
||||
halt-height = 0
|
||||
|
||||
[rpc]
|
||||
cors_allowed_origins = ["*"]
|
||||
# HaltTime contains a non-zero minimum block time (in Unix seconds) at which
|
||||
# a node will gracefully halt and shutdown that can be used to assist upgrades
|
||||
# and testing.
|
||||
#
|
||||
# Note: Commitment of state will be attempted on the corresponding block.
|
||||
halt-time = 0
|
||||
|
||||
[state-sync]
|
||||
snapshot-interval = 0
|
||||
snapshot-keep-recent = 2
|
||||
# MinRetainBlocks defines the minimum block height offset from the current
|
||||
# block being committed, such that all blocks past this offset are pruned
|
||||
# from Tendermint. It is used as part of the process of determining the
|
||||
# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates
|
||||
# that no blocks should be pruned.
|
||||
#
|
||||
# This configuration value is only responsible for pruning Tendermint blocks.
|
||||
# It has no bearing on application state pruning which is determined by the
|
||||
# "pruning-*" configurations.
|
||||
#
|
||||
# Note: Tendermint block pruning is dependant on this parameter in conunction
|
||||
# with the unbonding (safety threshold) period, state pruning and state sync
|
||||
# snapshot parameters to determine the correct minimum value of
|
||||
# ResponseCommit.RetainHeight.
|
||||
min-retain-blocks = 0
|
||||
|
||||
# InterBlockCache enables inter-block caching.
|
||||
inter-block-cache = true
|
||||
|
||||
# IndexEvents defines the set of events in the form {eventType}.{attributeKey},
|
||||
# which informs Tendermint what to index. If empty, all events will be indexed.
|
||||
#
|
||||
# Example:
|
||||
# ["message.sender", "message.recipient"]
|
||||
index-events = []
|
||||
|
||||
# IavlCacheSize set the size of the iavl tree cache.
|
||||
# Default cache size is 50mb.
|
||||
iavl-cache-size = 781250
|
||||
|
||||
# IAVLDisableFastNode enables or disables the fast node feature of IAVL.
|
||||
# Default is true.
|
||||
iavl-disable-fastnode = true
|
||||
|
||||
###############################################################################
|
||||
### Telemetry Configuration ###
|
||||
###############################################################################
|
||||
|
||||
[telemetry]
|
||||
enable-hostname = false
|
||||
enable-hostname-label = false
|
||||
enable-service-label = false
|
||||
enabled = false
|
||||
global-labels = []
|
||||
prometheus-retention-time = 0
|
||||
service-name = ""
|
||||
|
||||
# Prefixed with keys to separate services.
|
||||
service-name = ""
|
||||
|
||||
# Enabled enables the application telemetry functionality. When enabled,
|
||||
# an in-memory sink is also enabled by default. Operators may also enabled
|
||||
# other sinks such as Prometheus.
|
||||
enabled = false
|
||||
|
||||
# Enable prefixing gauge values with hostname.
|
||||
enable-hostname = false
|
||||
|
||||
# Enable adding hostname to labels.
|
||||
enable-hostname-label = false
|
||||
|
||||
# Enable adding service to labels.
|
||||
enable-service-label = false
|
||||
|
||||
# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink.
|
||||
prometheus-retention-time = 0
|
||||
|
||||
# GlobalLabels defines a global set of name/value label tuples applied to all
|
||||
# metrics emitted using the wrapper functions defined in telemetry package.
|
||||
#
|
||||
# Example:
|
||||
# [["chain_id", "cosmoshub-1"]]
|
||||
global-labels = [
|
||||
]
|
||||
|
||||
###############################################################################
|
||||
### API Configuration ###
|
||||
###############################################################################
|
||||
|
||||
[api]
|
||||
|
||||
# Enable defines if the API server should be enabled.
|
||||
enable = true
|
||||
|
||||
# Swagger defines if swagger documentation should automatically be registered.
|
||||
swagger = false
|
||||
|
||||
# Address defines the API server to listen on.
|
||||
address = "tcp://0.0.0.0:1317"
|
||||
|
||||
# MaxOpenConnections defines the number of maximum open connections.
|
||||
max-open-connections = 1000
|
||||
|
||||
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds).
|
||||
rpc-read-timeout = 10
|
||||
|
||||
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds).
|
||||
rpc-write-timeout = 0
|
||||
|
||||
# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes).
|
||||
rpc-max-body-bytes = 1000000
|
||||
|
||||
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
|
||||
enabled-unsafe-cors = true
|
||||
|
||||
###############################################################################
|
||||
### Rosetta Configuration ###
|
||||
###############################################################################
|
||||
|
||||
[rosetta]
|
||||
|
||||
# Enable defines if the Rosetta API server should be enabled.
|
||||
enable = false
|
||||
|
||||
# Address defines the Rosetta API server to listen on.
|
||||
address = ":8080"
|
||||
|
||||
# Network defines the name of the blockchain that will be returned by Rosetta.
|
||||
blockchain = "app"
|
||||
|
||||
# Network defines the name of the network that will be returned by Rosetta.
|
||||
network = "network"
|
||||
|
||||
# Retries defines the number of retries when connecting to the node before failing.
|
||||
retries = 3
|
||||
|
||||
# Offline defines if Rosetta server should run in offline mode.
|
||||
offline = false
|
||||
|
||||
###############################################################################
|
||||
### gRPC Configuration ###
|
||||
###############################################################################
|
||||
|
||||
[grpc]
|
||||
|
||||
# Enable defines if the gRPC server should be enabled.
|
||||
enable = true
|
||||
|
||||
# Address defines the gRPC server address to bind to.
|
||||
address = "0.0.0.0:9090"
|
||||
|
||||
###############################################################################
|
||||
### gRPC Web Configuration ###
|
||||
###############################################################################
|
||||
|
||||
[grpc-web]
|
||||
|
||||
# GRPCWebEnable defines if the gRPC-web should be enabled.
|
||||
# NOTE: gRPC must also be enabled, otherwise, this configuration is a no-op.
|
||||
enable = true
|
||||
|
||||
# Address defines the gRPC-web server address to bind to.
|
||||
address = "0.0.0.0:9091"
|
||||
|
||||
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
|
||||
enable-unsafe-cors = true
|
||||
|
||||
###############################################################################
|
||||
### State Sync Configuration ###
|
||||
###############################################################################
|
||||
|
||||
# State sync snapshots allow other nodes to rapidly join the network without replaying historical
|
||||
# blocks, instead downloading and applying a snapshot of the application state at a given height.
|
||||
[state-sync]
|
||||
|
||||
# snapshot-interval specifies the block interval at which local state sync snapshots are
|
||||
# taken (0 to disable). Must be a multiple of pruning-keep-every.
|
||||
snapshot-interval = 0
|
||||
|
||||
# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all).
|
||||
snapshot-keep-recent = 2
|
||||
|
||||
[wasm]
|
||||
lru_size = 0
|
||||
query_gas_limit = 300000
|
||||
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
||||
query_gas_limit = 300000
|
||||
# This is the number of wasm vm instances we keep cached in memory for speed-up
|
||||
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
|
||||
lru_size = 0
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
broadcast-mode = "block"
|
||||
# Tendermint client config
|
||||
|
||||
###############################################################################
|
||||
### Client Configuration ###
|
||||
###############################################################################
|
||||
|
||||
# The network chain ID
|
||||
chain-id = "wormchain"
|
||||
# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory)
|
||||
keyring-backend = "test"
|
||||
node = "tcp://localhost:26657"
|
||||
# CLI output format (text|json)
|
||||
output = "text"
|
||||
# <host>:<port> to Tendermint RPC interface for this chain
|
||||
node = "tcp://0.0.0.0:26657"
|
||||
# Transaction broadcasting mode (sync|async|block)
|
||||
broadcast-mode = "block"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
proxy_app = "tcp://127.0.0.1:26658"
|
||||
|
||||
# A custom human readable name for this node
|
||||
moniker = "mynode"
|
||||
moniker = "wormchain-local"
|
||||
|
||||
# If this node is many blocks behind the tip of the chain, FastSync
|
||||
# allows them to catchup quickly by downloading blocks in parallel
|
||||
|
@ -93,7 +93,7 @@ laddr = "tcp://0.0.0.0:26657"
|
|||
# A list of origins a cross-domain request can be executed from
|
||||
# Default value '[]' disables cors support
|
||||
# Use '["*"]' to allow any origin
|
||||
cors_allowed_origins = ["*", ]
|
||||
cors_allowed_origins = []
|
||||
|
||||
# A list of methods the client is allowed to use with cross-domain requests
|
||||
cors_allowed_methods = ["HEAD", "GET", "POST", ]
|
||||
|
@ -136,6 +136,33 @@ max_subscription_clients = 100
|
|||
# the estimated # maximum number of broadcast_tx_commit calls per block.
|
||||
max_subscriptions_per_client = 5
|
||||
|
||||
# Experimental parameter to specify the maximum number of events a node will
|
||||
# buffer, per subscription, before returning an error and closing the
|
||||
# subscription. Must be set to at least 100, but higher values will accommodate
|
||||
# higher event throughput rates (and will use more memory).
|
||||
experimental_subscription_buffer_size = 200
|
||||
|
||||
# Experimental parameter to specify the maximum number of RPC responses that
|
||||
# can be buffered per WebSocket client. If clients cannot read from the
|
||||
# WebSocket endpoint fast enough, they will be disconnected, so increasing this
|
||||
# parameter may reduce the chances of them being disconnected (but will cause
|
||||
# the node to use more memory).
|
||||
#
|
||||
# Must be at least the same as "experimental_subscription_buffer_size",
|
||||
# otherwise connections could be dropped unnecessarily. This value should
|
||||
# ideally be somewhat higher than "experimental_subscription_buffer_size" to
|
||||
# accommodate non-subscription-related RPC responses.
|
||||
experimental_websocket_write_buffer_size = 200
|
||||
|
||||
# If a WebSocket client cannot read fast enough, at present we may
|
||||
# silently drop events instead of generating an error or disconnecting the
|
||||
# client.
|
||||
#
|
||||
# Enabling this experimental parameter will cause the WebSocket connection to
|
||||
# be closed instead if it cannot read fast enough, allowing for greater
|
||||
# predictability in subscription behaviour.
|
||||
experimental_close_on_slow_client = false
|
||||
|
||||
# How long to wait for a tx to be committed during /broadcast_tx_commit.
|
||||
# WARNING: Using a value larger than 10s will result in increasing the
|
||||
# global HTTP write timeout, which applies to all connections and endpoints.
|
||||
|
@ -245,6 +272,11 @@ dial_timeout = "3s"
|
|||
#######################################################
|
||||
[mempool]
|
||||
|
||||
# Mempool version to use:
|
||||
# 1) "v0" - (default) FIFO mempool.
|
||||
# 2) "v1" - prioritized mempool.
|
||||
version = "v0"
|
||||
|
||||
recheck = true
|
||||
broadcast = true
|
||||
wal_dir = ""
|
||||
|
@ -274,6 +306,22 @@ max_tx_bytes = 1048576
|
|||
# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796
|
||||
max_batch_bytes = 0
|
||||
|
||||
# ttl-duration, if non-zero, defines the maximum amount of time a transaction
|
||||
# can exist for in the mempool.
|
||||
#
|
||||
# Note, if ttl-num-blocks is also defined, a transaction will be removed if it
|
||||
# has existed in the mempool at least ttl-num-blocks number of blocks or if it's
|
||||
# insertion time into the mempool is beyond ttl-duration.
|
||||
ttl-duration = "0s"
|
||||
|
||||
# ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction
|
||||
# can exist for in the mempool.
|
||||
#
|
||||
# Note, if ttl-duration is also defined, a transaction will be removed if it
|
||||
# has existed in the mempool at least ttl-num-blocks number of blocks or if
|
||||
# it's insertion time into the mempool is beyond ttl-duration.
|
||||
ttl-num-blocks = 0
|
||||
|
||||
#######################################################
|
||||
### State Sync Configuration Options ###
|
||||
#######################################################
|
||||
|
@ -362,6 +410,16 @@ create_empty_blocks_interval = "0s"
|
|||
peer_gossip_sleep_duration = "100ms"
|
||||
peer_query_maj23_sleep_duration = "2s"
|
||||
|
||||
#######################################################
|
||||
### Storage Configuration Options ###
|
||||
#######################################################
|
||||
|
||||
# Set to true to discard ABCI responses from the state store, which can save a
|
||||
# considerable amount of disk space. Set to false to ensure ABCI responses are
|
||||
# persisted. ABCI responses are required for /block_results RPC queries, and to
|
||||
# reindex events in the command-line tool.
|
||||
discard_abci_responses = false
|
||||
|
||||
#######################################################
|
||||
### Transaction Indexer Configuration Options ###
|
||||
#######################################################
|
||||
|
@ -376,8 +434,14 @@ peer_query_maj23_sleep_duration = "2s"
|
|||
# 1) "null"
|
||||
# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
|
||||
# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed.
|
||||
# 3) "psql" - the indexer services backed by PostgreSQL.
|
||||
# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed.
|
||||
indexer = "kv"
|
||||
|
||||
# The PostgreSQL connection configuration, the connection format:
|
||||
# postgresql://<user>:<password>@<host>:<port>/<db>?<opts>
|
||||
psql-conn = ""
|
||||
|
||||
#######################################################
|
||||
### Instrumentation Configuration Options ###
|
||||
#######################################################
|
||||
|
|
|
@ -65,7 +65,11 @@
|
|||
"coins": [
|
||||
{
|
||||
"denom": "utest",
|
||||
"amount": "10000"
|
||||
"amount": "100000000"
|
||||
},
|
||||
{
|
||||
"denom": "uworm",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -74,7 +78,11 @@
|
|||
"coins": [
|
||||
{
|
||||
"denom": "utest",
|
||||
"amount": "20000"
|
||||
"amount": "100000000000"
|
||||
},
|
||||
{
|
||||
"denom": "uworm",
|
||||
"amount": "200000000"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -380,4 +388,4 @@
|
|||
"sequenceCounterList": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
#!/usr/bin/env bash
|
||||
set -exu pipefail
|
||||
|
||||
echo "Starting wormchaind"
|
||||
./build/wormchaind start --home build --rpc.laddr="tcp://0.0.0.0:26659" > wormchaind.out 2>&1 &
|
||||
# give wormchain 2 seconds to startup
|
||||
sleep 2
|
||||
|
||||
cleanup() {
|
||||
echo "cleaning up test container"
|
||||
# kill wormchain, any dependents of the process (just in case)
|
||||
pkill -f "./build/wormchaind start --home build --rpc.laddr=tcp://0.0.0.0:26659"
|
||||
pkill -P $$
|
||||
# remove wormchaind log file
|
||||
rm wormchaind.out
|
||||
}
|
||||
|
||||
cleanup_and_exit_failure() {
|
||||
cleanup
|
||||
echo "exiting with failure code"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# run the deploy, and catch if it returns an error code
|
||||
npm run deploy-and-test --prefix contracts/tools || cleanup_and_exit_failure
|
||||
|
||||
# cleanup and return success
|
||||
cleanup
|
|
@ -0,0 +1 @@
|
|||
save-exact=true
|
|
@ -0,0 +1,206 @@
|
|||
import "dotenv/config";
|
||||
import * as os from "os"
|
||||
import { SigningCosmWasmClient, InstantiateResult } from "@cosmjs/cosmwasm-stargate";
|
||||
import { GasPrice } from "@cosmjs/stargate"
|
||||
import { Secp256k1HdWallet } from "@cosmjs/amino";
|
||||
import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx";
|
||||
import * as fs from "fs";
|
||||
import { readdirSync, } from "fs";
|
||||
import * as util from 'util'
|
||||
import { toUtf8 } from "@cosmjs/encoding";
|
||||
|
||||
import * as devnetConsts from "./devnet-consts.json"
|
||||
|
||||
if (process.env.INIT_SIGNERS === "undefined") {
|
||||
let msg = `.env is missing. run "make contracts-tools-deps" to fetch.`
|
||||
console.error(msg)
|
||||
throw msg
|
||||
}
|
||||
|
||||
const readFileAsync = util.promisify(fs.readFile);
|
||||
|
||||
/*
|
||||
NOTE: Only append to this array: keeping the ordering is crucial, as the
|
||||
contracts must be imported in a deterministic order so their addresses remain
|
||||
deterministic.
|
||||
*/
|
||||
type ContractName = string
|
||||
const artifacts: ContractName[] = [
|
||||
"cw20_base.wasm",
|
||||
"wormchain_accounting.wasm",
|
||||
];
|
||||
|
||||
const ARTIFACTS_PATH = "../artifacts/"
|
||||
/* Check that the artifact folder contains all the wasm files we expect and nothing else */
|
||||
|
||||
try {
|
||||
const actual_artifacts = readdirSync(ARTIFACTS_PATH).filter((a) =>
|
||||
a.endsWith(".wasm")
|
||||
);
|
||||
|
||||
const missing_artifacts = artifacts.filter(
|
||||
(a) => !actual_artifacts.includes(a)
|
||||
);
|
||||
if (missing_artifacts.length) {
|
||||
console.log(
|
||||
"Error during wormchain deployment. The following files are expected to be in the artifacts folder:"
|
||||
);
|
||||
missing_artifacts.forEach((file) => console.log(` - ${file}`));
|
||||
console.log(
|
||||
"Hint: the deploy script needs to run after the contracts have been built."
|
||||
);
|
||||
console.log(
|
||||
"External binary blobs need to be manually added in tools/Dockerfile."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`${ARTIFACTS_PATH} cannot be read. Do you need to run "make contracts-deploy-setup"?`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function main() {
|
||||
|
||||
/* Set up cosmos client & wallet */
|
||||
|
||||
let host = devnetConsts.chains[3104].tendermintUrlLocal
|
||||
if (os.hostname().includes("wormchain-deploy")) {
|
||||
// running in tilt devnet
|
||||
host = devnetConsts.chains[3104].tendermintUrlTilt
|
||||
}
|
||||
const denom = devnetConsts.chains[3104].addresses.native.denom
|
||||
const mnemonic = devnetConsts.chains[3104].accounts.wormchainNodeOfGuardian0.mnemonic
|
||||
const addressPrefix = "wormhole"
|
||||
|
||||
const w = await Secp256k1HdWallet.fromMnemonic(mnemonic, { prefix: addressPrefix })
|
||||
|
||||
|
||||
const gas = GasPrice.fromString(`0${denom}`)
|
||||
let cwc: SigningCosmWasmClient
|
||||
try {
|
||||
cwc = await SigningCosmWasmClient.connectWithSigner(host, w, { prefix: addressPrefix, gasPrice: gas })
|
||||
} catch (e) {
|
||||
let msg = `could not connect to wormchain host: ${host}`
|
||||
if (e?.message) {
|
||||
console.error(e.message)
|
||||
}
|
||||
throw msg
|
||||
}
|
||||
|
||||
|
||||
// there are several Cosmos chains in devnet, so check the config is as expected
|
||||
let id = await cwc.getChainId()
|
||||
if (id !== "wormchain") {
|
||||
throw new Error(`Wormchain CosmWasmClient connection produced an unexpected chainID: ${id}`)
|
||||
}
|
||||
|
||||
const signers = await w.getAccounts()
|
||||
const signer = signers[0].address
|
||||
console.log("wormchain contract deployer is: ", signer)
|
||||
|
||||
/* Deploy artifacts */
|
||||
|
||||
const codeIds: { [name: ContractName]: number } = await artifacts.reduce(async (prev, file) => {
|
||||
// wait for the previous to finish, to avoid the race condition of wallet sequence mismatch.
|
||||
const accum = await prev
|
||||
|
||||
const contract_bytes = await readFileAsync(`${ARTIFACTS_PATH}${file}`);
|
||||
|
||||
const i = await cwc.upload(signer, contract_bytes, "auto", "")
|
||||
console.log(`uploaded ${file}, codeID: ${i.codeId}, tx: ${i.transactionHash}`, i.codeId, i.transactionHash)
|
||||
|
||||
accum[file] = i.codeId
|
||||
return accum
|
||||
}, Object())
|
||||
|
||||
// Instantiate contracts.
|
||||
|
||||
async function instantiate(code_id: number, inst_msg: any, label: string) {
|
||||
let inst = await cwc.instantiate(signer, code_id, inst_msg, label, "auto", {})
|
||||
let addr = inst.contractAddress
|
||||
let txHash = inst.transactionHash
|
||||
console.log(`deployed contract ${label}, codeID: ${code_id}, address: ${addr}, txHash: ${txHash}`)
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
// Instantiate contracts.
|
||||
// NOTE: Only append at the end, the ordering must be deterministic.
|
||||
|
||||
const addresses: { [contractName: string]: InstantiateResult["transactionHash"] } = {};
|
||||
|
||||
const init_guardians: string[] = JSON.parse(String(process.env.INIT_SIGNERS));
|
||||
if (!init_guardians || init_guardians.length === 0) {
|
||||
throw "failed to get initial guardians from .env file.";
|
||||
}
|
||||
|
||||
addresses["mock.wasm"] = await instantiate(
|
||||
codeIds["cw20_base.wasm"],
|
||||
{
|
||||
name: "MOCK",
|
||||
symbol: "MCK",
|
||||
decimals: 6,
|
||||
initial_balances: [
|
||||
{
|
||||
address: signer,
|
||||
amount: "100000000",
|
||||
},
|
||||
],
|
||||
mint: null,
|
||||
},
|
||||
"mock"
|
||||
);
|
||||
console.log('instantiated cw20 MOCK token: ', addresses["mock.wasm"])
|
||||
|
||||
|
||||
const registrations: { [chainName: string]: string } = {
|
||||
// keys are only used for logging success/failure
|
||||
"solana": String(process.env.REGISTER_SOL_TOKEN_BRIDGE_VAA),
|
||||
"ethereum": String(process.env.REGISTER_ETH_TOKEN_BRIDGE_VAA),
|
||||
"bsc": String(process.env.REGISTER_BSC_TOKEN_BRIDGE_VAA),
|
||||
"algo": String(process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA),
|
||||
"terra": String(process.env.REGISTER_TERRA_TOKEN_BRIDGE_VAA),
|
||||
"near": String(process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA),
|
||||
"terra2": String(process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA),
|
||||
"aptos": String(process.env.REGISTER_APTOS_TOKEN_BRIDGE_VAA),
|
||||
}
|
||||
|
||||
|
||||
const instantiateMsg = {}
|
||||
addresses["wormchain_accounting.wasm"] = await instantiate(
|
||||
codeIds["wormchain_accounting.wasm"],
|
||||
instantiateMsg,
|
||||
"wormchainAccounting"
|
||||
)
|
||||
console.log("instantiated accounting: ", addresses["wormchain_accounting.wasm"])
|
||||
|
||||
const accountingRegistrations = Object.values(registrations)
|
||||
.map(r => Buffer.from(r, "hex").toString("base64"))
|
||||
|
||||
const msg = {
|
||||
typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
|
||||
value: MsgExecuteContract.fromPartial({
|
||||
sender: signer,
|
||||
contract: addresses["wormchain_accounting.wasm"],
|
||||
msg: toUtf8(JSON.stringify({
|
||||
submit_v_a_as: {
|
||||
vaas: accountingRegistrations,
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
const res = await cwc.signAndBroadcast(signer, [msg], "auto");
|
||||
console.log(`sent accounting chain registrations, tx: `, res.transactionHash);
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
main()
|
||||
} catch (e: any) {
|
||||
if (e?.message) {
|
||||
console.error(e.message)
|
||||
}
|
||||
throw e
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@wormhole-foundation/wormchain-contract-tools",
|
||||
"version": "0.0.1",
|
||||
"description": "scripts for working with wormchain contracts",
|
||||
"main": "deploy_wormchain.ts",
|
||||
"scripts": {
|
||||
"deploy-wormchain": "ts-node deploy_wormchain.ts",
|
||||
"test-wormchain": "ts-node test_wormchain.ts",
|
||||
"deploy-and-test": "npm run deploy-wormchain && npm run test-wormchain"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"dependencies": {
|
||||
"@cosmjs/cosmwasm-stargate": "0.29.5",
|
||||
"cosmwasm": "1.1.1",
|
||||
"dotenv": "16.0.3",
|
||||
"elliptic": "6.5.4",
|
||||
"ethers": "5.7.2",
|
||||
"web3-eth-abi": "1.8.1",
|
||||
"yargs": "17.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/elliptic": "6.4.14",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.9.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
import "dotenv/config";
|
||||
import * as os from "os"
|
||||
import { SigningCosmWasmClient, toBinary } from "@cosmjs/cosmwasm-stargate";
|
||||
import { GasPrice } from "@cosmjs/stargate"
|
||||
import { fromBase64 } from "cosmwasm";
|
||||
import { Secp256k1HdWallet } from "@cosmjs/amino";
|
||||
|
||||
import { zeroPad } from "ethers/lib/utils.js";
|
||||
import { keccak256 } from "@cosmjs/crypto"
|
||||
|
||||
import * as elliptic from "elliptic"
|
||||
import { concatArrays, encodeUint8 } from "./utils";
|
||||
|
||||
import * as devnetConsts from "./devnet-consts.json"
|
||||
|
||||
|
||||
function signBinary(key: elliptic.ec.KeyPair, binary: string): Uint8Array {
|
||||
// base64 string to Uint8Array,
|
||||
// so we have bytes to work with for signing, though not sure 100% that's correct.
|
||||
const bytes = fromBase64(binary);
|
||||
|
||||
// create the "digest" for signing.
|
||||
// The contract will calculate the digest of the "data",
|
||||
// then use that with the signature to ec recover the publickey that signed.
|
||||
const digest = keccak256(keccak256(bytes));
|
||||
|
||||
// sign the digest
|
||||
const signature = key.sign(digest, { canonical: true });
|
||||
|
||||
// create 65 byte signature (64 + 1)
|
||||
const signedParts = [
|
||||
zeroPad(signature.r.toBuffer(), 32),
|
||||
zeroPad(signature.s.toBuffer(), 32),
|
||||
encodeUint8(signature.recoveryParam || 0),
|
||||
];
|
||||
|
||||
// combine parts to be Uint8Array with length 65
|
||||
const signed = concatArrays(signedParts);
|
||||
|
||||
return signed
|
||||
}
|
||||
|
||||
|
||||
async function main() {
|
||||
|
||||
/* Set up cosmos client & wallet */
|
||||
|
||||
const WORMCHAIN_ID = 3104
|
||||
|
||||
let host = devnetConsts.chains[3104].tendermintUrlLocal
|
||||
if (os.hostname().includes("wormchain-deploy")) {
|
||||
// running in tilt devnet
|
||||
host = devnetConsts.chains[3104].tendermintUrlTilt
|
||||
}
|
||||
const denom = devnetConsts.chains[WORMCHAIN_ID].addresses.native.denom
|
||||
const mnemonic = devnetConsts.chains[WORMCHAIN_ID].accounts.wormchainNodeOfGuardian0.mnemonic
|
||||
const addressPrefix = "wormhole"
|
||||
const signerPk = devnetConsts.devnetGuardians[0].private
|
||||
const accountingAddress = devnetConsts.chains[WORMCHAIN_ID].contracts.accountingNativeAddress
|
||||
|
||||
const w = await Secp256k1HdWallet.fromMnemonic(mnemonic, { prefix: addressPrefix })
|
||||
|
||||
const gas = GasPrice.fromString(`0${denom}`)
|
||||
let cwc = await SigningCosmWasmClient.connectWithSigner(host, w, { prefix: addressPrefix, gasPrice: gas })
|
||||
|
||||
// there is no danger here, just several Cosmos chains in devnet, so check for config issues
|
||||
let id = await cwc.getChainId()
|
||||
if (id !== "wormchain") {
|
||||
throw new Error(`Wormchain CosmWasmClient connection produced an unexpected chainID: ${id}`)
|
||||
}
|
||||
|
||||
const signers = await w.getAccounts()
|
||||
const signer = signers[0].address
|
||||
console.log("wormchain wallet pubkey: ", signer)
|
||||
|
||||
const nativeBalance = await cwc.getBalance(signer, denom)
|
||||
console.log("nativeBalance ", nativeBalance.amount)
|
||||
|
||||
const utestBalance = await cwc.getBalance(signer, "utest")
|
||||
console.log("utest balance ", utestBalance.amount)
|
||||
|
||||
|
||||
// create key for guardian0
|
||||
const ec = new elliptic.ec("secp256k1");
|
||||
// create key from the devnet guardian0's private key
|
||||
const key = ec.keyFromPrivate(Buffer.from(signerPk, "hex"));
|
||||
|
||||
|
||||
// Test empty observation
|
||||
|
||||
// object to json string, then to base64 (serde binary)
|
||||
const arrayBinaryString = toBinary([]);
|
||||
|
||||
// combine parts to be Uint8Array with length 65
|
||||
const signedEmptyArray = signBinary(key, arrayBinaryString)
|
||||
|
||||
const observeEmptyArray = {
|
||||
submit_observations: {
|
||||
observations: arrayBinaryString,
|
||||
guardian_set_index: 0,
|
||||
signature: {
|
||||
index: 0,
|
||||
signature: Array.from(signedEmptyArray),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let emptyArrayObsRes = await cwc.execute(signer, accountingAddress, observeEmptyArray, "auto");
|
||||
console.log(`emptyArrayObsRes.transactionHash: ${emptyArrayObsRes.transactionHash}`);
|
||||
|
||||
|
||||
// Test (fake) observation
|
||||
const emitter_address = "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16"
|
||||
const observations = [
|
||||
{
|
||||
emitter_chain: 2,
|
||||
emitter_address: emitter_address,
|
||||
sequence: 2,
|
||||
nonce: 1,
|
||||
consistency_level: 0,
|
||||
timestamp: 1,
|
||||
payload:
|
||||
Buffer.from("030000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000002d8be6bf0baa74e0a907016679cae9190e80dd0a0002000000000000000000000000c10820983f33456ce7beb3a046f5a83fa34f027d0c2000000000000000000000000000000000000000000000000000000000000f4240", "hex").toString("base64"),
|
||||
|
||||
tx_hash:
|
||||
Buffer.from("9fc68fb0ee735d45c9074a20adef1747b0593803f33b9f3f2252c8e2df567f41", "hex").toString("base64")
|
||||
},
|
||||
];
|
||||
|
||||
// object to json string, then to base64 (serde binary)
|
||||
const observationsBinaryString = toBinary(observations);
|
||||
|
||||
const signed = signBinary(key, observationsBinaryString)
|
||||
|
||||
const executeMsg = {
|
||||
submit_observations: {
|
||||
observations: observationsBinaryString,
|
||||
guardian_set_index: 0,
|
||||
signature: {
|
||||
index: 0,
|
||||
signature: Array.from(signed),
|
||||
},
|
||||
},
|
||||
};
|
||||
console.log(executeMsg);
|
||||
|
||||
let inst = await cwc.execute(
|
||||
signer,
|
||||
accountingAddress,
|
||||
executeMsg,
|
||||
"auto"
|
||||
);
|
||||
let txHash = inst.transactionHash;
|
||||
console.log(`executed submit_observation! txHash: ${txHash}`);
|
||||
|
||||
|
||||
|
||||
console.log("done, exiting success.")
|
||||
}
|
||||
|
||||
try {
|
||||
main()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
export function concatArrays(arrays: Uint8Array[]): Uint8Array {
|
||||
const totalLength = arrays.reduce((accum, x) => accum + x.length, 0);
|
||||
const result = new Uint8Array(totalLength);
|
||||
|
||||
for (let i = 0, offset = 0; i < arrays.length; i++) {
|
||||
result.set(arrays[i], offset);
|
||||
offset += arrays[i].length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
export function encodeUint8(value: number): Uint8Array {
|
||||
if (value >= 2 ** 8 || value < 0) {
|
||||
throw new Error(`Out of bound value in Uint8: ${value}`);
|
||||
}
|
||||
|
||||
return new Uint8Array([value]);
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"type": "cosmos",
|
||||
"value": {
|
||||
"key": "default",
|
||||
"chain-id": "wormchain",
|
||||
"rpc-addr": "http://guardian-validator:26657",
|
||||
"account-prefix": "wormhole",
|
||||
"keyring-backend": "test",
|
||||
"gas-adjustment": 1.2,
|
||||
"gas-prices": "0.01utest",
|
||||
"debug": true,
|
||||
"timeout": "20s",
|
||||
"output-format": "json",
|
||||
"sign-mode": "direct"
|
||||
}
|
||||
}
|
||||
"type": "cosmos",
|
||||
"value": {
|
||||
"key": "default",
|
||||
"chain-id": "wormchain",
|
||||
"rpc-addr": "http://wormchain:26657",
|
||||
"account-prefix": "wormhole",
|
||||
"keyring-backend": "test",
|
||||
"gas-adjustment": 1.2,
|
||||
"gas-prices": "0.01utest",
|
||||
"debug": true,
|
||||
"timeout": "20s",
|
||||
"output-format": "json",
|
||||
"sign-mode": "direct"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue