Reimplement terra bridge in guardian software

Change-Id: Ic57d0ae91355d2415f13657f463e8929212b1c97
This commit is contained in:
Hendrik Hofstadt 2021-07-05 13:17:07 +02:00
parent d9fde6d7cc
commit 0004dd6c2a
17 changed files with 180 additions and 1105 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ node_modules
bin
target
/mutagen.sh
venv

View File

@ -79,7 +79,7 @@ const (
TerraTokenAddress = "terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5"
// Terra bridge contract address
TerraBridgeAddress = "terra174kgn5rtw4kf6f938wm7kwh70h2v4vcfd26jlc"
TerraBridgeAddress = "terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62"
// Terra devnet fee payer mnemonic
TerraFeePayerKey = "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius"

View File

@ -176,7 +176,7 @@ func (e *BridgeWatcher) Run(ctx context.Context) error {
sender := gjson.Get(json, "result.events.from_contract\\.message\\.sender.0")
chainId := gjson.Get(json, "result.events.from_contract\\.message\\.chain_id.0")
nonce := gjson.Get(json, "result.events.from_contract\\.message\\.nonce.0")
sequence := gjson.Get(json, "result.events.from_contract\\.message.sequence.0")
sequence := gjson.Get(json, "result.events.from_contract\\.message\\.sequence.0")
blockTime := gjson.Get(json, "result.events.from_contract\\.message\\.block_time.0")
txHash := gjson.Get(json, "result.events.tx\\.hash.0")

View File

@ -71,7 +71,7 @@ spec:
- --terraChainID
- localterra
- --terraContract
- terra174kgn5rtw4kf6f938wm7kwh70h2v4vcfd26jlc
- terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62
- --terraKey
- /tmp/terra.key
- --agentRPC

View File

@ -7,9 +7,9 @@ ADD contracts /code/contracts
RUN optimize_workspace.sh
# Contract deployment stage
FROM node:14@sha256:04a33dac55af8d3170bffc91ca31fe8000b96ae1bab1a090deb920ca2ca2a38e
FROM python:slim-buster@sha256:ec7a755e6313da2f7db02d8e82f6b0813b176f06c5622174c8ab45feefc8096d
RUN npm update && npm i -g typescript ts-node
RUN apt update && apt install netcat curl jq -y
WORKDIR /app/tools
@ -19,8 +19,6 @@ ADD ./tools /app/tools
RUN chmod +x /app/tools/deploy.sh
RUN npm install
RUN ts-node --version
RUN pip install -r /app/tools/requirements.txt
ENTRYPOINT /app/tools/deploy.sh

View File

@ -1,314 +0,0 @@
from terra_sdk.client.localterra import AsyncLocalTerra
from terra_sdk.core.auth import StdFee
import asyncio
from terra_sdk.core.wasm import (
MsgStoreCode,
MsgInstantiateContract,
MsgExecuteContract,
MsgMigrateContract,
)
from terra_sdk.util.contract import get_code_id, get_contract_address, read_file_as_b64
import os
import base64
import pprint
lt = AsyncLocalTerra(gas_prices={"uusd": "0.15"})
terra = lt
deployer = lt.wallets["test1"]
sequence = asyncio.get_event_loop().run_until_complete(deployer.sequence())
async def sign_and_broadcast(*msgs):
global sequence
try:
tx = await deployer.create_and_sign_tx(
msgs=msgs, fee=StdFee(30000000, "20000000uusd"), sequence=sequence
)
result = await terra.tx.broadcast(tx)
sequence += 1
if result.is_tx_error():
raise Exception(result.raw_log)
return result
except:
sequence = await deployer.sequence()
raise
async def store_contract(contract_name):
parent_dir = os.path.dirname(__file__)
contract_bytes = read_file_as_b64(f"{parent_dir}/artifacts/{contract_name}.wasm")
store_code = MsgStoreCode(deployer.key.acc_address, contract_bytes)
result = await sign_and_broadcast(store_code)
code_id = get_code_id(result)
print(f"Code id for {contract_name} is {code_id}")
return code_id
async def store_contracts():
parent_dir = os.path.dirname(__file__)
contract_names = [
i[:-5] for i in os.listdir(f"{parent_dir}/artifacts") if i.endswith(".wasm")
]
return {
contract_name: await store_contract(contract_name)
for contract_name in contract_names
}
class ContractQuerier:
def __init__(self, address):
self.address = address
def __getattr__(self, item):
async def result_fxn(**kwargs):
kwargs = convert_contracts_to_addr(kwargs)
return await terra.wasm.contract_query(self.address, {item: kwargs})
return result_fxn
class Contract:
@staticmethod
async def create(code_id, migratable=False, **kwargs):
kwargs = convert_contracts_to_addr(kwargs)
instantiate = MsgInstantiateContract(
deployer.key.acc_address, code_id, kwargs, migratable=migratable
)
result = await sign_and_broadcast(instantiate)
return Contract(get_contract_address(result))
def __init__(self, address):
self.address = address
def __getattr__(self, item):
async def result_fxn(coins=None, **kwargs):
kwargs = convert_contracts_to_addr(kwargs)
execute = MsgExecuteContract(
deployer.key.acc_address, self.address, {item: kwargs}, coins=coins
)
return await sign_and_broadcast(execute)
return result_fxn
@property
def query(self):
return ContractQuerier(self.address)
async def migrate(self, new_code_id):
migrate = MsgMigrateContract(
contract=self.address,
migrate_msg={},
new_code_id=new_code_id,
owner=deployer.key.acc_address,
)
return await sign_and_broadcast(migrate)
def convert_contracts_to_addr(obj):
if type(obj) == dict:
return {k: convert_contracts_to_addr(v) for k, v in obj.items()}
if type(obj) in {list, tuple}:
return [convert_contracts_to_addr(i) for i in obj]
if type(obj) == Contract:
return obj.address
return obj
def to_bytes(n, length, byteorder="big"):
return int(n).to_bytes(length, byteorder=byteorder)
def assemble_vaa(emitter_chain, emitter_address, payload):
import time
# version, guardian set index, len signatures
header = to_bytes(1, 1) + to_bytes(0, 4) + to_bytes(0, 1)
# timestamp, nonce, emitter_chain
body = to_bytes(time.time(), 8) + to_bytes(1, 4) + to_bytes(emitter_chain, 2)
# emitter_address, vaa payload
body += emitter_address + payload
return header + body
async def main():
code_ids = await store_contracts()
print(code_ids)
# fake governance contract on solana
GOV_CHAIN = 1
GOV_ADDRESS = b"0" * 32
wormhole = await Contract.create(
code_id=code_ids["wormhole"],
gov_chain=GOV_CHAIN,
gov_address=base64.b64encode(GOV_ADDRESS).decode("utf-8"),
guardian_set_expirity=10 ** 15,
initial_guardian_set={"addresses": [], "expiration_time": 10 ** 15},
migratable=True,
)
# TODO:
# resp = await wormhole.migrate(code_ids["wormhole"])
# for event in resp.logs:
# pprint.pprint(event.events_by_type)
token_bridge = await Contract.create(
code_id=code_ids["token_bridge"],
gov_chain=GOV_CHAIN,
gov_address=base64.b64encode(GOV_ADDRESS).decode("utf-8"),
wormhole_contract=wormhole,
wrapped_asset_code_id=int(code_ids["cw20_wrapped"]),
)
mock_token = await Contract.create(
code_id=code_ids["cw20_base"],
name="MOCK",
symbol="MCK",
decimals=6,
initial_balances=[{"address": deployer.key.acc_address, "amount": "100000000"}],
mint=None,
)
raw_addr = deployer.key.raw_address
recipient = b"\0" * 12 + raw_addr
recipient = base64.b64encode(recipient)
print(
"Balance before initiate transfer",
await mock_token.query.balance(address=deployer.key.acc_address),
)
await mock_token.increase_allowance(spender=token_bridge, amount="1000")
bridge_canonical = bytes.fromhex(
(await wormhole.query.query_address_hex(address=token_bridge))["hex"]
)
# fake a VAA from the gov contract
module = b"token_bridge"
module += b" " * (32 - len(module))
chain = to_bytes(0, 2)
action = to_bytes(0, 1)
# chain_id chain_address (pretend there's a bridge w/ the same address on solana)
payload = to_bytes(3, 2) + bridge_canonical
vaa = assemble_vaa(GOV_CHAIN, GOV_ADDRESS, module + chain + action + payload)
# register the chain
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
resp = await token_bridge.initiate_transfer(
asset=mock_token,
amount="1000",
recipient_chain=3,
recipient=recipient.decode("utf-8"),
nonce=0,
coins={"uluna": "10000"},
)
print(
"Balance after initiate transfer",
await mock_token.query.balance(address=deployer.key.acc_address),
)
logs = resp.logs[0].events_by_type
transfer_data = {
k: v[0] for k, v in logs["from_contract"].items() if k.startswith("message")
}
vaa = assemble_vaa(
transfer_data["message.chain_id"],
bytes.fromhex(transfer_data["message.sender"]),
bytes.fromhex(transfer_data["message.message"]),
)
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
print(
"Balance after complete transfer",
await mock_token.query.balance(address=deployer.key.acc_address),
)
# pretend there exists another bridge contract with the same address but on solana
# fake a VAA from the gov contract
module = b"token_bridge"
module += b" " * (32 - len(module))
chain = to_bytes(0, 2)
action = to_bytes(0, 1)
# chain_id chain_address (pretend there's a bridge w/ the same address on solana)
payload = to_bytes(1, 2) + bridge_canonical
vaa = assemble_vaa(GOV_CHAIN, GOV_ADDRESS, module + chain + action + payload)
# register the chain
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
resp = await token_bridge.create_asset_meta(
asset_address=mock_token,
nonce=1,
coins={"uluna": "10000"},
)
logs = resp.logs[0].events_by_type
create_meta_data = {
k: v[0] for k, v in logs["from_contract"].items() if k.startswith("message")
}
message_bytes = bytes.fromhex(create_meta_data["message.message"])
# switch the chain of the asset meta to say its from solana
message_bytes = message_bytes[:1] + to_bytes(1, 2) + message_bytes[3:]
vaa = assemble_vaa(
1, # totally came from solana
bytes.fromhex(create_meta_data["message.sender"]),
message_bytes,
)
# attest this metadata and make a wrapped asset from solana
resp = await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
wrapped_token = Contract(get_contract_address(resp))
# now send from solana...
message_bytes = bytes.fromhex(transfer_data["message.message"])
message_bytes = message_bytes[:1] + to_bytes(1, 2) + message_bytes[3:]
vaa = assemble_vaa(
1, # totally came from solana
bytes.fromhex(transfer_data["message.sender"]),
message_bytes,
)
print(
"Balance before completing transfer from solana",
await wrapped_token.query.balance(address=deployer.key.acc_address),
)
await token_bridge.submit_vaa(data=base64.b64encode(vaa).decode("utf-8"))
print(
"Balance after completing transfer from solana",
await wrapped_token.query.balance(address=deployer.key.acc_address),
)
await wrapped_token.increase_allowance(spender=token_bridge, amount="1000")
resp = await token_bridge.initiate_transfer(
asset=wrapped_token,
amount="1000",
recipient_chain=1,
recipient=recipient.decode("utf-8"),
nonce=0,
coins={"uluna": "10000"},
)
print(
"Balance after completing transfer to solana",
await wrapped_token.query.balance(address=deployer.key.acc_address),
)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())

160
terra/tools/deploy.py Normal file
View File

@ -0,0 +1,160 @@
from terra_sdk.client.localterra import AsyncLocalTerra
from terra_sdk.core.auth import StdFee
import asyncio
from terra_sdk.core.wasm import (
MsgStoreCode,
MsgInstantiateContract,
MsgExecuteContract,
MsgMigrateContract,
)
from terra_sdk.util.contract import get_code_id, get_contract_address, read_file_as_b64
import os
import base64
import pprint
lt = AsyncLocalTerra(gas_prices={"uusd": "0.15"}, url="http://terra-lcd:1317")
terra = lt
deployer = lt.wallets["test1"]
sequence = asyncio.get_event_loop().run_until_complete(deployer.sequence())
async def sign_and_broadcast(*msgs):
global sequence
try:
tx = await deployer.create_and_sign_tx(
msgs=msgs, fee=StdFee(30000000, "20000000uusd"), sequence=sequence
)
result = await terra.tx.broadcast(tx)
sequence += 1
if result.is_tx_error():
raise Exception(result.raw_log)
return result
except:
sequence = await deployer.sequence()
raise
async def store_contract(contract_name):
parent_dir = os.path.dirname(__file__)
contract_bytes = read_file_as_b64(f"{parent_dir}/../artifacts/{contract_name}.wasm")
store_code = MsgStoreCode(deployer.key.acc_address, contract_bytes)
result = await sign_and_broadcast(store_code)
code_id = get_code_id(result)
print(f"Code id for {contract_name} is {code_id}")
return code_id
async def store_contracts():
parent_dir = os.path.dirname(__file__)
contract_names = [
i[:-5] for i in os.listdir(f"{parent_dir}/../artifacts") if i.endswith(".wasm")
]
return {
contract_name: await store_contract(contract_name)
for contract_name in contract_names
}
class ContractQuerier:
def __init__(self, address):
self.address = address
def __getattr__(self, item):
async def result_fxn(**kwargs):
kwargs = convert_contracts_to_addr(kwargs)
return await terra.wasm.contract_query(self.address, {item: kwargs})
return result_fxn
class Contract:
@staticmethod
async def create(code_id, migratable=False, **kwargs):
kwargs = convert_contracts_to_addr(kwargs)
instantiate = MsgInstantiateContract(
deployer.key.acc_address, code_id, kwargs, migratable=migratable
)
result = await sign_and_broadcast(instantiate)
return Contract(get_contract_address(result))
def __init__(self, address):
self.address = address
def __getattr__(self, item):
async def result_fxn(coins=None, **kwargs):
kwargs = convert_contracts_to_addr(kwargs)
execute = MsgExecuteContract(
deployer.key.acc_address, self.address, {item: kwargs}, coins=coins
)
return await sign_and_broadcast(execute)
return result_fxn
@property
def query(self):
return ContractQuerier(self.address)
async def migrate(self, new_code_id):
migrate = MsgMigrateContract(
contract=self.address,
migrate_msg={},
new_code_id=new_code_id,
owner=deployer.key.acc_address,
)
return await sign_and_broadcast(migrate)
def convert_contracts_to_addr(obj):
if type(obj) == dict:
return {k: convert_contracts_to_addr(v) for k, v in obj.items()}
if type(obj) in {list, tuple}:
return [convert_contracts_to_addr(i) for i in obj]
if type(obj) == Contract:
return obj.address
return obj
def to_bytes(n, length, byteorder="big"):
return int(n).to_bytes(length, byteorder=byteorder)
def assemble_vaa(emitter_chain, emitter_address, payload):
import time
# version, guardian set index, len signatures
header = to_bytes(1, 1) + to_bytes(0, 4) + to_bytes(0, 1)
# timestamp, nonce, emitter_chain
body = to_bytes(time.time(), 8) + to_bytes(1, 4) + to_bytes(emitter_chain, 2)
# emitter_address, vaa payload
body += emitter_address + payload
return header + body
async def main():
code_ids = await store_contracts()
print(code_ids)
# fake governance contract on solana
GOV_CHAIN = 1
GOV_ADDRESS = b"0" * 32
wormhole = await Contract.create(
code_id=code_ids["wormhole"],
gov_chain=GOV_CHAIN,
gov_address=base64.b64encode(GOV_ADDRESS).decode("utf-8"),
guardian_set_expirity=10 ** 15,
initial_guardian_set={
"addresses": [{"bytes": base64.b64encode(
bytearray.fromhex("beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe")).decode("utf-8")}],
"expiration_time": 0},
migratable=True,
)
print("Wormhole contract: {}".format(wormhole.address))
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())

View File

@ -1,5 +1,14 @@
npm run prepare-token http://terra-lcd:1317
npm run prepare-wormhole http://terra-lcd:1317
npm run lock-token terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 terra174kgn5rtw4kf6f938wm7kwh70h2v4vcfd26jlc 1000 http://terra-lcd:1317
# Wait for node to start
while ! /bin/netcat -z localhost 26657; do
sleep 1
done
# Wait for first block
while [ $(curl localhost:26657/status -ks | jq ".result.sync_info.latest_block_height|tonumber") -lt 1 ]; do
sleep 1
done
sleep 2
python deploy.py
echo "Going to sleep, interrupt if running manually"
sleep infinity

View File

@ -1,26 +0,0 @@
import { init_lcd, execute_contract, execute_contract_with_fee, query_contract } from './utils';
async function script() {
if (process.argv.length < 5) {
console.log('Required 3 params TOKEN_CONTRACT, WORMHOLE_CONTRACT, integer AMOUNT');
}
let token_contract = process.argv[2];
let wormhole_contract = process.argv[3];
let amount = process.argv[4];
let allowanceResult = await execute_contract(token_contract, {increase_allowance: {spender: wormhole_contract, amount}});
if (allowanceResult == null) return;
console.log('Allowance increased');
let lockResult = await execute_contract_with_fee(wormhole_contract, {lock_assets: {
asset: token_contract,
amount,
recipient: Buffer.from('00000000000000000000000019a4437E2BA06bF1FA42C56Fb269Ca0d30f60716', 'hex').toString('base64'),
target_chain: 2, // Ethereum
nonce: Date.now() % 1000000
}});
if (lockResult == null) return;
console.log('Tokens locked');
}
init_lcd(process.argv[5]);
script();

View File

@ -1,494 +0,0 @@
{
"name": "terra-contract-tools",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@terra-money/terra.js": {
"version": "0.5.12",
"resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-0.5.12.tgz",
"integrity": "sha512-3UZWMT3Tu+MOQrHZ8uEtHL+hurKbe1QVm8x+qWOe4+IOeY3eWdVeBIkHflhGI8NU31v/r5eznbTuy7kEMA4CMQ==",
"requires": {
"axios": "^0.20.0",
"bech32": "^1.1.4",
"bip32": "^2.0.6",
"bip39": "^3.0.2",
"bufferutil": "^4.0.1",
"crypto-js": "3.3.0",
"decimal.js": "^10.2.1",
"post-message-stream": "^3.0.0",
"secp256k1": "^4.0.2",
"utf-8-validate": "^5.0.2",
"ws": "^7.3.1"
}
},
"@types/node": {
"version": "14.14.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz",
"integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw=="
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
},
"axios": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"base-x": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz",
"integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"bech32": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bip32": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz",
"integrity": "sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA==",
"requires": {
"@types/node": "10.12.18",
"bs58check": "^2.1.1",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"tiny-secp256k1": "^1.1.3",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
},
"dependencies": {
"@types/node": {
"version": "10.12.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ=="
}
}
},
"bip39": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
"integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
"requires": {
"@types/node": "11.11.6",
"create-hash": "^1.1.0",
"pbkdf2": "^3.0.9",
"randombytes": "^2.0.1"
},
"dependencies": {
"@types/node": {
"version": "11.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
"integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
}
}
},
"bn.js": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw=="
},
"brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "^3.0.2"
}
},
"bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"requires": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"bufferutil": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz",
"integrity": "sha512-AtnG3W6M8B2n4xDQ5R+70EXvOpnXsFYg/AK2yTZd+HQ/oxAdz+GI+DvjmhBw3L0ole+LJ0ngqY4JMbDzkfNzhA==",
"requires": {
"node-gyp-build": "^4.2.0"
}
},
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
"md5.js": "^1.3.4",
"ripemd160": "^2.0.1",
"sha.js": "^2.4.0"
}
},
"create-hmac": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
"inherits": "^2.0.1",
"ripemd160": "^2.0.0",
"safe-buffer": "^5.0.1",
"sha.js": "^2.4.8"
}
},
"crypto-js": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz",
"integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q=="
},
"decimal.js": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz",
"integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw=="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
},
"elliptic": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
},
"hash-base": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
"safe-buffer": "^5.2.0"
}
},
"hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
}
},
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
"safe-buffer": "^5.1.2"
}
},
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
},
"nan": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
},
"node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node-gyp-build": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
},
"pbkdf2": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
"ripemd160": "^2.0.1",
"safe-buffer": "^5.0.1",
"sha.js": "^2.4.8"
}
},
"post-message-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/post-message-stream/-/post-message-stream-3.0.0.tgz",
"integrity": "sha1-kNn1S9IJ5rb110eVuHWIIFtUcEg=",
"requires": {
"readable-stream": "^2.1.4"
},
"dependencies": {
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"requires": {
"safe-buffer": "^5.1.0"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"ripemd160": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"secp256k1": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
"requires": {
"elliptic": "^6.5.2",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
},
"sha.js": {
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"tiny-secp256k1": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.5.tgz",
"integrity": "sha512-duE2hSLSQIpHGzmK48OgRrGTi+4OTkXLC6aa86uOYQ6LLCYZSarVKIAvEtY7MoXjoL6bOXMSerEGMzrvW4SkDw==",
"requires": {
"bindings": "^1.3.0",
"bn.js": "^4.11.8",
"create-hmac": "^1.1.7",
"elliptic": "^6.4.0",
"nan": "^2.13.2"
}
},
"ts-node": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
"integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==",
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"typescript": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
"integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ=="
},
"utf-8-validate": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz",
"integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==",
"requires": {
"node-gyp-build": "^4.2.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
"requires": {
"bs58check": "<3.0.0"
}
},
"ws": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
}
}
}

View File

@ -1,22 +0,0 @@
{
"name": "terra-contract-tools",
"version": "1.0.0",
"description": "Tools to build and deploy Terra contracts",
"repository": "https://github.com/certusone/wormhole",
"main": "index.js",
"scripts": {
"build-contracts": "( cd .. && docker run --rm -v \"$(pwd)\":/code --mount type=volume,source=\"$(basename \"$(pwd)\")_cache\",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/workspace-optimizer:0.10.4 )",
"prepare-token": "ts-node prepare-token.ts",
"prepare-wormhole": "ts-node prepare-wormhole.ts",
"lock-token": "ts-node lock-token.ts",
"submit-vaa": "ts-node submit-vaa.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"@terra-money/terra.js": "^0.5.12",
"@types/node": "^14.14.6",
"ts-node": "^9.0.0",
"typescript": "^4.1.2"
}
}

View File

@ -1,28 +0,0 @@
import { init_lcd, deploy_contract, instantiate_contract, query_contract } from './utils';
async function script() {
const TEST_ADDRESS: string = 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v';
// cw20_base.wasm is a binary artifact built from https://github.com/CosmWasm/cosmwasm-plus repository at v0.2.0
// and is a standard base cw20 contract. Is it used for testing only.
let code_id = await deploy_contract('../artifacts/cw20_base.wasm');
if (code_id == -1) return;
console.log(`Program deployed with code id ${code_id}`);
let contract_address = await instantiate_contract(code_id, {
name: 'Test token',
symbol: 'TST',
decimals: 8,
initial_balances: [{
address: TEST_ADDRESS,
amount: '100000000000000',
}],
mint: null,
});
console.log(`Contract instance created at ${contract_address}`);
// Verify if token was minted to the test address
let result = await query_contract(contract_address, {balance: { address : TEST_ADDRESS}});
console.log(`${TEST_ADDRESS} balance is ${result.balance}`);
}
init_lcd(process.argv[2]);
script();

View File

@ -1,27 +0,0 @@
import { init_lcd, deploy_contract, instantiate_contract, query_contract } from './utils';
async function script() {
// Deploy cw20-wrapped
let wrapped_code_id = await deploy_contract('../artifacts/cw20_wrapped.wasm');
if (wrapped_code_id == -1) return;
console.log(`CW20 Wrapped program deployed with code id ${wrapped_code_id}`);
// Deploy wormhole
let wormhole_code_id = await deploy_contract('../artifacts/wormhole.wasm');
if (wormhole_code_id == -1) return;
console.log(`Wormhole program deployed with code id ${wormhole_code_id}`);
// Instantiate wormhole
let contract_address = await instantiate_contract(wormhole_code_id, {
initial_guardian_set: {
addresses: [
{ bytes: Buffer.from('beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe', 'hex').toString('base64') }
],
expiration_time: Math.floor(Date.now() / 1000) + 1000 * 60 * 60
},
guardian_set_expirity: 0,
wrapped_asset_code_id: wrapped_code_id,
});
console.log(`Wormhole instance created at ${contract_address}`);
}
init_lcd(process.argv[2]);
script();

View File

@ -0,0 +1 @@
terra_sdk==0.14.0

View File

@ -1,18 +0,0 @@
import { init_lcd, execute_contract } from './utils';
async function script() {
if (process.argv.length < 3) {
console.log('Required 1 param WORMHOLE_CONTRACT');
}
let wormhole_contract = process.argv[2];
// Test VAA built using bridge/cmd/vaa-test
let vaaResult = await execute_contract(wormhole_contract, {submit_v_a_a: {
vaa: Buffer.from('010000000001001063f503dd308134e0f158537f54c5799719f4fa2687dd276c72ef60ae0c82c47d4fb560545afaabdf60c15918e221763fd1892c75f2098c0ffd5db4af254a4501000007d01000000038010302010400000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988080000000000000000000000000000000000000000000000000de0b6b3a7640000', 'hex').toString('base64')
}});
if (vaaResult == null) return;
console.log('Vaa submitted');
}
init_lcd(process.argv[3]);
script();

View File

@ -1,11 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es2017",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2017"]
}

View File

@ -1,154 +0,0 @@
import { LCDClient, MsgStoreCode, MsgInstantiateContract, MsgExecuteContract, MnemonicKey, isTxError } from '@terra-money/terra.js';
import * as fs from 'fs';
// test1 key from localterra accounts
const mk = new MnemonicKey({
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'
})
let terra: LCDClient;
let wallet;
export function init_lcd(host_name='http://localhost:1317') {
// connect to localterra
terra = new LCDClient({
URL: host_name,
chainID: 'localterra'
});
wallet = terra.wallet(mk);
}
function delay(ms: number) {
return new Promise( resolve => setTimeout(resolve, ms) );
}
export async function deploy_contract(wasm_file) : Promise<number> {
const storeCode = new MsgStoreCode(
wallet.key.accAddress,
fs.readFileSync(wasm_file).toString('base64')
);
let first_attempt = true;
for (;;) {
try {
const storeCodeTx = await wallet.createAndSignTx({
msgs: [storeCode],
});
const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx);
//console.log(storeCodeTxResult);
if (isTxError(storeCodeTxResult)) {
throw new Error(
`store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`
);
}
const {
store_code: { code_id },
} = storeCodeTxResult.logs[0].eventsByType;
return parseInt(code_id[0], 10);
} catch (err) {
// Only show error from the second time it shows to avoid spamming errors while initialization not yet finished
if (!first_attempt) {
console.log(`Error ${err}`);
if (err.response) {
console.log(err.response.data);
}
}
first_attempt = false;
await delay(5000);
}
}
}
export async function instantiate_contract(code_id: number, initMsg: object) : Promise<string> {
try {
const instantiate = new MsgInstantiateContract(
wallet.key.accAddress,
code_id,
initMsg,
{},
false
);
const instantiateTx = await wallet.createAndSignTx({
msgs: [instantiate],
});
const instantiateTxResult = await terra.tx.broadcast(instantiateTx);
if (isTxError(instantiateTxResult)) {
throw new Error(
`instantiate failed. code: ${instantiateTxResult.code}, codespace: ${instantiateTxResult.codespace}, raw_log: ${instantiateTxResult.raw_log}`
);
return null;
}
const {
instantiate_contract: { contract_address },
} = instantiateTxResult.logs[0].eventsByType;
return contract_address[0];
} catch (err) {
console.log(`Error ${err}`);
if (err.response) {
console.log(err.response.data);
}
return null;
}
}
export async function execute_contract(contract_address: string, msg: object) : Promise<any> {
try {
const execute = new MsgExecuteContract(
wallet.key.accAddress,
contract_address,
{ ...msg }, { }
);
const executeTx = await wallet.createAndSignTx({
msgs: [execute]
});
const result = await terra.tx.broadcast(executeTx);
return result;
} catch (err) {
console.log(`Error ${err}`);
if (err.response) {
console.log(err.response.data);
}
return null;
}
}
export async function execute_contract_with_fee(contract_address: string, msg: object) : Promise<any> {
try {
const execute = new MsgExecuteContract(
wallet.key.accAddress,
contract_address,
{ ...msg }, { uluna: 10000 }
);
const executeTx = await wallet.createAndSignTx({
msgs: [execute]
});
const result = await terra.tx.broadcast(executeTx);
return result;
} catch (err) {
console.log(`Error ${err}`);
if (err.response) {
console.log(err.response.data);
}
return null;
}
}
export async function query_contract(contract_address: string, query: object) : Promise<any> {
const result = await terra.wasm.contractQuery(
contract_address, query
);
return result;
}