Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,10 @@ jobs:
protoc --version
- name: Install wasm-opt
run: cargo install wasm-opt --locked
- name: Install cosmwasm-check
run: cargo install cosmwasm-check --locked
- name: WASM release build
run: RUSTFLAGS="-C link-arg=-s" cargo wasm --locked
- name: Optimize WASM artifacts
run: |
mkdir artifacts
for f in target/wasm32-unknown-unknown/release/*.wasm; do
wasm-opt -Os "$f" -o "artifacts/$(basename "$f")"
done
run: make build-opt
- name: Generate checksums
run: |
cd artifacts
Expand Down Expand Up @@ -108,12 +104,48 @@ jobs:
sudo apt-get install -y protobuf-compiler
protoc --version
- name: Install cargo-tarpaulin
run: cargo +1.82.0 install cargo-tarpaulin
run: cargo +1.90.0 install cargo-tarpaulin
- name: Run coverage
run: cargo +1.82.0 tarpaulin --workspace --all-features --all-targets --locked --out Xml --output-dir coverage
run: cargo +1.90.0 tarpaulin --workspace --all-features --all-targets --locked --out Xml --output-dir coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage/cobertura.xml
fail_ci_if_error: true

e2e:
name: E2E
runs-on: ubuntu-latest
needs: fmt_lint
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Compose
uses: docker/setup-buildx-action@v2
- name: Install test deps
run: |
sudo apt-get update
sudo apt-get install -y bats jq
bats --version
jq --version
- name: Install toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_VERSION }}
targets: wasm32-unknown-unknown
- name: Install protoc
run: |
sudo apt-get update
sudo apt-get install -y protobuf-compiler
protoc --version
- name: Install wasm-opt
run: cargo install wasm-opt --locked
- name: Install cosmwasm-check
run: cargo install cosmwasm-check --locked
- name: E2E test
run: bats e2e/tests/converter.bats
- name: Cleanup
if: always()
run: docker compose -f e2e/docker-compose.yml down -v
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
.idea/
artifacts/
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "e2e/test_helper/bats-support"]
path = e2e/test_helper/bats-support
url = https://github.com/bats-core/bats-support
[submodule "e2e/test_helper/bats-assert"]
path = e2e/test_helper/bats-assert
url = https://github.com/bats-core/bats-assert
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ resolver = "2"

[workspace.package]
version = "0.1.0"
rust-version = "1.86.0"

[workspace.dependencies]
bech32 = "0.11"
Expand Down
48 changes: 48 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
MAKEFLAGS += --no-print-directory

e2e-chain-up:
@echo "--> Starting e2e test blockchain environment"
@docker compose -f e2e/docker-compose.yml up -d --wait

e2e-chain-down:
@echo "--> Stopping e2e test blockchain environment"
@docker compose -f e2e/docker-compose.yml down -v

.PHONY: e2e-chain-up e2e-chain-down

#### Build ####

build:
@echo "--> Building contracts"
@cargo wasm

build-opt:
@echo "--> Checking for protoc installation"
@$(MAKE) check-protoc
@echo "--> Checking for wasm-opt installation"
@$(MAKE) check-wasm-opt
@echo "--> Checking for cosmwasm-check installation"
@$(MAKE) check-cosmwasm-check
@echo "--> Building optimized contracts"
@RUSTFLAGS="-C link-arg=-s" cargo wasm --locked
@echo "--> Optimizing wasm binaries"
@mkdir -p ./artifacts/
@for f in target/wasm32-unknown-unknown/release/*.wasm; do wasm-opt -Os "$$f" -o "artifacts/$$(basename "$$f")"; done
@echo "--> Optimized wasm binaries are in the ./artifacts/ directory"
@echo "--> Running cosmwasm-check on optimized binaries"
@for f in artifacts/*.wasm; do cosmwasm-check "$$f"; done

clean:
@echo "--> Cleaning build artifacts"
@cargo clean

check-protoc:
@command -v protoc >/dev/null 2>&1 || { echo "protoc not found; install with: sudo apt install protobuf-compiler (or your distro's package)"; exit 1; }

check-wasm-opt:
@command -v wasm-opt >/dev/null 2>&1 || { echo "wasm-opt not found; install with: sudo apt install binaryen (or your distro's package)"; exit 1; }

check-cosmwasm-check:
@command -v cosmwasm-check >/dev/null 2>&1 || { echo "cosmwasm-check not found; install with: cargo install cosmwasm-check"; exit 1; }

.PHONY: build clean build-opt check-protoc check-wasm-opt check-cosmwasm-check
4 changes: 3 additions & 1 deletion contracts/converter/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ pub enum QueryMsg {
}

#[cw_serde]
pub enum MigrateMsg {}
pub enum MigrateMsg {
Migrate {},
}

// TODO: Write a macro to generate this struct from the Config struct
#[cw_serde]
Expand Down
35 changes: 35 additions & 0 deletions e2e/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
KEY="user1"
KEY2="user2"
ADDR1="manifest1hj5fveer5cjtn4wd6wstzugjfdxzl0xp8ws9ct"
ADDR2="manifest1efd63aw40lxf3n4mhf7dzhjkr453axurm6rp3z"
VESTING_ADDR="manifest1yyuzq9665yjmmhnmfn7zsajnyz9lcdelggf6ke"
CHAIN_ID="test-1"
MONIKER="zebradonkey"
KEYRING="test"
HOME_DIR="/persistent/.manifest"
BINARY="/usr/bin/manifestd"
MNEMO1="decorate bright ozone fork gallery riot bus exhaust worth way bone indoor calm squirrel merry zero scheme cotton until shop any excess stage laundry"
MNEMO2="wealth flavor believe regret funny network recall kiss grape useless pepper cram hint member few certain unveil rather brick bargain curious require crowd raise"
BANK_ADDR=manifest1hj5fveer5cjtn4wd6wstzugjfdxzl0xp8ws9ct
GAS_STATION_ADDR=manifest1efd63aw40lxf3n4mhf7dzhjkr453axurm6rp3z
RPC="26657"
REST="1317"
PROFF="6060"
P2P="26656"
GRPC="9090"
GRPC_WEB="9091"
ROSETTA="8080"
TIMEOUT_COMMIT="3s"
VOTING_TIMEOUT="10s"
DENOM=umfx
BOND_DENOM=upoa
POA_ADMIN_ADDRESS="manifest1hj5fveer5cjtn4wd6wstzugjfdxzl0xp8ws9ct"
USER_GROUP_ADDRESS="manifest1dlszg2sst9r69my4f84l3mj66zxcf3umcgujys30t84srg95dgvsmxrlcr"
COMMON_MANIFESTD_ARGS="--gas-prices 0.0011${DENOM} --gas-adjustment 1.8 --gas auto --home ${HOME_DIR} --keyring-backend $KEYRING --chain-id $CHAIN_ID --yes --node http://manifest-ledger:$RPC"
GROUP_MEMBERS={"members":[{"address":"${ADDR1}","weight":"1","metadata":"user1"},{"address":"${ADDR2}","weight":"1","metadata":"user2"}]}
DECISION_POLICY={"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period":"10s","min_execution_period":"0s"}}
TX_COUNT_DIR=/tx-count
TX_COUNT_FILE=tx-count.txt
TX_COUNT_PATH="${TX_COUNT_DIR}/${TX_COUNT_FILE}"
POSTGREST_HOST=postgrest
CONVERT_WASM_ADDRESS="manifest14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4zfs7u"
23 changes: 23 additions & 0 deletions e2e/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
services:
manifest-ledger:
image: ghcr.io/manifest-network/manifest-ledger:1.0.11
volumes:
- manifest-ledger-bin:/usr/bin
- manifest-ledger-data:/persistent
- ./scripts/init_manifest_ledger.sh:/usr/local/bin/init_manifest_ledger.sh:ro
- ../:/workspace:ro
ports:
- "9090:9090"
- "26657:26657"
entrypoint: ["/bin/bash", "-c"]
env_file: ./.env
command: /usr/local/bin/init_manifest_ledger.sh
healthcheck:
test: manifestd status | grep '"earliest_block_height":"1"'
interval: 10s
timeout: 5s
retries: 5

volumes:
manifest-ledger-bin:
manifest-ledger-data:
49 changes: 49 additions & 0 deletions e2e/scripts/init_manifest_ledger.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# This script initializes the manifest ledger genesis file and starts a ledger node

set -e

update_test_genesis () {
cat $HOME_DIR/config/genesis.json | jq "$1" > $HOME_DIR/config/tmp_genesis.json && mv $HOME_DIR/config/tmp_genesis.json $HOME_DIR/config/genesis.json
}

echo "$MNEMO1" | $BINARY keys add "$KEY" --home="$HOME_DIR" --keyring-backend "$KEYRING" --recover
echo "$MNEMO2" | $BINARY keys add "$KEY2" --home="$HOME_DIR" --keyring-backend "$KEYRING" --recover
$BINARY init $MONIKER --home=$HOME_DIR --chain-id $CHAIN_ID
update_test_genesis '.consensus["params"]["block"]["max_gas"]="1000000000"'
update_test_genesis '.app_state["bank"]["denom_metadata"]=[{"base":"umfx","denom_units":[{"aliases":[],"denom":"umfx","exponent":0},{"aliases":[],"denom":"MFX","exponent":6}],"description":"MFX","display":"MFX","name":"MFX","symbol":"MFX","uri":"","uri_hash":""}]'
update_test_genesis '.app_state["gov"]["params"]["min_deposit"]=[{"denom":"'$DENOM'","amount":"1000000"}]'
update_test_genesis '.app_state["gov"]["params"]["voting_period"]="15s"'
update_test_genesis '.app_state["gov"]["params"]["expedited_voting_period"]="10s"'
update_test_genesis '.app_state["staking"]["params"]["bond_denom"]="'${BOND_DENOM}'"'
update_test_genesis '.app_state["staking"]["params"]["min_commission_rate"]="0.000000000000000000"'
update_test_genesis '.app_state["mint"]["params"]["mint_denom"]="'$DENOM'"'
update_test_genesis '.app_state["mint"]["params"]["blocks_per_year"]="6311520"'
update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_fee"]=[]'
update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_gas_consume"]=0'
update_test_genesis '.app_state["feegrant"]["allowances"]=[{"granter":"'${GAS_STATION_ADDR}'","grantee":"'${BANK_ADDR}'","allowance":{"@type":"/cosmos.feegrant.v1beta1.AllowedMsgAllowance","allowance":{"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spend_limit":[],"expiration":null},"allowed_messages":["/cosmos.bank.v1beta1.MsgSend"]}}]'
update_test_genesis '.app_state["group"]["group_seq"]="1"'
update_test_genesis '.app_state["group"]["groups"]=[{"id":"1","admin":"'${POA_ADMIN_ADDRESS}'","metadata":"AQ==","version":"2","total_weight":"2","created_at":"2024-05-16T15:10:54.372190727Z"}]'
update_test_genesis '.app_state["group"]["group_members"]=[{"group_id":"1","member":{"address":"'${ADDR1}'","weight":"1","metadata":"user1","added_at":"2024-05-16T15:10:54.372190727Z"}},{"group_id":"1","member":{"address":"'${ADDR2}'","weight":"1","metadata":"user2","added_at":"2024-05-16T15:10:54.372190727Z"}}]'
update_test_genesis '.app_state["group"]["group_policy_seq"]="1"'
update_test_genesis '.app_state["group"]["group_policies"]=[{"address":"'${POA_ADMIN_ADDRESS}'","group_id":"1","admin":"'${POA_ADMIN_ADDRESS}'","metadata":"AQ==","version":"2","decision_policy":{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period":"'${VOTING_TIMEOUT}'","min_execution_period":"0s"}},"created_at":"2024-05-16T15:10:54.372190727Z"}]'
update_test_genesis '.app_state["tokenfactory"]["factory_denoms"]=[{"denom":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","authority_metadata":{"admin":"manifest1hj5fveer5cjtn4wd6wstzugjfdxzl0xp8ws9ct"}}]'
update_test_genesis '.app_state["bank"]["denom_metadata"] |= . + [{"description":"PWR","denom_units":[{"denom":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","exponent":0,"aliases":["PWR"]},{"denom":"PWR","exponent":6,"aliases":["factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr"]}],"base":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","display":"PWR","name":"POWER","symbol":"PWR","uri":"","uri_hash":""}]'
update_test_genesis '.app_state["wasm"]["params"]["code_upload_access"]["permission"]="Everybody"'
update_test_genesis '.app_state["wasm"]["params"]["instantiate_default_permission"]="Everybody"'
$BINARY genesis add-genesis-account $KEY 100000000000000000${BOND_DENOM},100000000000000000000000000000${DENOM} --keyring-backend $KEYRING --home=$HOME_DIR
$BINARY genesis add-genesis-account $KEY2 100000000000000000${DENOM} --keyring-backend $KEYRING --home=$HOME_DIR
$BINARY genesis gentx $KEY 1000000${BOND_DENOM} --keyring-backend $KEYRING --home=$HOME_DIR --chain-id $CHAIN_ID --commission-rate=0.0 --commission-max-rate=1.0 --commission-max-change-rate=0.1
$BINARY genesis collect-gentxs --home=$HOME_DIR
$BINARY genesis validate-genesis --home=$HOME_DIR
sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:'$RPC'"/g' $HOME_DIR/config/config.toml
sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = \["\*"\]/g' $HOME_DIR/config/config.toml
sed -i 's/address = "tcp:\/\/localhost:1317"/address = "tcp:\/\/0.0.0.0:'$REST'"/g' $HOME_DIR/config/app.toml
sed -i 's/enable = false/enable = true/g' $HOME_DIR/config/app.toml
sed -i 's/pprof_laddr = "localhost:6060"/pprof_laddr = "localhost:'$PROFF'"/g' $HOME_DIR/config/config.toml
sed -i 's/laddr = "tcp:\/\/0.0.0.0:26656"/laddr = "tcp:\/\/0.0.0.0:'$P2P'"/g' $HOME_DIR/config/config.toml
sed -i 's/address = "localhost:9090"/address = "0.0.0.0:'$GRPC'"/g' $HOME_DIR/config/app.toml
sed -i 's/address = "localhost:9091"/address = "0.0.0.0:'$GRPC_WEB'"/g' $HOME_DIR/config/app.toml
sed -i 's/address = ":8080"/address = "0.0.0.0:'$ROSETTA'"/g' $HOME_DIR/config/app.toml
sed -i 's/timeout_commit = "5s"/timeout_commit = "'$TIMEOUT_COMMIT'"/g' $HOME_DIR/config/config.toml
POA_ADMIN_ADDRESS=${POA_ADMIN_ADDRESS} $BINARY start --home=${HOME_DIR} --pruning=nothing --minimum-gas-prices=0.0011${DENOM} --rpc.laddr="tcp://0.0.0.0:$RPC"
1 change: 1 addition & 0 deletions e2e/test_helper/bats-assert
Submodule bats-assert added at f1e928
1 change: 1 addition & 0 deletions e2e/test_helper/bats-support
Submodule bats-support added at 004e70
87 changes: 87 additions & 0 deletions e2e/test_helper/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env bash

run_tx() {
local desc=$1
shift
echo "# --> $desc" >&3
run docker exec "$CONTAINER_NAME" manifestd tx "$@" \
--home "/persistent/.manifest" \
--keyring-backend "test" \
--gas auto \
--gas-adjustment 1.8 \
--gas-prices "$GAS_PRICES" \
--chain-id "$CHAIN_ID" \
--node "$RPC" \
--yes \
--output json

assert_success
local json_output=$(echo "$output" | tail -n +3)
TX_HASH=$(echo "$json_output" | jq -r '.txhash')
ERR_CODE=$(echo "$json_output" | jq -r '.code')
assert [ -n "$TX_HASH" ]
assert [ "$ERR_CODE" -eq 0 ]
echo "# --> Transaction submitted with hash: $TX_HASH" >&3
sleep 3

run docker exec "$CONTAINER_NAME" manifestd query tx "$TX_HASH" \
--node "$RPC" \
--output json
assert_success
ERR_CODE=$(echo "$output" | tail -n +2 | jq -r '.code')
if [ "$ERR_CODE" != "0" ]; then
echo "# ⚠️ Tx returned error code $ERR_CODE" >&3
echo "$output" >&3
fi
}

query_json() {
local desc=$1
shift
echo "# --> $desc" >&3
run docker exec "$CONTAINER_NAME" manifestd query "$@" \
--node "$RPC" --output json
assert_success
echo "$output" | tail -n +2
}

store_contract() {
run_tx "Storing contract on-chain" wasm store "/workspace/$WASM_FILE" --from "$USER_ADDR"
CODE_ID=$(docker exec "$CONTAINER_NAME" manifestd query tx "$TX_HASH" --node "$RPC" --output json | \
jq -r '.events[] | select(.type=="store_code") | .attributes[] | select(.key=="code_id") | .value')
assert [ "$CODE_ID" -gt 0 ]
echo "# --> Contract uploaded with code ID: $CODE_ID" >&3
}

instantiate_contract() {
local init_msg=$1
run_tx "Instantiating contract" wasm instantiate "$CODE_ID" "$init_msg" \
--from "$USER_ADDR" --label "converter-test" --admin "$USER_ADDR"
CONTRACT_ADDR=$(docker exec "$CONTAINER_NAME" manifestd query tx "$TX_HASH" --node "$RPC" --output json | \
jq -r '.events[] | select(.type=="wasm") | .attributes[] | select(.key=="_contract_address") | .value')
assert [ -n "$CONTRACT_ADDR" ]
echo "# --> Contract instantiated at: $CONTRACT_ADDR" >&3
}

grant_authz() {
local msg_type=$1
run_tx "Granting authz for $msg_type" authz grant "$CONTRACT_ADDR" generic \
--msg-type "$msg_type" --from "$USER_ADDR"
}

execute_contract() {
local msg=$1
local from=$2
local amount=${3:-} # optional third argument

echo "# --> Executing contract message" >&3

if [ -n "$amount" ]; then
run_tx "Executing contract (with funds)" wasm execute "$CONTRACT_ADDR" "$msg" \
--from "$from" \
--amount "$amount"
else
run_tx "Executing contract" wasm execute "$CONTRACT_ADDR" "$msg" \
--from "$from"
fi
}
Loading
Loading