From b719deb33c7770292ff08689b3e3958d1507c1c4 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Fri, 4 Apr 2025 16:25:40 +0100 Subject: [PATCH 01/24] chore(orchestration): set xcs multichain environment feat(multichain): open liquidity pool on osmosis chore(multichain): set pool config json via script feat(multichain): add osmosis pool to CI E2E Workflow fix(multichain): fix lint issues fix(multichain): fix multichain workflow Invalid input chore(multichain): change osmosis_pool input type on CI workflow fix(multichain): fix Unable to use a TTY issue fix(multichain): fix timing issue when creating pool fix(multichain): remove kubectl tty flag refactor(multichain): reduce duplicated code squash multiple commits fix(multichain): change agoric-osmosis channel id chore(multichain): create pool by default and update names for clarity fix(multichain): handle inconsistent channel-id chore(multichain): remove temporary pool config file chore(multichain): do not create osmosis pool by default fix(multichain): derive ibc-denom chore: store and instantiate Osmosis XCS contracts Refs: #8863 fix: lint fixes feat(multichain): store osmosis pool on swaprouter --- .github/workflows/multichain-e2e-template.yml | 18 ++ .github/workflows/multichain-e2e.yml | 2 + multichain-testing/.gitignore | 2 + multichain-testing/Makefile | 16 ++ multichain-testing/README.md | 7 + .../scripts/create-osmosis-pool.sh | 192 ++++++++++++++++++ .../scripts/download-wasm-artifacts.sh | 26 +++ multichain-testing/scripts/setup-xcs.sh | 134 ++++++++++++ 8 files changed, 397 insertions(+) create mode 100755 multichain-testing/scripts/create-osmosis-pool.sh create mode 100755 multichain-testing/scripts/download-wasm-artifacts.sh create mode 100755 multichain-testing/scripts/setup-xcs.sh diff --git a/.github/workflows/multichain-e2e-template.yml b/.github/workflows/multichain-e2e-template.yml index 9f57fc69895..d642f8b8a51 100644 --- a/.github/workflows/multichain-e2e-template.yml +++ b/.github/workflows/multichain-e2e-template.yml @@ -14,6 +14,16 @@ on: required: true type: string description: 'Identifier for the test suite that will be used as part of the filename name for logs' + osmosis_pool: + description: 'Condition to open liquidity pool on osmosis' + default: false + required: false + type: boolean + osmosis_xcs: + description: 'Flag to enable Osmosis Crosschain Swaps' + default: false + required: false + type: boolean jobs: multichain-e2e: @@ -114,6 +124,14 @@ jobs: run: make register-bank-assets working-directory: ./agoric-sdk/multichain-testing + - name: Setup Osmosis XCS Contracts + run: make osmosis-xcs-setup + working-directory: ./agoric-sdk/multichain-testing + + - name: Create Osmosis Pool + run: make create-osmosis-pool + working-directory: ./agoric-sdk/multichain-testing + - name: Run @agoric/multichain-testing E2E Tests run: ${{ inputs.test_command }} working-directory: ./agoric-sdk/multichain-testing diff --git a/.github/workflows/multichain-e2e.yml b/.github/workflows/multichain-e2e.yml index 0f2c16d195f..8b0af894285 100644 --- a/.github/workflows/multichain-e2e.yml +++ b/.github/workflows/multichain-e2e.yml @@ -30,6 +30,8 @@ jobs: config: config.yaml test_command: yarn test:main test_suite_name: orchestration-api-hermes + osmosis_pool: true + osmosis_xcs: true fast-usdc-hermes: name: Fast USDC - Hermes diff --git a/multichain-testing/.gitignore b/multichain-testing/.gitignore index 1d6079098c9..908eb1b7c1a 100644 --- a/multichain-testing/.gitignore +++ b/multichain-testing/.gitignore @@ -8,3 +8,5 @@ start* eval-* # ci logs for archive upload logs/ +# osmosis pool configuration +*-pool-config.json diff --git a/multichain-testing/Makefile b/multichain-testing/Makefile index 8c2e3b866d1..403a963a2da 100644 --- a/multichain-testing/Makefile +++ b/multichain-testing/Makefile @@ -93,6 +93,22 @@ provision-smart-wallet: tail-slog: kubectl exec -i agoriclocal-genesis-0 -c validator -- tail -f slog.slog + +############################################################################### +### Osmosis Setup ### +############################################################################### + +create-osmosis-pool: + $(CURDIR)/scripts/create-osmosis-pool.sh + + +############################################################################### +### Osmosis Setup ### +############################################################################### + +osmosis-xcs-setup: + $(CURDIR)/scripts/setup-xcs.sh + ############################################################################### ### Start All ### ############################################################################### diff --git a/multichain-testing/README.md b/multichain-testing/README.md index 572865afe9c..0cda4a349ca 100644 --- a/multichain-testing/README.md +++ b/multichain-testing/README.md @@ -136,6 +136,13 @@ make provision-smart-wallet ADDR=$ADDR kubectl exec -i noblelocal-genesis-0 -c validator -- nobled query interchain-accounts host params | jq ``` +## Optional Features + +```sh +# create and fund a liquidity pool on Osmosis +make create-osmosis-pool +``` + ## Chain Registry These only work if you've done `make port-forward`. diff --git a/multichain-testing/scripts/create-osmosis-pool.sh b/multichain-testing/scripts/create-osmosis-pool.sh new file mode 100755 index 00000000000..13105be2421 --- /dev/null +++ b/multichain-testing/scripts/create-osmosis-pool.sh @@ -0,0 +1,192 @@ +#!/bin/bash + +set -euo pipefail +shopt -s expand_aliases + +alias agoric-exec="kubectl exec -i agoriclocal-genesis-0 -c validator -- agd" +alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" +alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" +alias osmo-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" + +AGORIC_WALLET="test1" +AGORIC_ADDRESS=$(agoric-exec keys show ${AGORIC_WALLET} -a) +OSMOSIS_WALLET="test1" +OSMOSIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_WALLET} -a) + +CHANNEL_INFO=$(hermes-exec --json query channels --show-counterparty --chain agoriclocal \ + | jq '[.][] | select(.result) | .result[] | select(.chain_id_b == "osmosislocal")') +AGORIC_OSMOSIS_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_a') +OSMOSIS_AGORIC_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_b') +AGORIC_OSMOSIS_PORT="transfer" + +AGORIC_TOKEN_DENOM="ubld" +AGORIC_TOKEN_AMOUNT="250000000000" + +IBC_DENOM=$(echo -n "$AGORIC_OSMOSIS_PORT/$OSMOSIS_AGORIC_CHANNEL/$AGORIC_TOKEN_DENOM" | sha256sum | awk '{print toupper($1)}') + +POOL_ASSET_1_DENOM="uosmo" +POOL_ASSET_1_AMOUNT="250000" +POOL_ASSET_1_WEIGHT="1" +POOL_ASSET_2_DENOM="ibc/$IBC_DENOM" +POOL_ASSET_2_AMOUNT="250000" +POOL_ASSET_2_WEIGHT="1" +SWAP_FEE="0.01" +EXIT_FEE="0.00", +FUTURE_GOVERNOR="" + +POOL_CONFIG_FILE="$POOL_ASSET_1_DENOM-$AGORIC_TOKEN_DENOM-pool-config.json" +POOL_CONFIG_DEST="/opt/$POOL_CONFIG_FILE" + +MAX_RETRIES="5" +DELAY="5" + +echo "Generating pool configuration file ..." +jq -n \ + --arg weight1 "${POOL_ASSET_1_WEIGHT}${POOL_ASSET_1_DENOM}" \ + --arg weight2 "${POOL_ASSET_2_WEIGHT}${POOL_ASSET_2_DENOM}" \ + --arg amount1 "${POOL_ASSET_1_AMOUNT}${POOL_ASSET_1_DENOM}" \ + --arg amount2 "${POOL_ASSET_2_AMOUNT}${POOL_ASSET_2_DENOM}" \ + --arg swapFee "$SWAP_FEE" \ + --arg exitFee "$EXIT_FEE" \ + --arg futureGovernor "$FUTURE_GOVERNOR" \ + '{ + "weights": "\($weight1),\($weight2)", + "initial-deposit": "\($amount1),\($amount2)", + "swap-fee": $swapFee, + "exit-fee": $exitFee, + "future-governor": $futureGovernor + }' > "$POOL_CONFIG_FILE" + +echo "Verifying if Agoric wallet has enough funds ..." +agoric_balance_json=$(agoric-exec query bank balances $AGORIC_ADDRESS --denom $AGORIC_TOKEN_DENOM -o json) +agoric_balance=$(jq -r '.amount' <<< "$agoric_balance_json") + +if [ "$agoric_balance" -le "$AGORIC_TOKEN_AMOUNT" ]; then + echo "Balance is NOT sufficient. Exiting..." + exit 1 +fi + +echo "Starting IBC transfer from Agoric to Osmosis ..." +agoric-exec tx ibc-transfer transfer $AGORIC_OSMOSIS_PORT $AGORIC_OSMOSIS_CHANNEL $OSMOSIS_ADDRESS ${AGORIC_TOKEN_AMOUNT}${AGORIC_TOKEN_DENOM} --from $AGORIC_ADDRESS --yes + +echo "Verifying if Osmosis wallet has the funds ..." +for ((i = 1; i <= MAX_RETRIES; i++)); do + echo "Attempt $i of $MAX_RETRIES..." + + osmosis_balances_json=$(osmosis-exec query bank balances $OSMOSIS_ADDRESS -o json) + + balance_1=$(jq -r --arg denom "$POOL_ASSET_1_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") + balance_2=$(jq -r --arg denom "$POOL_ASSET_2_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") + + # If not found, treat as zero + balance_1=${balance_1:-0} + balance_2=${balance_2:-0} + + if [[ "$balance_1" -ge "$POOL_ASSET_1_AMOUNT" && "$balance_2" -ge "$POOL_ASSET_2_AMOUNT" ]]; then + echo "Sufficient funds available." + break + fi + + if [[ $i -eq $MAX_RETRIES ]]; then + echo "Insufficient funds after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Waiting $DELAY seconds before retrying..." + sleep $DELAY +done + +# Record amount of existing pools before creating a new one +query_command='osmosis-exec query gamm num-pools -o json' +pool_count_json=$(eval "$query_command") +pool_count=$(jq -r '.num_pools' <<< "$pool_count_json") + +echo "Copying pool configuration to Osmosis ..." +kubectl cp "${POOL_CONFIG_FILE}" osmosislocal-genesis-0:"${POOL_CONFIG_DEST}" + +echo "Creating liquidity pool on Osmosis ..." +osmosis-exec tx gamm create-pool --pool-file $POOL_CONFIG_DEST --from $OSMOSIS_ADDRESS --chain-id osmosislocal --gas auto --gas-adjustment 1.2 --gas-prices=0.5uosmo --yes + +echo "Verifying pool details ..." +for ((i = 1; i <= MAX_RETRIES; i++)); do + current_pool_count_json=$(eval "$query_command") + current_pool_count=$(jq -r '.num_pools' <<< "$current_pool_count_json") + + if [ "$current_pool_count" -gt "$pool_count" ]; then + pool_info=$(osmosis-exec query gamm pool $current_pool_count) + break + fi + + if [[ $i -eq $MAX_RETRIES ]]; then + echo "Pool not created after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Waiting $DELAY seconds before retrying..." + sleep $DELAY +done + +SWAPROUTER_OWNER="genesis" +SWAPROUTER_OWNER_ADDRESS=$(osmosis-exec keys show ${SWAPROUTER_OWNER} -a) +SWAPROUTER_ADDRESS=$(osmo-cli "jq -r '.swaprouter.address' /contract-info.json") + +POOL_ID=$(jq -r '.pool | .id' <<< "$pool_info") +POOL_OUTPUT_DENOM=$POOL_ASSET_1_DENOM +POOL_INPUT_DENOM=$POOL_ASSET_2_DENOM + +SET_ROUTE_JSON=$( + cat << EOF +{ + "set_route": { + "input_denom": "$POOL_INPUT_DENOM", + "output_denom": "$POOL_OUTPUT_DENOM", + "pool_route": [ + { + "pool_id": "$POOL_ID", + "token_out_denom": "$POOL_OUTPUT_DENOM" + } + ] + } +} +EOF +) + +GET_ROUTE_JSON=$( + cat << EOF +{ + "get_route": { + "input_denom": "$POOL_INPUT_DENOM", + "output_denom": "$POOL_OUTPUT_DENOM" + } +} +EOF +) + +echo "Storing pool on swaprouter contract ..." +osmosis-exec tx wasm execute "$SWAPROUTER_ADDRESS" "$SET_ROUTE_JSON" --from "$SWAPROUTER_OWNER_ADDRESS" --chain-id osmosislocal --yes --fees 1000uosmo + +echo "Querying pool route ..." +( + set +e # handle failure of "osmosis-exec query wasm contract-state smart" + + for ((i = 1; i <= MAX_RETRIES; i++)); do + echo "Attempt $i of $MAX_RETRIES..." + pool_route_json=$(osmosis-exec query wasm contract-state smart "$SWAPROUTER_ADDRESS" "$GET_ROUTE_JSON" 2> /dev/null) + + if [[ $? -eq 0 ]]; then + echo "Pool route found:" + echo "$pool_route_json" + break + fi + + if [[ $i -eq MAX_RETRIES ]]; then + echo "Pool not stored after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Query failed. Waiting $DELAY seconds before retrying..." + sleep "$DELAY" + done +) + +echo "Liquidity Pool open and stored on swaprouter successfully." diff --git a/multichain-testing/scripts/download-wasm-artifacts.sh b/multichain-testing/scripts/download-wasm-artifacts.sh new file mode 100755 index 00000000000..f6c45e83c64 --- /dev/null +++ b/multichain-testing/scripts/download-wasm-artifacts.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Usage: ./download_specific_files.sh ... + +OWNER="$1" +REPO="$2" +BRANCH="$3" +FOLDER="$4" +DEST="$5" +shift 5 +FILES_TO_DOWNLOAD=("$@") + +API_URL="https://api.github.com/repos/$OWNER/$REPO/contents/$FOLDER?ref=$BRANCH" +mkdir -p "$DEST" + +curl -s "$API_URL" | jq -r '.[] | select(.type=="file") | .name + " " + .download_url' \ + | while read -r filename url; do + for wanted in "${FILES_TO_DOWNLOAD[@]}"; do + if [[ "$filename" == "$wanted" ]]; then + echo "Downloading $filename..." + curl -sL "$url" -o "$DEST/$filename" + fi + done + done + +echo "✅ Selected files downloaded to $DEST" diff --git a/multichain-testing/scripts/setup-xcs.sh b/multichain-testing/scripts/setup-xcs.sh new file mode 100755 index 00000000000..9753d05893f --- /dev/null +++ b/multichain-testing/scripts/setup-xcs.sh @@ -0,0 +1,134 @@ +#!/bin/bash + +set -euo pipefail +shopt -s expand_aliases + +alias osmo-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" +alias osmo-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" + +RPC=http://localhost:26655 +TX_FLAGS="--keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal" +OWNER=genesis +OWNER_ADDRESS=$(osmo-exec keys show genesis -a) +CONTRACT_INFO_HEX=636F6E74726163745F696E666F + +COMMON_INSTANTIATE_MSG="{\"owner\": \"$OWNER_ADDRESS\"}" + +wait_for_blocks() { + local num_blocks="$1" + local rpc="${2:-$RPC}" + + echo "Fetching current height from $rpc..." + + local start_height + start_height=$(curl -s "$rpc/status" | jq -r '.result.sync_info.latest_block_height') + + if [[ -z "$start_height" || "$start_height" == "null" ]]; then + echo "Failed to fetch block height" + return 1 + fi + + local target_height=$((start_height + num_blocks)) + echo "Waiting for $num_blocks blocks... (target: $target_height)" + + while true; do + local current_height + current_height=$(curl -s "$rpc/status" | jq -r '.result.sync_info.latest_block_height') + + if [[ "$current_height" -ge "$target_height" ]]; then + echo "Reached target height: $current_height" + break + else + echo "Current height: $current_height — waiting..." + sleep 2 + fi + done +} + +check_data_not_null() { + local json="$1" + local error_message="${2:-'data is null'}" + + local data + data=$(echo "$json" | jq -r '.data') + + if [[ "$data" == "null" ]]; then + echo "$error_message" + exit 1 + else + echo "contract initiated successfully: $(echo $data | base64 -d)" + fi +} + +echo "Prepare download script inside osmosislocal-genesis-0 pod so that we can deploy wasm contracts..." +cat ./scripts/download-wasm-artifacts.sh | osmo-cli "tee /download-wasm-artifacts.sh > /dev/null" + +echo "Set newly created file's permissions..." +osmo-cli "chmod 755 /download-wasm-artifacts.sh" + +echo "Download artifacts for XCS..." +osmo-cli "/download-wasm-artifacts.sh osmosis-labs osmosis main tests/ibc-hooks/bytecode /wasm-artifacts crosschain_swaps.wasm swaprouter.wasm crosschain_registry.wasm" + +echo "Storing Swaprouter code..." +osmo-exec tx wasm store /wasm-artifacts/swaprouter.wasm --from $OWNER $TX_FLAGS +wait_for_blocks 5 + +SWAPROUTER_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') + +echo "Instantiating Swaprouter..." +osmo-exec tx wasm instantiate "$SWAPROUTER_CODE_ID" "$COMMON_INSTANTIATE_MSG" --from $OWNER --label swaprouter --admin $OWNER_ADDRESS $TX_FLAGS +wait_for_blocks 5 + +SWAPROUTER_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$SWAPROUTER_CODE_ID" -o json | jq -r '.contracts | [last][0]') +echo "Swaprouter address: $SWAPROUTER_ADDRESS" + +echo "Storing Crosschain Registry code..." +osmo-exec tx wasm store /wasm-artifacts/crosschain_registry.wasm --from $OWNER $TX_FLAGS +wait_for_blocks 5 +CROSSCHAIN_REGISTRY_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') + +echo "Crosschain Registry code id: $CROSSCHAIN_REGISTRY_CODE_ID" + +echo "Instantiating Crosschain Registry..." +osmo-exec tx wasm instantiate "$CROSSCHAIN_REGISTRY_CODE_ID" "$COMMON_INSTANTIATE_MSG" --from $OWNER --label crosschain_registry --admin $OWNER_ADDRESS $TX_FLAGS +wait_for_blocks 5 + +CROSSCHAIN_REGISTRY_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$CROSSCHAIN_REGISTRY_CODE_ID" -o json | jq -r '.contracts | [last][0]') +echo "Crosschain Registry address: $CROSSCHAIN_REGISTRY_ADDRESS" + +echo "Storing Crosschain Swaps code..." +osmo-exec tx wasm store /wasm-artifacts/crosschain_swaps.wasm --from $OWNER $TX_FLAGS +wait_for_blocks 5 +CROSSCHAIN_SWAPS_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') + +XCS_INSTANTIATE_MSG="{\"swap_contract\": \"$SWAPROUTER_ADDRESS\", \"governor\": \"$OWNER_ADDRESS\", \"registry_contract\": \"$CROSSCHAIN_REGISTRY_ADDRESS\"}" + +echo "Instantiating Crosschain Swaps contract..." +osmo-exec tx wasm instantiate "$CROSSCHAIN_SWAPS_CODE_ID" "$XCS_INSTANTIATE_MSG" --from $OWNER --label crosschain_swaps --admin $OWNER_ADDRESS $TX_FLAGS +wait_for_blocks 5 + +CROSSCHAIN_SWAPS_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$CROSSCHAIN_SWAPS_CODE_ID" -o json | jq -r '.contracts | [last][0]') +echo "Crosschain Swaps address: $CROSSCHAIN_SWAPS_ADDRESS" + +echo "Persist contract information..." + +osmo-cli 'cat >/contract-info.json' << EOF +{ + "swaprouter": {"codeId": "${SWAPROUTER_CODE_ID}", "address": "${SWAPROUTER_ADDRESS}"}, + "crosschain_registry": {"codeId": "${CROSSCHAIN_REGISTRY_CODE_ID}", "address": "${CROSSCHAIN_REGISTRY_ADDRESS}"}, + "crosschain_swaps": {"codeId": "${CROSSCHAIN_SWAPS_CODE_ID}", "address": "${CROSSCHAIN_SWAPS_ADDRESS}"} +} +EOF + +echo "Contract Information" +osmo-cli 'cat /contract-info.json' + +echo "Check instantiations..." +swaprouterContractInfo=$(osmo-exec q wasm contract-state raw $SWAPROUTER_ADDRESS $CONTRACT_INFO_HEX -o json) +check_data_not_null $swaprouterContractInfo "swaprouter not instantiated correctly" + +registryContractInfo=$(osmo-exec q wasm contract-state raw $CROSSCHAIN_REGISTRY_ADDRESS $CONTRACT_INFO_HEX -o json) +check_data_not_null $registryContractInfo "crosschain_registry not instantiated correctly" + +xcsContractInfo=$(osmo-exec q wasm contract-state raw $CROSSCHAIN_SWAPS_ADDRESS $CONTRACT_INFO_HEX -o json) +check_data_not_null $xcsContractInfo "crosschain_swaps not instantiated correctly" From 89b18db4b7ddd9c92bf2a78833c992f862c0aca1 Mon Sep 17 00:00:00 2001 From: Luqi Pan Date: Thu, 10 Apr 2025 17:45:24 -0700 Subject: [PATCH 02/24] chore(orchestration): create scaffold for swap anything asyncFlow --- .../src/examples/swap-anything.flows.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages/orchestration/src/examples/swap-anything.flows.js diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js new file mode 100644 index 00000000000..23a8f852f21 --- /dev/null +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -0,0 +1,51 @@ +/** + * @import {GuestInterface, GuestOf} from '@agoric/async-flow'; + * @import {Invitation, ZCF, ZCFSeat} from '@agoric/zoe'; + * @import {Brand} from '@agoric/ertp'; + * @import {Vow} from '@agoric/vow'; + * @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js'; + * @import {ZoeTools} from '../utils/zoe-tools.js'; + * @import {Orchestrator, OrchestrationFlow, LocalAccountMethods, ChainHub, ChainInfo} from '../types.js'; + * @import {AccountIdArg} from '../orchestration-api.ts'; + */ + +/** + * @satisfies {OrchestrationFlow} + * @param {Orchestrator} orch + * @param {object} ctx + * @param {GuestInterface} ctx.chainHub + * @param {Promise>} ctx.sharedLocalAccountP + * @param {Promise< + * GuestInterface< + * import('../exos/cosmos-orchestration-account.js').CosmosOrchestrationAccountKit['holder'] + * > + * >} ctx.nobleAccountP + * @param {GuestInterface} ctx.zoeTools + * @param {GuestOf<(msg: string) => Vow>} ctx.log + * @param {Brand} ctx.USDC + * @param {ZCFSeat} seat + * @param {{ + * destAddr: AccountIdArg; + * destDenom: Denom; + * slippage: { slippageRatio: Ratio; windowSeconds: Nat }; + * onFailedDelivery: string; + * nextMemo: string; + * }} offerArgs + */ + +// Given USDC, swap to desired token with slippage +// Ref: https://github.com/osmosis-labs/osmosis/tree/main/cosmwasm/contracts/crosschain-swaps#via-ibc +export const swapIt = async ( + orch, + { + chainHub, + sharedLocalAccountP, + log, + nobleAccountP, + USDC, + zoeTools: { localTransfer, withdrawToSeat }, + }, + seat, + offerArgs, +) => {}; +harden(swapIt); From 1c76e82fc09a5c7277e05732692b26baa945f527 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Wed, 23 Apr 2025 16:13:43 +0300 Subject: [PATCH 03/24] chore: implement swap-anything.contract.js with zoe offers chore: WIP swap anything Refs: #8863 chore: unit test for happy path Refs: #8863 chore: init multichain testing work Refs: #8863 chore: WIP basic use case multichain testing Refs: #8863 chore: improve assertions, add README Refs: #8863 --- .github/workflows/multichain-e2e-template.yml | 18 --- .github/workflows/multichain-e2e.yml | 2 - multichain-testing/Makefile | 10 +- .../config.xcs-swap-anything.yaml | 125 ++++++++++++++ .../scripts/create-osmosis-pool.sh | 2 +- .../scripts/update-config-logs.sh | 66 ++++++++ .../test/xcs-swap-anything/Makefile | 108 +++++++++++++ .../test/xcs-swap-anything/README.md | 18 +++ .../xcs-swap-anything/swap-anything.test.ts | 109 +++++++++++++ .../scripts/testing/init-swap-anything.js | 36 +++++ .../src/examples/swap-anything.contract.js | 103 ++++++++++++ .../src/examples/swap-anything.flows.js | 152 +++++++++++++++--- .../src/proposals/start-swap-anything.js | 133 +++++++++++++++ .../test/examples/swap-anything.test.ts | 141 ++++++++++++++++ 14 files changed, 974 insertions(+), 49 deletions(-) create mode 100644 multichain-testing/config.xcs-swap-anything.yaml create mode 100644 multichain-testing/scripts/update-config-logs.sh create mode 100644 multichain-testing/test/xcs-swap-anything/Makefile create mode 100644 multichain-testing/test/xcs-swap-anything/README.md create mode 100644 multichain-testing/test/xcs-swap-anything/swap-anything.test.ts create mode 100644 packages/builders/scripts/testing/init-swap-anything.js create mode 100644 packages/orchestration/src/examples/swap-anything.contract.js create mode 100644 packages/orchestration/src/proposals/start-swap-anything.js create mode 100644 packages/orchestration/test/examples/swap-anything.test.ts diff --git a/.github/workflows/multichain-e2e-template.yml b/.github/workflows/multichain-e2e-template.yml index d642f8b8a51..9f57fc69895 100644 --- a/.github/workflows/multichain-e2e-template.yml +++ b/.github/workflows/multichain-e2e-template.yml @@ -14,16 +14,6 @@ on: required: true type: string description: 'Identifier for the test suite that will be used as part of the filename name for logs' - osmosis_pool: - description: 'Condition to open liquidity pool on osmosis' - default: false - required: false - type: boolean - osmosis_xcs: - description: 'Flag to enable Osmosis Crosschain Swaps' - default: false - required: false - type: boolean jobs: multichain-e2e: @@ -124,14 +114,6 @@ jobs: run: make register-bank-assets working-directory: ./agoric-sdk/multichain-testing - - name: Setup Osmosis XCS Contracts - run: make osmosis-xcs-setup - working-directory: ./agoric-sdk/multichain-testing - - - name: Create Osmosis Pool - run: make create-osmosis-pool - working-directory: ./agoric-sdk/multichain-testing - - name: Run @agoric/multichain-testing E2E Tests run: ${{ inputs.test_command }} working-directory: ./agoric-sdk/multichain-testing diff --git a/.github/workflows/multichain-e2e.yml b/.github/workflows/multichain-e2e.yml index 8b0af894285..0f2c16d195f 100644 --- a/.github/workflows/multichain-e2e.yml +++ b/.github/workflows/multichain-e2e.yml @@ -30,8 +30,6 @@ jobs: config: config.yaml test_command: yarn test:main test_suite_name: orchestration-api-hermes - osmosis_pool: true - osmosis_xcs: true fast-usdc-hermes: name: Fast USDC - Hermes diff --git a/multichain-testing/Makefile b/multichain-testing/Makefile index 403a963a2da..c19d2e66941 100644 --- a/multichain-testing/Makefile +++ b/multichain-testing/Makefile @@ -97,18 +97,12 @@ tail-slog: ############################################################################### ### Osmosis Setup ### ############################################################################### +osmosis-xcs-setup: + $(CURDIR)/scripts/setup-xcs.sh create-osmosis-pool: $(CURDIR)/scripts/create-osmosis-pool.sh - -############################################################################### -### Osmosis Setup ### -############################################################################### - -osmosis-xcs-setup: - $(CURDIR)/scripts/setup-xcs.sh - ############################################################################### ### Start All ### ############################################################################### diff --git a/multichain-testing/config.xcs-swap-anything.yaml b/multichain-testing/config.xcs-swap-anything.yaml new file mode 100644 index 00000000000..82b1095762b --- /dev/null +++ b/multichain-testing/config.xcs-swap-anything.yaml @@ -0,0 +1,125 @@ +name: agoric-multichain-testing +version: 0.2.20 + +chains: + - id: agoriclocal + name: agoric + image: ghcr.io/agoric/agoric-sdk:dev + numValidators: 1 + env: + - name: DEBUG + value: SwingSet:vat,SwingSet:ls + genesis: + app_state: + staking: + params: + unbonding_time: '2m' + swingset: + params: + bootstrap_vat_config: '@agoric/vm-config/decentral-itest-orchestration-chains-config.json' + scripts: + updateConfig: + file: scripts/update-config.sh + faucet: + enabled: true + type: starship + ports: + rest: 1317 + rpc: 26657 + exposer: 38087 + grpc: 9090 + faucet: 8082 + resources: + cpu: 1 + memory: 4Gi + - id: osmosislocal + name: osmosis + numValidators: 1 + genesis: + app_state: + staking: + params: + unbonding_time: '2m' + interchain_accounts: + host_genesis_state: + params: + host_enabled: true + allow_messages: ['*'] + interchainquery: + host_port: 'icqhost' + params: + host_enabled: true + allow_queries: + - /cosmos.bank.v1beta1.Query/Balance + - /cosmos.bank.v1beta1.Query/AllBalances + scripts: + updateConfig: + file: scripts/update-config-logs.sh + faucet: + enabled: true + type: starship + ports: + rest: 1315 + rpc: 26655 + grpc: 9093 + faucet: 8084 + resources: + cpu: 1 + memory: 1Gi + - id: cosmoshublocal + name: cosmoshub + numValidators: 1 + genesis: + app_state: + staking: + params: + unbonding_time: '2m' + interchain_accounts: + host_genesis_state: + params: + host_enabled: true + allow_messages: ['*'] + faucet: + enabled: true + type: starship + ports: + rest: 1314 + rpc: 26654 + grpc: 9092 + faucet: 8083 + resources: + cpu: 1 + memory: 1Gi + +relayers: + - name: osmosis-cosmoshub + type: hermes + replicas: 1 + chains: + - osmosislocal + - cosmoshublocal + - name: agoric-osmosis + type: hermes + replicas: 1 + chains: + - agoriclocal + - osmosislocal + config: + global: + log_level: 'debug' + telemetry: + enabled: true + - name: agoric-cosmoshub + type: hermes + replicas: 1 + chains: + - agoriclocal + - cosmoshublocal + +explorer: + enabled: false + +registry: + enabled: true + ports: + rest: 8081 diff --git a/multichain-testing/scripts/create-osmosis-pool.sh b/multichain-testing/scripts/create-osmosis-pool.sh index 13105be2421..2b0aa74d251 100755 --- a/multichain-testing/scripts/create-osmosis-pool.sh +++ b/multichain-testing/scripts/create-osmosis-pool.sh @@ -22,7 +22,7 @@ AGORIC_OSMOSIS_PORT="transfer" AGORIC_TOKEN_DENOM="ubld" AGORIC_TOKEN_AMOUNT="250000000000" -IBC_DENOM=$(echo -n "$AGORIC_OSMOSIS_PORT/$OSMOSIS_AGORIC_CHANNEL/$AGORIC_TOKEN_DENOM" | sha256sum | awk '{print toupper($1)}') +IBC_DENOM=$(echo -n "$AGORIC_OSMOSIS_PORT/$OSMOSIS_AGORIC_CHANNEL/$AGORIC_TOKEN_DENOM" | shasum -a 256 | awk '{print toupper($1)}') POOL_ASSET_1_DENOM="uosmo" POOL_ASSET_1_AMOUNT="250000" diff --git a/multichain-testing/scripts/update-config-logs.sh b/multichain-testing/scripts/update-config-logs.sh new file mode 100644 index 00000000000..93598a1d982 --- /dev/null +++ b/multichain-testing/scripts/update-config-logs.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +CHAIN_ID="${CHAIN_ID:=osmosis}" +CHAIN_DIR="${CHAIN_DIR:=$HOME/.osmosisd}" +KEYS_CONFIG="${KEYS_CONFIG:=configs/keys.json}" + +set -eux + +ls $CHAIN_DIR + +echo "Update config.toml file" +sed -i -e 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' $CHAIN_DIR/config/config.toml +sed -i -e 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/config/config.toml +sed -i -e 's/seeds = ".*"/seeds = ""/g' $CHAIN_DIR/config/config.toml +sed -i -e 's#cors_allowed_origins = \[\]#cors_allowed_origins = \["*"\]#g' $CHAIN_DIR/config/config.toml +sed -i -e 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/config/config.toml + +echo "Update client.toml file" +sed -i -e 's#keyring-backend = "os"#keyring-backend = "test"#g' $CHAIN_DIR/config/client.toml +sed -i -e 's#output = "text"#output = "json"#g' $CHAIN_DIR/config/client.toml +sed -i -e "s#chain-id = \"\"#chain-id = \"$CHAIN_ID\"#g" $CHAIN_DIR/config/client.toml + +echo "Update app.toml file" +sed -i -e "s#minimum-gas-prices = \".*\"#minimum-gas-prices = \"0$DENOM\"#g" $CHAIN_DIR/config/app.toml +sed -i -e "s#pruning = \".*\"#pruning = \"default\"#g" $CHAIN_DIR/config/app.toml +sed -i -e 's/enable-unsafe-cors = false/enable-unsafe-cors = true/g' $CHAIN_DIR/config/app.toml +sed -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' $CHAIN_DIR/config/app.toml +sed -i -e 's/enable = false/enable = true/g' $CHAIN_DIR/config/app.toml +sed -i -e 's/swagger = false/swagger = true/g' $CHAIN_DIR/config/app.toml +sed -i -e 's/enable = false/enable = true/g' $CHAIN_DIR/config/app.toml +sed -i -e 's/enabled = false/enabled = true/g' $CHAIN_DIR/config/app.toml + +function get_next_line_number() { + local txt=$1 + local file=$2 + local line_number=$(grep -n "$txt" $file | cut -d: -f1 | head -1) + echo $((line_number + 1)) +} + +line_number=$(get_next_line_number "Address defines the API server to listen on." $CHAIN_DIR/config/app.toml) +sed -i -e "${line_number}s#address = \".*\"#address = \"tcp://0.0.0.0:1317\"#g" $CHAIN_DIR/config/app.toml + +line_number=$(get_next_line_number "Address defines the gRPC server address to bind to." $CHAIN_DIR/config/app.toml) +sed -i -e "${line_number}s#address = \".*\"#address = \"0.0.0.0:9090\"#g" $CHAIN_DIR/config/app.toml + +line_number=$(get_next_line_number "Address defines the gRPC-web server address to bind to." $CHAIN_DIR/config/app.toml) +sed -i -e "${line_number}s#address = \".*\"#address = \"0.0.0.0:9091\"#g" $CHAIN_DIR/config/app.toml + +if [ "$METRICS" == "true" ]; then + sed -i -e "s/prometheus = false/prometheus = true/g" $CHAIN_DIR/config/config.toml + + line_number=$(get_next_line_number "PrometheusRetentionTime, when positive, enables a Prometheus metrics sink." $CHAIN_DIR/config/app.toml) + sed -i -e "${line_number}s/prometheus-retention-time = 0/prometheus-retention-time = 3600/g" $CHAIN_DIR/config/app.toml +fi + +echo "Update consensus params in config.toml" +sed -i -e "s#timeout_propose = \".*\"#timeout_propose = \"$TIMEOUT_PROPOSE\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_propose_delta = \".*\"#timeout_propose_delta = \"$TIMEOUT_PROPOSE_DELTA\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_prevote = \".*\"#timeout_prevote = \"$TIMEOUT_PREVOTE\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_prevote_delta = \".*\"#timeout_prevote_delta = \"$TIMEOUT_PREVOTE_DELTA\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_precommit = \".*\"#timeout_precommit = \"$TIMEOUT_PRECOMMIT\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_precommit_delta = \".*\"#timeout_precommit_delta = \"$TIMEOUT_PRECOMMIT_DELTA\"#g" $CHAIN_DIR/config/config.toml +sed -i -e "s#timeout_commit = \".*\"#timeout_commit = \"$TIMEOUT_COMMIT\"#g" $CHAIN_DIR/config/config.toml + +echo "Update config.toml file log level" +sed -i -E 's/^(log_level\s*=\s*)".*"/\1"debug"/' $CHAIN_DIR/config/config.toml diff --git a/multichain-testing/test/xcs-swap-anything/Makefile b/multichain-testing/test/xcs-swap-anything/Makefile new file mode 100644 index 00000000000..2e68b607c21 --- /dev/null +++ b/multichain-testing/test/xcs-swap-anything/Makefile @@ -0,0 +1,108 @@ +cli-hermes=kubectl exec -it hermes-agoric-osmosis-0 -c relayer -- hermes +exec-agd=kubectl exec -i agoriclocal-genesis-0 -c validator -- agd +exec-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd +cli-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c + +AGORIC_TEST_ADDRESS=$(shell $(exec-agd) keys show test1 -a --keyring-backend test) +AGORIC_GENESIS_ADDRESS=$(shell $(exec-agd) keys show genesis -a --keyring-backend test) +OSMOSIS_TEST_ADDRESS=$(shell $(exec-osmo) keys show test1 -a --keyring-backend test) +OSMOSIS_GENESIS_ADDRESS = $(shell $(exec-osmo) keys show genesis -a --keyring-backend test) + +TX_FLAGS=--from $(OSMOSIS_GENESIS_ADDRESS) --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal +AGD_TX_FLAGS=--from $(AGORIC_GENESIS_ADDRESS) --keyring-backend=test --gas=auto --gas-prices 0.1ubld --gas-adjustment 1.3 --yes --chain-id agoriclocal + +CHANNEL_INFO=$(shell $(cli-hermes) --json query channels --show-counterparty --chain agoriclocal \ + | jq '[.][] | select(.result) | .result[] | select(.chain_id_b == "osmosislocal")') +AGORIC_OSMOSIS_CHANNEL=$(shell echo '$(CHANNEL_INFO)' | jq -r '.channel_a') +OSMOSIS_AGORIC_CHANNEL=$(shell echo '$(CHANNEL_INFO)' | jq -r '.channel_b') + +REGISTRY_ADDRESS="osmo1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqvlx82r" +SWAPROUTER_ADDRESS="osmo14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sq2r9g9" +SWAP_ADDRESS="osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8" + +POOL_ASSET_1_DENOM="uosmo" +POOL_ASSET_1_AMOUNT="250000" +POOL_ASSET_2_DENOM="ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596" + +GET_ROUTE_JSON = '{"get_route":{"input_denom":$(POOL_ASSET_2_DENOM),"output_denom":$(POOL_ASSET_1_DENOM)}}' +SET_CHAIN_CHANNEL_LINKS='{"modify_chain_channel_links":{"operations":[{"operation":"set","source_chain":"agoric","destination_chain":"osmosis","channel_id":"$(AGORIC_OSMOSIS_CHANNEL)"},{"operation":"set","source_chain":"osmosis","destination_chain":"agoric","channel_id":"$(OSMOSIS_AGORIC_CHANNEL)"}]}}' +SET_PREFIXES_MSG='{"modify_bech32_prefixes":{"operations":[{"operation":"set","chain_name":"osmosis","prefix":"osmo"},{"operation":"set","chain_name":"agoric","prefix":"agoric"}]}}' +GET_CHANNEL_FROM_CHAINS_MSG='{"get_channel_from_chain_pair":{"source_chain":"osmosis","destination_chain":"agoric"}}' +GET_PREFIX_FROM_CHAIN_MSG='{"get_bech32_prefix_from_chain_name":{"chain_name":"osmosis"}}' + +GOOD_SWAP_MEMO='{"wasm":{"contract":$(SWAP_ADDRESS),"msg":{"osmosis_swap":{"output_denom":"uosmo","slippage":{"twap":{"window_seconds":10,"slippage_percentage":"20"}},"receiver":"agoric1elueec97as0uwavlxpmj75u5w7yq9dgphq47zx","on_failed_delivery":"do_nothing", "next_memo":{}}}}}' +BAD_SWAP_MEMO=' \ +{"wasm":{ \ + "contract":"$(SWAP_ADDRESS)", \ + "msg":{ \ + "osmosis_swap":{ \ + "output_denom":"uosmo", \ + "slippage":{ \ + "twap":{ \ + "window_seconds":10, \ + "slippage_percentage":"20" \ + } \ + }, \ + "receiver":"$(AGORIC_GENESIS_ADDRESS)", \ + "on_failed_delivery":"do_nothing", \ + "next_memo":{} \ + } \ + } \ +}}' + +print-wasm-info: + $(cli-osmo) "cat /contract-info.json" + +print-channel-info: + @echo $(CHANNEL_INFO) + +print-agoric-channel: + @echo $(AGORIC_OSMOSIS_CHANNEL) + +print-osmosis-channel: + @echo $(OSMOSIS_AGORIC_CHANNEL) + +print-osmosis-address: + echo '$(AGORIC_GENESIS_ADDRESS)' + +versions: + $(cli-hermes) --version + $(exec-agd) version + $(exec-osmo) version + +query-channels: + $(cli-hermes) query channels --show-counterparty --chain $(CHAIN) + +query-balance-osmo: + $(exec-osmo) query bank balances $(OSMOSIS_TEST_ADDRESS) | jq + +query-balance-agoric: + $(exec-agd) query bank balances agoric1elueec97as0uwavlxpmj75u5w7yq9dgphq47zx | jq + +query-route: + $(exec-osmo) q wasm contract-state smart $(SWAPROUTER_ADDRESS) $(GET_ROUTE_JSON) + +query-pool-balance: + $(exec-osmo) q gamm pool 1 | jq + +query-tx-osmo: + $(exec-osmo) q tx $(TX_HASH) | jq . + +query-tx-agoric: + $(exec-agd) q tx $(TX_HASH) | jq . + +query-channel-from-registry: + $(exec-osmo) q wasm contract-state smart $(REGISTRY_ADDRESS) $(GET_CHANNEL_FROM_CHAINS_MSG) | jq . + +query-prefix-from-registry: + $(exec-osmo) q wasm contract-state smart $(REGISTRY_ADDRESS) $(GET_PREFIX_FROM_CHAIN_MSG) | jq . + +tx-chain-channel-links: + $(exec-osmo) tx wasm execute $(REGISTRY_ADDRESS) $(SET_CHAIN_CHANNEL_LINKS) $(TX_FLAGS) + +tx-bec32-prefixes: + $(exec-osmo) tx wasm execute $(REGISTRY_ADDRESS) $(SET_PREFIXES_MSG) $(TX_FLAGS) + +tx-send-xcs-ibc-transfer: + $(exec-agd) tx ibc-transfer transfer transfer $(AGORIC_OSMOSIS_CHANNEL) $(SWAP_ADDRESS) 125ubld \ + --memo $(GOOD_SWAP_MEMO) $(AGD_TX_FLAGS) \ No newline at end of file diff --git a/multichain-testing/test/xcs-swap-anything/README.md b/multichain-testing/test/xcs-swap-anything/README.md new file mode 100644 index 00000000000..3af79181147 --- /dev/null +++ b/multichain-testing/test/xcs-swap-anything/README.md @@ -0,0 +1,18 @@ +## Spin up Environment +```sh +cd agoric-sdk/multichain-testing +make start FILE=config.xcs-swap-anything.yaml +make osmosis-xcs-setup +make create-osmosis-pool + +## Configure the osmosis registries +cd cd agoric-sdk/multichain-testing/test/xcs-swap-anything +make tx-chain-channel-links +make tx-bec32-prefixes +``` + +## Run tests +```sh +cd agoric-sdk/multichain-testing +yarn ava test/xcs-swap-anything/swap-anything.test.ts +``` \ No newline at end of file diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts new file mode 100644 index 00000000000..f4de72029cd --- /dev/null +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -0,0 +1,109 @@ +import anyTest from '@endo/ses-ava/prepare-endo.js'; +import type { TestFn } from 'ava'; +import { AmountMath } from '@agoric/ertp'; +import { makeDoOffer } from '../../tools/e2e-tools.js'; +import { commonSetup, type SetupContextWithWallets } from '../support.js'; +import { makeQueryClient } from '../../tools/query.js'; +import starshipChainInfo from '../../starship-chain-info.js'; + +const test = anyTest as TestFn; + +const accounts = ['agoricSender', 'agoricReceiver']; + +const contractName = 'swapAnything'; +const contractBuilder = + '../packages/builders/scripts/testing/init-swap-anything.js'; + +test.before(async t => { + const { setupTestKeys, ...common } = await commonSetup(t); + const { commonBuilderOpts, deleteTestKeys, startContract } = common; + await deleteTestKeys(accounts).catch(); + const wallets = await setupTestKeys(accounts); + console.log('WALLETS', wallets); + t.context = { ...common, wallets }; + await startContract(contractName, contractBuilder, commonBuilderOpts); +}); + +test('BLD for OSMO, receiver on Agoric', async t => { + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + // Provision the Agoric smart wallet + const agoricAddr = wallets.agoricSender; + const wdUser = await provisionSmartWallet(agoricAddr, { + BLD: 1000n, + IST: 1000n, + }); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + const osmosisChainId = useChain('osmosis').chain.chain_id; + + const { + transferChannel: { channelId }, + } = starshipChainInfo.agoric.connections[osmosisChainId]; + + const doOffer = makeDoOffer(wdUser); + + // Verify deposit + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const bldBrand = Object.fromEntries(brands).BLD; + const swapInAmount = AmountMath.make(bldBrand, 125n); + const { balances: balancesBefore } = await queryClient.queryBalances( + wallets.agoricReceiver, + ); + + // Send swap offer + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; + await doOffer({ + id: makeAccountOfferId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeSendInvitation']], + }, + offerArgs: { + // TODO: get the contract address dynamically + destAddr: + 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', + receiverAddr: wallets.agoricReceiver, + outDenom: 'uosmo', + slippage: { slippagePercentage: '20', windowSeconds: 10 }, + onFailedDelivery: 'do_nothing', + }, + proposal: { give: { Send: swapInAmount } }, + }); + + const { balances: agoricReceiverBalances } = await retryUntilCondition( + () => queryClient.queryBalances(wallets.agoricReceiver), + ({ balances }) => balances.length > balancesBefore.length, + 'Deposit reflected in localOrchAccount balance', + ); + t.log(agoricReceiverBalances); + + const { hash: expectedHash } = await queryClient.queryDenom( + `transfer/${channelId}`, + 'uosmo', + ); + + t.log('Expected denom hash:', expectedHash); + + t.regex(agoricReceiverBalances[0]?.denom, /^ibc/); + t.is( + agoricReceiverBalances[0]?.denom.split('ibc/')[1], + expectedHash, + 'got expected ibc denom hash', + ); +}); + +test.after(async t => { + const { deleteTestKeys } = t.context; + deleteTestKeys(accounts); +}); diff --git a/packages/builders/scripts/testing/init-swap-anything.js b/packages/builders/scripts/testing/init-swap-anything.js new file mode 100644 index 00000000000..f3faf4debb3 --- /dev/null +++ b/packages/builders/scripts/testing/init-swap-anything.js @@ -0,0 +1,36 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { + getManifest, + startSwapAnything, +} from '@agoric/orchestration/src/proposals/start-swap-anything.js'; +import { parseChainHubOpts } from '../orchestration/helpers.js'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ( + { publishRef, install }, + options, +) => + harden({ + sourceSpec: '@agoric/orchestration/src/proposals/start-swap-anything.js', + getManifestCall: [ + getManifest.name, + { + installationRef: publishRef( + install( + '@agoric/orchestration/src/examples/swap-anything.contract.js', + ), + ), + options, + }, + ], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + const { scriptArgs } = endowments; + const opts = parseChainHubOpts(scriptArgs); + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval(startSwapAnything.name, utils => + defaultProposalBuilder(utils, opts), + ); +}; diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js new file mode 100644 index 00000000000..de7785809ff --- /dev/null +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -0,0 +1,103 @@ +import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; +import { E } from '@endo/far'; +import { M } from '@endo/patterns'; +import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js'; +import { withOrchestration } from '../utils/start-helper.js'; +import * as sharedFlows from './shared.flows.js'; +import { swapIt } from './swap-anything.flows.js'; +import { AnyNatAmountShape } from '../typeGuards.js'; +import { registerChainsAndAssets } from '../utils/chain-hub-helper.js'; + +/** + * @import {Remote, Vow} from '@agoric/vow'; + * @import {Zone} from '@agoric/zone'; + * @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js'; + * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; + */ + +export const SingleNatAmountRecord = M.and( + M.recordOf(M.string(), AnyNatAmountShape, { numPropertiesLimit: 1 }), + M.not(harden({})), +); +harden(SingleNatAmountRecord); + +/** + * Send assets currently in an ERTP purse to an account on another chain. This + * currently supports IBC and CCTP transfers. It could eventually support other + * protocols, like Axelar GMP or IBC Eureka. + * + * Orchestration contract to be wrapped by withOrchestration for Zoe + * + * @param {ZCF} zcf + * @param {OrchestrationPowers & { + * assetInfo?: [Denom, DenomDetail & { brandKey?: string }][]; + * chainInfo?: Record; + * marshaller: Marshaller; + * storageNode: Remote; + * }} privateArgs + * @param {Zone} zone + * @param {OrchestrationTools} tools + */ +export const contract = async ( + zcf, + privateArgs, + zone, + { chainHub, orchestrate, vowTools, zoeTools }, +) => { + const creatorFacet = prepareChainHubAdmin(zone, chainHub); + + // UNTIL https://github.com/Agoric/agoric-sdk/issues/9066 + const logNode = E(privateArgs.storageNode).makeChildNode('log'); + /** @type {(msg: string) => Vow} */ + const log = msg => vowTools.watch(E(logNode).setValue(msg)); + + const makeLocalAccount = orchestrate( + 'makeLocalAccount', + {}, + sharedFlows.makeLocalAccount, + ); + + /** + * @type {any} sharedLocalAccountP expects a Promise but this is a vow UNTIL + * https://github.com/Agoric/agoric-sdk/issues/9822 + */ + const sharedLocalAccountP = zone.makeOnce('localAccount', () => + makeLocalAccount(), + ); + + const swapAnything = orchestrate( + 'swapAnything', + { chainHub, sharedLocalAccountP, log, zoeTools }, + swapIt, + ); + + const publicFacet = zone.exo( + 'Send PF', + M.interface('Send PF', { + makeSendInvitation: M.callWhen().returns(InvitationShape), + }), + { + makeSendInvitation() { + return zcf.makeInvitation( + swapAnything, + 'swap', + undefined, + M.splitRecord({ give: SingleNatAmountRecord }), + ); + }, + }, + ); + + registerChainsAndAssets( + chainHub, + zcf.getTerms().brands, + privateArgs.chainInfo, + privateArgs.assetInfo, + ); + + return { publicFacet, creatorFacet }; +}; +harden(contract); + +export const start = withOrchestration(contract, { publishAccountInfo: true }); +harden(start); diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js index 23a8f852f21..2041a7ad5e9 100644 --- a/packages/orchestration/src/examples/swap-anything.flows.js +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -1,13 +1,67 @@ +import { NonNullish, makeTracer } from '@agoric/internal'; +import { Fail, makeError, q } from '@endo/errors'; +import { M, mustMatch } from '@endo/patterns'; + +const trace = makeTracer('SwapAnything'); + +const { entries } = Object; + /** + * @typedef {{ + * destAddr: string; + * receiverAddr: string; + * outDenom: Denom; + * slippage: { slippagePercentage: string; windowSeconds: number }; + * onFailedDelivery: string; + * nextMemo?: string; + * }} SwapInfo + * * @import {GuestInterface, GuestOf} from '@agoric/async-flow'; - * @import {Invitation, ZCF, ZCFSeat} from '@agoric/zoe'; - * @import {Brand} from '@agoric/ertp'; + * @import {Denom} from '@agoric/orchestration'; + * @import {ZCFSeat} from '@agoric/zoe'; * @import {Vow} from '@agoric/vow'; * @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js'; * @import {ZoeTools} from '../utils/zoe-tools.js'; - * @import {Orchestrator, OrchestrationFlow, LocalAccountMethods, ChainHub, ChainInfo} from '../types.js'; - * @import {AccountIdArg} from '../orchestration-api.ts'; + * @import {Orchestrator, OrchestrationFlow, ChainHub, ChainInfo, CosmosChainInfo} from '../types.js'; + */ + +const denomForBrand = async (orch, brand) => { + const agoric = await orch.getChain('agoric'); + const assets = await agoric.getVBankAssetInfo(); + const { denom } = NonNullish( + assets.find(a => a.brand === brand), + `${brand} not registered in ChainHub`, + ); + return denom; +}; + +/** + * @param {SwapInfo} swapInfo + * @returns {string} */ +const buildXCSMemo = swapInfo => { + const memo = { + wasm: { + contract: swapInfo.destAddr, + msg: { + osmosis_swap: { + output_denom: swapInfo.outDenom, + slippage: { + twap: { + window_seconds: swapInfo.slippage.windowSeconds, + slippage_percentage: swapInfo.slippage.slippagePercentage, + }, + }, + receiver: swapInfo.receiverAddr, + on_failed_delivery: swapInfo.onFailedDelivery, + nextMemo: swapInfo.nextMemo, + }, + }, + }, + }; + + return JSON.stringify(memo); +}; /** * @satisfies {OrchestrationFlow} @@ -15,22 +69,10 @@ * @param {object} ctx * @param {GuestInterface} ctx.chainHub * @param {Promise>} ctx.sharedLocalAccountP - * @param {Promise< - * GuestInterface< - * import('../exos/cosmos-orchestration-account.js').CosmosOrchestrationAccountKit['holder'] - * > - * >} ctx.nobleAccountP * @param {GuestInterface} ctx.zoeTools * @param {GuestOf<(msg: string) => Vow>} ctx.log - * @param {Brand} ctx.USDC * @param {ZCFSeat} seat - * @param {{ - * destAddr: AccountIdArg; - * destDenom: Denom; - * slippage: { slippageRatio: Ratio; windowSeconds: Nat }; - * onFailedDelivery: string; - * nextMemo: string; - * }} offerArgs + * @param {SwapInfo} offerArgs */ // Given USDC, swap to desired token with slippage @@ -41,11 +83,81 @@ export const swapIt = async ( chainHub, sharedLocalAccountP, log, - nobleAccountP, - USDC, zoeTools: { localTransfer, withdrawToSeat }, }, seat, offerArgs, -) => {}; +) => { + mustMatch( + offerArgs, + M.splitRecord( + { + destAddr: M.string(), + receiverAddr: M.string(), + outDenom: M.string(), + onFailedDelivery: M.string(), + slippage: { slippagePercentage: M.string(), windowSeconds: M.number() }, + }, + { nextMemo: M.string() }, + ), + ); + + const { receiverAddr, destAddr } = offerArgs; + // NOTE the proposal shape ensures that the `give` is a single asset + const { give } = seat.getProposal(); + const [[_kw, amt]] = entries(give); + void log(`sending {${amt.value}} from osmosis to ${receiverAddr}`); + const denom = await denomForBrand(orch, amt.brand); + + /** + * @type {any} XXX methods returning vows + * https://github.com/Agoric/agoric-sdk/issues/9822 + */ + const sharedLocalAccount = await sharedLocalAccountP; + + /** + * Helper function to recover if IBC Transfer fails + * + * @param {Error} e + */ + const recoverFailedTransfer = async e => { + await withdrawToSeat(sharedLocalAccount, seat, give); + const errorMsg = `IBC Transfer failed ${q(e)}`; + void log(`ERROR: ${errorMsg}`); + seat.fail(errorMsg); + throw makeError(errorMsg); + }; + + const [_a, osmosisChainInfo, connection] = + await chainHub.getChainsAndConnection('agoric', 'osmosis'); + + connection.counterparty || Fail`No IBC connection to Osmosis`; + + void log(`got info for chain: osmosis ${osmosisChainInfo}`); + trace(osmosisChainInfo); + + await localTransfer(seat, sharedLocalAccount, give); + void log(`completed transfer to localAccount`); + + try { + const memo = buildXCSMemo(offerArgs); + trace(memo); + + await sharedLocalAccount.transfer( + { + value: destAddr, + encoding: 'bech32', + chainId: /** @type {CosmosChainInfo} */ (osmosisChainInfo).chainId, + }, + { denom, value: amt.value }, + { memo }, + ); + void log(`completed transfer to ${destAddr}`); + } catch (e) { + return recoverFailedTransfer(e); + } + + seat.exit(); + void log(`transfer complete, seat exited`); +}; harden(swapIt); diff --git a/packages/orchestration/src/proposals/start-swap-anything.js b/packages/orchestration/src/proposals/start-swap-anything.js new file mode 100644 index 00000000000..f357232bcb7 --- /dev/null +++ b/packages/orchestration/src/proposals/start-swap-anything.js @@ -0,0 +1,133 @@ +import { + deeplyFulfilledObject, + makeTracer, + NonNullish, +} from '@agoric/internal'; +import { E } from '@endo/far'; + +/// + +/** + * @import {Installation} from '@agoric/zoe/src/zoeService/utils.js'; + * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; + * @import {start as StartFn} from '@agoric/orchestration/src/examples/send-anywhere.contract.js'; + */ + +const trace = makeTracer('StartSA', true); + +/** + * @param {BootstrapPowers & { + * installation: { + * consume: { + * swapAnything: Installation; + * }; + * }; + * instance: { + * produce: { + * swapAnything: Producer; + * }; + * }; + * issuer: { + * consume: { + * BLD: Issuer<'nat'>; + * IST: Issuer<'nat'>; + * }; + * }; + * }} powers + * @param {{ + * options: { + * chainInfo: Record; + * assetInfo: [Denom, DenomDetail & { brandKey?: string }][]; + * }; + * }} config + */ +export const startSwapAnything = async ( + { + consume: { + agoricNames, + board, + chainStorage, + chainTimerService, + cosmosInterchainService, + localchain, + startUpgradable, + }, + installation: { + consume: { swapAnything }, + }, + instance: { + produce: { swapAnything: produceInstance }, + }, + issuer: { + consume: { BLD, IST }, + }, + }, + { options: { chainInfo, assetInfo } }, +) => { + trace(startSwapAnything.name); + + const marshaller = await E(board).getReadonlyMarshaller(); + + const privateArgs = await deeplyFulfilledObject( + harden({ + agoricNames, + localchain, + marshaller, + orchestrationService: cosmosInterchainService, + storageNode: E(NonNullish(await chainStorage)).makeChildNode( + 'send-anywhere', + ), + timerService: chainTimerService, + chainInfo, + assetInfo, + }), + ); + + const issuerKeywordRecord = harden({ + BLD: await BLD, + IST: await IST, + }); + trace('issuerKeywordRecord', issuerKeywordRecord); + + const { instance } = await E(startUpgradable)({ + label: 'swap-anything', + installation: swapAnything, + issuerKeywordRecord, + privateArgs, + }); + produceInstance.resolve(instance); + trace('done'); +}; +harden(startSwapAnything); + +export const getManifest = ({ restoreRef }, { installationRef, options }) => { + return { + manifest: { + [startSwapAnything.name]: { + consume: { + agoricNames: true, + board: true, + chainStorage: true, + chainTimerService: true, + cosmosInterchainService: true, + localchain: true, + + startUpgradable: true, + }, + installation: { + consume: { swapAnything: true }, + }, + instance: { + produce: { swapAnything: true }, + }, + issuer: { + consume: { BLD: true, IST: true }, + }, + }, + }, + installations: { + swapAnything: restoreRef(installationRef), + }, + options, + }; +}; diff --git a/packages/orchestration/test/examples/swap-anything.test.ts b/packages/orchestration/test/examples/swap-anything.test.ts new file mode 100644 index 00000000000..27066c7fc4c --- /dev/null +++ b/packages/orchestration/test/examples/swap-anything.test.ts @@ -0,0 +1,141 @@ +import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; +import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js'; +import { E } from '@endo/far'; +import * as contractExports from '../../src/examples/swap-anything.contract.js'; +import { commonSetup } from '../supports.js'; + +const contractName = 'swap-anything'; +type StartFn = typeof contractExports.start; + +const config = { + xcsInformation: { + // A message that we know to be working + rawMsgNoNextMemo: + '{"wasm":{"contract":"osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8","msg":{"osmosis_swap":{"output_denom":"uosmo","slippage":{"twap":{"window_seconds":10,"slippage_percentage":"20"}},"receiver":"agoric1elueec97as0uwavlxpmj75u5w7yq9dgphq47zx","on_failed_delivery":"do_nothing"}}}}', + }, +}; + +const bootstrapOrchestration = async t => { + t.log('bootstrap, orchestration core-eval'); + const { + bootstrap, + commonPrivateArgs, + brands: { bld }, + utils: { inspectLocalBridge, pourPayment, transmitTransferAck }, + } = await commonSetup(t); + const vt = bootstrap.vowTools; + + const { zoe, bundleAndInstall } = await setUpZoeForTest(); + + t.log('contract coreEval', contractName); + + const installation: Installation = + await bundleAndInstall(contractExports); + + const storageNode = await E(bootstrap.storage.rootNode).makeChildNode( + contractName, + ); + + const swapKit = await E(zoe).startInstance( + installation, + { BLD: bld.issuer }, + {}, + { ...commonPrivateArgs, storageNode }, + ); + + return { + bootstrap, + commonPrivateArgs, + bld, + inspectLocalBridge, + pourPayment, + transmitTransferAck, + vt, + zoe, + installation, + storageNode, + swapKit, + }; +}; + +const buildOfferArgs = rawMsg => { + const { + wasm: { + contract, + msg: { + osmosis_swap: { + receiver, + output_denom: outDenom, + slippage: { + twap: { + slippage_percentage: slippagePercentage, + window_seconds: windowSeconds, + }, + }, + + on_failed_delivery: onFailedDelivery, + next_memo: nextMemo, + }, + }, + }, + } = JSON.parse(rawMsg); + + return { + destAddr: contract, + receiverAddr: receiver, + outDenom, + slippage: { slippagePercentage, windowSeconds }, + onFailedDelivery, + nextMemo, + }; +}; + +test('swap BLD for Osmo, receiver on Agoric', async t => { + const { + vt, + swapKit, + zoe, + pourPayment, + bld, + transmitTransferAck, + inspectLocalBridge, + } = await bootstrapOrchestration(t); + + const publicFacet = await E(zoe).getPublicFacet(swapKit.instance); + const inv = E(publicFacet).makeSendInvitation(); + const amt = await E(zoe).getInvitationDetails(inv); + t.is(amt.description, 'swap'); + + const anAmt = bld.units(3.5); + const Send = await pourPayment(anAmt); + const offerArgs = buildOfferArgs(config.xcsInformation.rawMsgNoNextMemo); + + const userSeat = await E(zoe).offer( + inv, + { give: { Send: anAmt } }, + { Send }, + offerArgs, + ); + await transmitTransferAck(); + await vt.when(E(userSeat).getOfferResult()); + + const history = inspectLocalBridge(); + t.log(history); + t.like(history, [ + { type: 'VLOCALCHAIN_ALLOCATE_ADDRESS' }, + { type: 'VLOCALCHAIN_EXECUTE_TX' }, + ]); + + t.like( + history.find(x => x.type === 'VLOCALCHAIN_EXECUTE_TX')?.messages?.[0], + { + '@type': '/ibc.applications.transfer.v1.MsgTransfer', + receiver: offerArgs.destAddr, // XCS contract has to be the one receiving the IBC message + sender: 'agoric1fakeLCAAddress', + memo: config.xcsInformation.rawMsgNoNextMemo, + }, + 'crosschain swap sent', + ); +}); + +test.todo('should throw when Osmosis not connected'); From 00b07f97569c0284dd0a22fdda1161f820f02510 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Wed, 30 Apr 2025 14:49:43 +0300 Subject: [PATCH 04/24] chore(orchestration): integrate address hooks chore: integrate address hooks, unit tests partially complete Refs: #8863 chore: add multichain tests for swapAnything with address hooks Refs: #8863 --- .../xcs-swap-anything/swap-anything.test.ts | 158 +++++++++++++++++- .../src/examples/swap-anything.contract.js | 93 ++++++++++- .../src/examples/swap-anything.flows.js | 79 ++++++++- .../src/proposals/start-swap-anything.js | 4 +- .../test/examples/swap-anything.test.ts | 57 +++++++ 5 files changed, 377 insertions(+), 14 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index f4de72029cd..733ffc30496 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -1,10 +1,15 @@ import anyTest from '@endo/ses-ava/prepare-endo.js'; import type { TestFn } from 'ava'; import { AmountMath } from '@agoric/ertp'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { makeDoOffer } from '../../tools/e2e-tools.js'; import { commonSetup, type SetupContextWithWallets } from '../support.js'; import { makeQueryClient } from '../../tools/query.js'; import starshipChainInfo from '../../starship-chain-info.js'; +import { + createFundedWalletAndClient, + makeIBCTransferMsg, +} from '../../tools/ibc-transfer.js'; const test = anyTest as TestFn; @@ -14,6 +19,69 @@ const contractName = 'swapAnything'; const contractBuilder = '../packages/builders/scripts/testing/init-swap-anything.js'; +const fundRemote = async ( + t, + destinationChain, + denomToTransfer = 'ubld', + amount = 100000000n, +) => { + const { retryUntilCondition, useChain } = t.context; + + const { client, address, wallet } = await createFundedWalletAndClient( + t.log, + destinationChain, + useChain, + ); + const balancesResult = await retryUntilCondition( + () => client.getAllBalances(address), + coins => !!coins?.length, + `Faucet balances found for ${address}`, + ); + console.log('Balances:', balancesResult); + + const { client: agoricClient, address: agoricAddress } = + await createFundedWalletAndClient(t.log, 'agoric', useChain); + + const balancesResultAg = await retryUntilCondition( + () => agoricClient.getAllBalances(agoricAddress), + coins => !!coins?.length, + `Faucet balances found for ${agoricAddress}`, + ); + console.log('Balances AGORIC:', balancesResultAg); + + const transferArgs = makeIBCTransferMsg( + { denom: denomToTransfer, value: amount }, + { address, chainName: destinationChain }, + { address: agoricAddress, chainName: 'agoric' }, + Date.now(), + useChain, + ); + console.log('Transfer Args:', transferArgs); + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await agoricClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ${denomToTransfer}`); + } + const { events: _events, ...txRest } = txRes; + console.log(txRest); + t.is(txRes.code, 0, `Transaction succeeded`); + t.log(`Funds transferred to ${agoricAddress}`); + + await retryUntilCondition( + () => client.getAllBalances(address), + coins => !!coins?.length, + `${denomToTransfer} transferred to ${address}`, + ); + + return { + client, + address, + wallet, + }; +}; + test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; @@ -24,7 +92,7 @@ test.before(async t => { await startContract(contractName, contractBuilder, commonBuilderOpts); }); -test('BLD for OSMO, receiver on Agoric', async t => { +test.serial('BLD for OSMO, receiver on Agoric', async t => { const { wallets, provisionSmartWallet, @@ -103,6 +171,94 @@ test('BLD for OSMO, receiver on Agoric', async t => { ); }); +test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { + const { wallets, vstorageClient, retryUntilCondition, useChain } = t.context; + const { getRestEndpoint, chain: cosmosChain } = useChain('cosmoshub'); + + const { address: cosmosHubAddr, client: cosmosHubClient } = await fundRemote( + t, + 'cosmoshub', + ); + + const cosmosHubApiUrl = await getRestEndpoint(); + const cosmosHubQueryClient = makeQueryClient(cosmosHubApiUrl); + + const { + transferChannel: { counterPartyChannelId }, + } = starshipChainInfo.agoric.connections[cosmosChain.chain_id]; + + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const { balances: balancesBefore } = await queryClient.queryBalances( + wallets.agoricReceiver, + ); + + const { hash: bldDenomOnHub } = await cosmosHubQueryClient.queryDenom( + `transfer/${counterPartyChannelId}`, + 'ubld', + ); + t.log({ bldDenomOnHub, counterPartyChannelId }); + + const { + sharedLocalAccount: { value: baseAddress }, + } = await vstorageClient.queryData('published.swap-anything'); + t.log(baseAddress); + + const orcContractReceiverAddress = encodeAddressHook(baseAddress, { + destAddr: 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', + receiverAddr: wallets.agoricReceiver, + outDenom: 'uosmo', + }); + + const transferArgs = makeIBCTransferMsg( + { denom: `ibc/${bldDenomOnHub}`, value: 125n }, + { address: orcContractReceiverAddress, chainName: 'agoric' }, + { address: cosmosHubAddr, chainName: 'cosmoshub' }, + Date.now(), + useChain, + ); + console.log('Transfer Args:', transferArgs); + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ibc/${bldDenomOnHub}`); + } + const { events: _events, ...txRest } = txRes; + console.log(txRest); + t.is(txRes.code, 0, `Transaction succeeded`); + t.log(`Funds transferred to ${orcContractReceiverAddress}`); + + const osmosisChainId = useChain('osmosis').chain.chain_id; + + const { + transferChannel: { channelId }, + } = starshipChainInfo.agoric.connections[osmosisChainId]; + + const { balances: agoricReceiverBalances } = await retryUntilCondition( + () => queryClient.queryBalances(wallets.agoricReceiver), + ({ balances }) => balances.length > balancesBefore.length, + 'Deposit reflected in localOrchAccount balance', + ); + t.log(agoricReceiverBalances); + + const { hash: expectedHash } = await queryClient.queryDenom( + `transfer/${channelId}`, + 'uosmo', + ); + + t.log('Expected denom hash:', expectedHash); + + t.regex(agoricReceiverBalances[0]?.denom, /^ibc/); + t.is( + agoricReceiverBalances[0]?.denom.split('ibc/')[1], + expectedHash, + 'got expected ibc denom hash', + ); +}); + test.after(async t => { const { deleteTestKeys } = t.context; deleteTestKeys(accounts); diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js index de7785809ff..f1b80fda603 100644 --- a/packages/orchestration/src/examples/swap-anything.contract.js +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -1,13 +1,19 @@ import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; +import { makeTracer } from '@agoric/internal'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; +import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js'; import { withOrchestration } from '../utils/start-helper.js'; import * as sharedFlows from './shared.flows.js'; -import { swapIt } from './swap-anything.flows.js'; +import { swapIt, swapAnythingViaHook } from './swap-anything.flows.js'; import { AnyNatAmountShape } from '../typeGuards.js'; import { registerChainsAndAssets } from '../utils/chain-hub-helper.js'; +const trace = makeTracer('SwapAnything.Contract'); + +const interfaceTODO = undefined; + /** * @import {Remote, Vow} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; @@ -65,12 +71,93 @@ export const contract = async ( makeLocalAccount(), ); - const swapAnything = orchestrate( + const swapAnythingOffer = orchestrate( 'swapAnything', { chainHub, sharedLocalAccountP, log, zoeTools }, swapIt, ); + const swapAnythingAddressHook = orchestrate( + 'swapAnythingViaHook', + { + chainHub, + sharedLocalAccountP, + log, + }, + swapAnythingViaHook, + ); + + const tap = zone.makeOnce('tapPosition', _key => { + console.log('making tap'); + return zone.exo('tap', interfaceTODO, { + /** + * @param {import('@agoric/vats').VTransferIBCEvent} event + */ + async receiveUpcall(event) { + await null; + trace('receiveUpcall', event); + + if (event.event !== 'writeAcknowledgement') return; + trace('Moving on...'); + /** + * Extract the incoming packet data. + * + * @type {import('@agoric/cosmic-proto/ibc/applications/transfer/v2/packet.js').FungibleTokenPacketData} + */ + const { + amount, + denom, // transfer/channel-1/ubld, uatom + receiver: origReceiver, + } = JSON.parse(atob(event.packet.data)); + + trace({ amount, denom, origReceiver }); + + const { baseAddress, query } = decodeAddressHook(origReceiver); + + /** + * @type {{ + * destAddr: string; + * receiverAddr: string; + * outDenom: string; + * }} + */ + // @ts-expect-error + const { destAddr, receiverAddr, outDenom } = query; + + trace({ + baseAddress, + destAddr, + receiverAddr, + outDenom, + }); + + if (!receiverAddr || !destAddr || !outDenom) return; + // Invoke the flow to perform swap and end up at the final destination. + return swapAnythingAddressHook( + { denom: 'ubld', amount }, + { + destAddr, + receiverAddr, + outDenom, // swapOutDenom + onFailedDelivery: 'do_nothing', + slippage: { + slippagePercentage: '20', + windowSeconds: 10, + }, + }, + ); + }, + }); + }); + + void vowTools.when(sharedLocalAccountP, async sharedLocalAccount => { + sharedLocalAccount.monitorTransfers(tap); + const encoded = await E(privateArgs.marshaller).toCapData({ + sharedLocalAccount: sharedLocalAccount.getAddress(), + }); + void E(privateArgs.storageNode).setValue(JSON.stringify(encoded)); + }); + const publicFacet = zone.exo( 'Send PF', M.interface('Send PF', { @@ -79,7 +166,7 @@ export const contract = async ( { makeSendInvitation() { return zcf.makeInvitation( - swapAnything, + swapAnythingOffer, 'swap', undefined, M.splitRecord({ give: SingleNatAmountRecord }), diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js index 2041a7ad5e9..6b2b7a5331f 100644 --- a/packages/orchestration/src/examples/swap-anything.flows.js +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -2,7 +2,7 @@ import { NonNullish, makeTracer } from '@agoric/internal'; import { Fail, makeError, q } from '@endo/errors'; import { M, mustMatch } from '@endo/patterns'; -const trace = makeTracer('SwapAnything'); +const trace = makeTracer('SwapAnything.Flow'); const { entries } = Object; @@ -22,7 +22,7 @@ const { entries } = Object; * @import {Vow} from '@agoric/vow'; * @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js'; * @import {ZoeTools} from '../utils/zoe-tools.js'; - * @import {Orchestrator, OrchestrationFlow, ChainHub, ChainInfo, CosmosChainInfo} from '../types.js'; + * @import {Orchestrator, OrchestrationFlow, ChainHub, CosmosChainInfo} from '../types.js'; */ const denomForBrand = async (orch, brand) => { @@ -101,12 +101,13 @@ export const swapIt = async ( { nextMemo: M.string() }, ), ); + void log('Begin swapIt'); const { receiverAddr, destAddr } = offerArgs; // NOTE the proposal shape ensures that the `give` is a single asset const { give } = seat.getProposal(); const [[_kw, amt]] = entries(give); - void log(`sending {${amt.value}} from osmosis to ${receiverAddr}`); + trace(`sending {${amt.value}} from osmosis to ${receiverAddr}`); const denom = await denomForBrand(orch, amt.brand); /** @@ -123,7 +124,7 @@ export const swapIt = async ( const recoverFailedTransfer = async e => { await withdrawToSeat(sharedLocalAccount, seat, give); const errorMsg = `IBC Transfer failed ${q(e)}`; - void log(`ERROR: ${errorMsg}`); + trace(`ERROR: ${errorMsg}`); seat.fail(errorMsg); throw makeError(errorMsg); }; @@ -133,11 +134,11 @@ export const swapIt = async ( connection.counterparty || Fail`No IBC connection to Osmosis`; - void log(`got info for chain: osmosis ${osmosisChainInfo}`); + trace(`got info for chain: osmosis ${osmosisChainInfo}`); trace(osmosisChainInfo); await localTransfer(seat, sharedLocalAccount, give); - void log(`completed transfer to localAccount`); + trace(`completed transfer to localAccount`); try { const memo = buildXCSMemo(offerArgs); @@ -152,12 +153,74 @@ export const swapIt = async ( { denom, value: amt.value }, { memo }, ); - void log(`completed transfer to ${destAddr}`); + trace(`completed transfer to ${destAddr}`); } catch (e) { return recoverFailedTransfer(e); } seat.exit(); - void log(`transfer complete, seat exited`); + trace(`transfer complete, seat exited`); }; harden(swapIt); + +/** + * @satisfies {OrchestrationFlow} + * @param {Orchestrator} _orch + * @param {object} ctx + * @param {GuestInterface} ctx.chainHub + * @param {Promise>} ctx.sharedLocalAccountP + * @param {{ denom: string; amount: string }} transferInfo + * @param {SwapInfo} memoArgs + */ +export const swapAnythingViaHook = async ( + _orch, + { chainHub, sharedLocalAccountP }, + { denom, amount }, + memoArgs, +) => { + mustMatch( + memoArgs, + M.splitRecord( + { + destAddr: M.string(), + receiverAddr: M.string(), + outDenom: M.string(), + onFailedDelivery: M.string(), + slippage: { slippagePercentage: M.string(), windowSeconds: M.number() }, + }, + { nextMemo: M.string() }, + ), + ); + + const { receiverAddr, destAddr } = memoArgs; + trace(`sending {${amount}} from osmosis to ${receiverAddr}`); + + /** + * @type {any} XXX methods returning vows + * https://github.com/Agoric/agoric-sdk/issues/9822 + */ + const sharedLocalAccount = await sharedLocalAccountP; + + const [_a, osmosisChainInfo, connection] = + await chainHub.getChainsAndConnection('agoric', 'osmosis'); + + connection.counterparty || Fail`No IBC connection to Osmosis`; + + trace(`got info for chain: osmosis ${osmosisChainInfo}`); + trace(osmosisChainInfo); + + const memo = buildXCSMemo(memoArgs); + + await sharedLocalAccount.transfer( + { + value: destAddr, + encoding: 'bech32', + chainId: /** @type {CosmosChainInfo} */ (osmosisChainInfo).chainId, + }, + { denom, value: BigInt(amount) }, + { memo }, + ); + + return 'Done'; +}; +harden(swapAnythingViaHook); diff --git a/packages/orchestration/src/proposals/start-swap-anything.js b/packages/orchestration/src/proposals/start-swap-anything.js index f357232bcb7..a4706e48291 100644 --- a/packages/orchestration/src/proposals/start-swap-anything.js +++ b/packages/orchestration/src/proposals/start-swap-anything.js @@ -10,7 +10,7 @@ import { E } from '@endo/far'; /** * @import {Installation} from '@agoric/zoe/src/zoeService/utils.js'; * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; - * @import {start as StartFn} from '@agoric/orchestration/src/examples/send-anywhere.contract.js'; + * @import {start as StartFn} from '@agoric/orchestration/src/examples/swap-anything.contract.js'; */ const trace = makeTracer('StartSA', true); @@ -75,7 +75,7 @@ export const startSwapAnything = async ( marshaller, orchestrationService: cosmosInterchainService, storageNode: E(NonNullish(await chainStorage)).makeChildNode( - 'send-anywhere', + 'swap-anything', ), timerService: chainTimerService, chainInfo, diff --git a/packages/orchestration/test/examples/swap-anything.test.ts b/packages/orchestration/test/examples/swap-anything.test.ts index 27066c7fc4c..9693c8bfaf5 100644 --- a/packages/orchestration/test/examples/swap-anything.test.ts +++ b/packages/orchestration/test/examples/swap-anything.test.ts @@ -1,8 +1,12 @@ import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js'; import { E } from '@endo/far'; +import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; +import { NonNullish } from '@agoric/internal'; import * as contractExports from '../../src/examples/swap-anything.contract.js'; import { commonSetup } from '../supports.js'; +import { buildVTransferEvent } from '../../tools/ibc-mocks.js'; const contractName = 'swap-anything'; type StartFn = typeof contractExports.start; @@ -22,6 +26,7 @@ const bootstrapOrchestration = async t => { commonPrivateArgs, brands: { bld }, utils: { inspectLocalBridge, pourPayment, transmitTransferAck }, + mocks: { transferBridge }, } = await commonSetup(t); const vt = bootstrap.vowTools; @@ -55,6 +60,7 @@ const bootstrapOrchestration = async t => { installation, storageNode, swapKit, + transferBridge, }; }; @@ -138,4 +144,55 @@ test('swap BLD for Osmo, receiver on Agoric', async t => { ); }); +test('trigger osmosis swap from an address hook', async t => { + const { + bootstrap: { storage }, + transferBridge, + inspectLocalBridge, + commonPrivateArgs, + } = await bootstrapOrchestration(t); + await eventLoopIteration(); + + const { sharedLocalAccount } = commonPrivateArgs.marshaller.fromCapData( + JSON.parse( + NonNullish(storage.data.get('mockChainStorageRoot.swap-anything')), + ), + ); + + t.deepEqual(sharedLocalAccount.value, 'agoric1fakeLCAAddress'); + + const memoArgs = buildOfferArgs(config.xcsInformation.rawMsgNoNextMemo); + t.log(memoArgs); + + await E(transferBridge).fromBridge( + buildVTransferEvent({ + event: 'writeAcknowledgement', + denom: 'ubld', + receiver: encodeAddressHook( + 'agoric1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp7zqht', + { + destAddr: memoArgs.destAddr, + receiverAddr: memoArgs.receiverAddr, + outDenom: memoArgs.outDenom, + }, + ), + }), + ); + await eventLoopIteration(); + + const history = inspectLocalBridge(); + t.log(history); + + t.like( + history.find(x => x.type === 'VLOCALCHAIN_EXECUTE_TX')?.messages?.[0], + { + '@type': '/ibc.applications.transfer.v1.MsgTransfer', + receiver: memoArgs.destAddr, // XCS contract has to be the one receiving the IBC message + sender: 'agoric1fakeLCAAddress', + memo: config.xcsInformation.rawMsgNoNextMemo, + }, + 'crosschain swap sent', + ); +}); + test.todo('should throw when Osmosis not connected'); From 668f415e94e4b3ab1d6c668c9c03b1509cdf69e0 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 6 May 2025 17:00:08 +0100 Subject: [PATCH 05/24] chore: minor improvements test: Automate XCS setup via ava test chore: improve error handling fix: style fixes from prettier Refs: #8863 chore: WIP ci setup Refs: #8863 --- .github/workflows/multichain-e2e.yml | 13 ++++ multichain-testing/ava.xcs.config.js | 6 ++ multichain-testing/package.json | 3 +- .../test/xcs-swap-anything/Makefile | 2 +- .../xcs-swap-anything/swap-anything.test.ts | 70 ++++++++++++++++++- 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 multichain-testing/ava.xcs.config.js diff --git a/.github/workflows/multichain-e2e.yml b/.github/workflows/multichain-e2e.yml index 0f2c16d195f..2ba1227bc53 100644 --- a/.github/workflows/multichain-e2e.yml +++ b/.github/workflows/multichain-e2e.yml @@ -16,6 +16,7 @@ on: - orchestration-staking-hermes - orchestration-queries-go-relayer - orchestration-queries-hermes + - swap-on-osmosis workflow_call: jobs: @@ -106,3 +107,15 @@ jobs: config: config.yaml test_command: yarn test:queries test_suite_name: orchestration-queries-hermes + + swap-on-osmosis: + name: Swap on Osmosis XCS contract + if: | + github.event_name == 'workflow_call' || + github.event_name == 'pull_request' || + (github.event_name == 'workflow_dispatch' && inputs.test_type == 'swap-on-osmosis') + uses: ./.github/workflows/multichain-e2e-template.yml + with: + config: config.xcs-swap-anything.yaml + test_command: yarn test:xcs + test_suite_name: swap-on-osmosis diff --git a/multichain-testing/ava.xcs.config.js b/multichain-testing/ava.xcs.config.js new file mode 100644 index 00000000000..5ff4bf094da --- /dev/null +++ b/multichain-testing/ava.xcs.config.js @@ -0,0 +1,6 @@ +import mainConfig from './ava.config.js'; + +export default { + ...mainConfig, + files: ['test/xcs-swap-anything/**/*.test.ts'], +}; diff --git a/multichain-testing/package.json b/multichain-testing/package.json index 5346f8898ac..f94afcc20a1 100644 --- a/multichain-testing/package.json +++ b/multichain-testing/package.json @@ -9,7 +9,8 @@ "test:main": "ava --config ava.rest.config.js", "test:fast-usdc": "ava --config ava.fusdc.config.js", "test:queries": "ava --config ava.queries.config.js", - "test:staking": "ava --config ava.staking.config.js" + "test:staking": "ava --config ava.staking.config.js", + "test:xcs": "ava --config ava.xcs.config.js" }, "packageManager": "yarn@4.9.1", "devDependencies": { diff --git a/multichain-testing/test/xcs-swap-anything/Makefile b/multichain-testing/test/xcs-swap-anything/Makefile index 2e68b607c21..4b340da2b70 100644 --- a/multichain-testing/test/xcs-swap-anything/Makefile +++ b/multichain-testing/test/xcs-swap-anything/Makefile @@ -1,4 +1,4 @@ -cli-hermes=kubectl exec -it hermes-agoric-osmosis-0 -c relayer -- hermes +cli-hermes=kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes exec-agd=kubectl exec -i agoriclocal-genesis-0 -c validator -- agd exec-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd cli-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 733ffc30496..9ce7fa6ca5d 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -10,6 +10,9 @@ import { createFundedWalletAndClient, makeIBCTransferMsg, } from '../../tools/ibc-transfer.js'; +import { execa } from 'execa'; +import path from 'path'; +import { fileURLToPath } from 'url'; const test = anyTest as TestFn; @@ -82,6 +85,55 @@ const fundRemote = async ( }; }; +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); + +const setupXcsContracts = async t => { + console.log('Setting XXC Contracts ...'); + try { + const scriptPath = path.resolve(dirname, '../../scripts/setup-xcs.sh'); + const { stdout } = await execa(scriptPath); + console.log('setup-xcs script output:', stdout); + } catch (error) { + t.fail(`setup-xcs script failed with error: ${error}`); + } +}; + +const createOsmosisPool = async t => { + console.log('Creating Osmosis Pool ...'); + try { + const scriptPath = path.resolve( + dirname, + '../../scripts/create-osmosis-pool.sh', + ); + const { stdout } = await execa(scriptPath); + console.log('create-osmosis-pool script output:', stdout); + } catch (error) { + t.fail(`create-osmosis-pool failed with error: ${error}`); + } +}; + +const setupXcsState = async t => { + console.log('Setting XXC State ...'); + try { + const { stdout } = await execa('make', ['tx-chain-channel-links'], { + cwd: dirname, + }); + console.log('tx-chain-channel-links target output:', stdout); + } catch (error) { + t.fail(`tx-chain-channel-links failed with error: ${error}`); + } + + try { + const { stdout } = await execa('make', ['tx-bec32-prefixes'], { + cwd: dirname, + }); + console.log('tx-bec32-prefixes target output:', stdout); + } catch (error) { + t.fail(`tx-bec32-prefixes failed with error: ${error}`); + } +}; + test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; @@ -90,8 +142,18 @@ test.before(async t => { console.log('WALLETS', wallets); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); + await setupXcsContracts(t); + await createOsmosisPool(t); + await setupXcsState(t); }); +/** + * We could use this test to extract the contract addresses from the osmosis container + * (see make print-wasm-info) and some other verifications using the queries that we + * see useful. + */ +test.todo('verify-xcs-boot-correctly'); + test.serial('BLD for OSMO, receiver on Agoric', async t => { const { wallets, @@ -171,7 +233,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); }); -test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { +test.skip('address hook - BLD for OSMO, receiver on Agoric', async t => { const { wallets, vstorageClient, retryUntilCondition, useChain } = t.context; const { getRestEndpoint, chain: cosmosChain } = useChain('cosmoshub'); @@ -239,7 +301,11 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { const { balances: agoricReceiverBalances } = await retryUntilCondition( () => queryClient.queryBalances(wallets.agoricReceiver), - ({ balances }) => balances.length > balancesBefore.length, + ({ balances }) => { + const balancesBeforeAmount = BigInt(balancesBefore[0]?.amount || 0); + const currentBalanceAmount = BigInt(balances[0]?.amount || 0); + return currentBalanceAmount > balancesBeforeAmount; + }, 'Deposit reflected in localOrchAccount balance', ); t.log(agoricReceiverBalances); From 2ffcdceb2f849d82895a810f79853a8b26504b06 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Wed, 7 May 2025 16:49:27 +0300 Subject: [PATCH 06/24] chore: remove address hooks related code Refs: #8863 --- .../xcs-swap-anything/swap-anything.test.ts | 4 + .../src/examples/swap-anything.contract.js | 88 ++----------------- .../src/examples/swap-anything.flows.js | 4 +- 3 files changed, 13 insertions(+), 83 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 9ce7fa6ca5d..84a0b12a1c5 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -233,6 +233,10 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); }); +/** + * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this + * until the ticket above is done + */ test.skip('address hook - BLD for OSMO, receiver on Agoric', async t => { const { wallets, vstorageClient, retryUntilCondition, useChain } = t.context; const { getRestEndpoint, chain: cosmosChain } = useChain('cosmoshub'); diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js index f1b80fda603..b11afd72e2c 100644 --- a/packages/orchestration/src/examples/swap-anything.contract.js +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -2,18 +2,15 @@ import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; import { makeTracer } from '@agoric/internal'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; -import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js'; import { withOrchestration } from '../utils/start-helper.js'; import * as sharedFlows from './shared.flows.js'; -import { swapIt, swapAnythingViaHook } from './swap-anything.flows.js'; +import { swapIt } from './swap-anything.flows.js'; import { AnyNatAmountShape } from '../typeGuards.js'; import { registerChainsAndAssets } from '../utils/chain-hub-helper.js'; const trace = makeTracer('SwapAnything.Contract'); -const interfaceTODO = undefined; - /** * @import {Remote, Vow} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; @@ -28,9 +25,8 @@ export const SingleNatAmountRecord = M.and( harden(SingleNatAmountRecord); /** - * Send assets currently in an ERTP purse to an account on another chain. This - * currently supports IBC and CCTP transfers. It could eventually support other - * protocols, like Axelar GMP or IBC Eureka. + * Swap assets that are currently in an ERTP purse against another cosmos asset + * by using an Osmosis pool then have the swap output routed to any address * * Orchestration contract to be wrapped by withOrchestration for Zoe * @@ -55,7 +51,8 @@ export const contract = async ( // UNTIL https://github.com/Agoric/agoric-sdk/issues/9066 const logNode = E(privateArgs.storageNode).makeChildNode('log'); /** @type {(msg: string) => Vow} */ - const log = msg => vowTools.watch(E(logNode).setValue(msg)); + const log = msg => + vowTools.watch(E(logNode).setValue(JSON.stringify({ msg }))); const makeLocalAccount = orchestrate( 'makeLocalAccount', @@ -77,85 +74,12 @@ export const contract = async ( swapIt, ); - const swapAnythingAddressHook = orchestrate( - 'swapAnythingViaHook', - { - chainHub, - sharedLocalAccountP, - log, - }, - swapAnythingViaHook, - ); - - const tap = zone.makeOnce('tapPosition', _key => { - console.log('making tap'); - return zone.exo('tap', interfaceTODO, { - /** - * @param {import('@agoric/vats').VTransferIBCEvent} event - */ - async receiveUpcall(event) { - await null; - trace('receiveUpcall', event); - - if (event.event !== 'writeAcknowledgement') return; - trace('Moving on...'); - /** - * Extract the incoming packet data. - * - * @type {import('@agoric/cosmic-proto/ibc/applications/transfer/v2/packet.js').FungibleTokenPacketData} - */ - const { - amount, - denom, // transfer/channel-1/ubld, uatom - receiver: origReceiver, - } = JSON.parse(atob(event.packet.data)); - - trace({ amount, denom, origReceiver }); - - const { baseAddress, query } = decodeAddressHook(origReceiver); - - /** - * @type {{ - * destAddr: string; - * receiverAddr: string; - * outDenom: string; - * }} - */ - // @ts-expect-error - const { destAddr, receiverAddr, outDenom } = query; - - trace({ - baseAddress, - destAddr, - receiverAddr, - outDenom, - }); - - if (!receiverAddr || !destAddr || !outDenom) return; - // Invoke the flow to perform swap and end up at the final destination. - return swapAnythingAddressHook( - { denom: 'ubld', amount }, - { - destAddr, - receiverAddr, - outDenom, // swapOutDenom - onFailedDelivery: 'do_nothing', - slippage: { - slippagePercentage: '20', - windowSeconds: 10, - }, - }, - ); - }, - }); - }); - void vowTools.when(sharedLocalAccountP, async sharedLocalAccount => { - sharedLocalAccount.monitorTransfers(tap); const encoded = await E(privateArgs.marshaller).toCapData({ sharedLocalAccount: sharedLocalAccount.getAddress(), }); void E(privateArgs.storageNode).setValue(JSON.stringify(encoded)); + trace('Localchain account information published', encoded); }); const publicFacet = zone.exo( diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js index 6b2b7a5331f..ef3f26bd503 100644 --- a/packages/orchestration/src/examples/swap-anything.flows.js +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -75,7 +75,6 @@ const buildXCSMemo = swapInfo => { * @param {SwapInfo} offerArgs */ -// Given USDC, swap to desired token with slippage // Ref: https://github.com/osmosis-labs/osmosis/tree/main/cosmwasm/contracts/crosschain-swaps#via-ibc export const swapIt = async ( orch, @@ -164,6 +163,9 @@ export const swapIt = async ( harden(swapIt); /** + * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51 is done, we + * can't demonstrate this + * * @satisfies {OrchestrationFlow} * @param {Orchestrator} _orch * @param {object} ctx From b2bff31f0ef49a9a4be6c6c5eecbb0007448b481 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Wed, 7 May 2025 18:40:17 +0300 Subject: [PATCH 07/24] test(orchestration): extend xcs multichain test cases chore: address account sequence mismatch chore: refactor osmosis swap test and script to remove hardcoded variables Additional optimizations were included to handle json objects A new shell script replaced the use of a makefile to set the osmosis XCS state Rebase conflicts handled test: verify osmosis xcs state Conflicts handled test: swap BLD for OSMO with receiver on CosmosHub ref: https://github.com/Agoric/agoric-sdk/issues/8863 --- .../scripts/create-osmosis-pool.sh | 100 +++--- .../scripts/setup-xcs-channel-link.sh | 85 +++++ .../scripts/setup-xcs-prefix.sh | 73 +++++ multichain-testing/scripts/setup-xcs.sh | 5 +- .../xcs-swap-anything/swap-anything.test.ts | 300 ++++++++++++++++-- 5 files changed, 482 insertions(+), 81 deletions(-) create mode 100755 multichain-testing/scripts/setup-xcs-channel-link.sh create mode 100755 multichain-testing/scripts/setup-xcs-prefix.sh diff --git a/multichain-testing/scripts/create-osmosis-pool.sh b/multichain-testing/scripts/create-osmosis-pool.sh index 2b0aa74d251..821a362e631 100755 --- a/multichain-testing/scripts/create-osmosis-pool.sh +++ b/multichain-testing/scripts/create-osmosis-pool.sh @@ -3,15 +3,17 @@ set -euo pipefail shopt -s expand_aliases -alias agoric-exec="kubectl exec -i agoriclocal-genesis-0 -c validator -- agd" +alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" +alias agoric-exec="kubectl exec -i agoriclocal-genesis-0 -c validator -- agd" alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" -alias osmo-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" AGORIC_WALLET="test1" AGORIC_ADDRESS=$(agoric-exec keys show ${AGORIC_WALLET} -a) OSMOSIS_WALLET="test1" OSMOSIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_WALLET} -a) +SWAPROUTER_OWNER_WALLET="genesis" +SWAPROUTER_OWNER_ADDRESS=$(osmosis-exec keys show ${SWAPROUTER_OWNER_WALLET} -a) CHANNEL_INFO=$(hermes-exec --json query channels --show-counterparty --chain agoriclocal \ | jq '[.][] | select(.result) | .result[] | select(.chain_id_b == "osmosislocal")') @@ -19,22 +21,22 @@ AGORIC_OSMOSIS_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_a') OSMOSIS_AGORIC_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_b') AGORIC_OSMOSIS_PORT="transfer" -AGORIC_TOKEN_DENOM="ubld" -AGORIC_TOKEN_AMOUNT="250000000000" +AGORIC_TOKEN_DENOM="$1" +AGORIC_TOKEN_TRANSFER_AMOUNT="250000000000" IBC_DENOM=$(echo -n "$AGORIC_OSMOSIS_PORT/$OSMOSIS_AGORIC_CHANNEL/$AGORIC_TOKEN_DENOM" | shasum -a 256 | awk '{print toupper($1)}') -POOL_ASSET_1_DENOM="uosmo" -POOL_ASSET_1_AMOUNT="250000" -POOL_ASSET_1_WEIGHT="1" -POOL_ASSET_2_DENOM="ibc/$IBC_DENOM" -POOL_ASSET_2_AMOUNT="250000" -POOL_ASSET_2_WEIGHT="1" +TOKEN_IN_DENOM="ibc/$IBC_DENOM" +TOKEN_IN_AMOUNT="$2" +TOKEN_IN_WEIGHT="$3" +TOKEN_OUT_DENOM="$4" +TOKEN_OUT_AMOUNT="$5" +TOKEN_OUT_WEIGHT="$6" SWAP_FEE="0.01" -EXIT_FEE="0.00", +EXIT_FEE="0.00" FUTURE_GOVERNOR="" -POOL_CONFIG_FILE="$POOL_ASSET_1_DENOM-$AGORIC_TOKEN_DENOM-pool-config.json" +POOL_CONFIG_FILE="$AGORIC_TOKEN_DENOM-$TOKEN_OUT_DENOM-pool-config.json" POOL_CONFIG_DEST="/opt/$POOL_CONFIG_FILE" MAX_RETRIES="5" @@ -42,10 +44,10 @@ DELAY="5" echo "Generating pool configuration file ..." jq -n \ - --arg weight1 "${POOL_ASSET_1_WEIGHT}${POOL_ASSET_1_DENOM}" \ - --arg weight2 "${POOL_ASSET_2_WEIGHT}${POOL_ASSET_2_DENOM}" \ - --arg amount1 "${POOL_ASSET_1_AMOUNT}${POOL_ASSET_1_DENOM}" \ - --arg amount2 "${POOL_ASSET_2_AMOUNT}${POOL_ASSET_2_DENOM}" \ + --arg weight1 "${TOKEN_IN_WEIGHT}${TOKEN_IN_DENOM}" \ + --arg weight2 "${TOKEN_OUT_WEIGHT}${TOKEN_OUT_DENOM}" \ + --arg amount1 "${TOKEN_IN_AMOUNT}${TOKEN_IN_DENOM}" \ + --arg amount2 "${TOKEN_OUT_AMOUNT}${TOKEN_OUT_DENOM}" \ --arg swapFee "$SWAP_FEE" \ --arg exitFee "$EXIT_FEE" \ --arg futureGovernor "$FUTURE_GOVERNOR" \ @@ -61,13 +63,13 @@ echo "Verifying if Agoric wallet has enough funds ..." agoric_balance_json=$(agoric-exec query bank balances $AGORIC_ADDRESS --denom $AGORIC_TOKEN_DENOM -o json) agoric_balance=$(jq -r '.amount' <<< "$agoric_balance_json") -if [ "$agoric_balance" -le "$AGORIC_TOKEN_AMOUNT" ]; then +if [ "$agoric_balance" -le "$AGORIC_TOKEN_TRANSFER_AMOUNT" ]; then echo "Balance is NOT sufficient. Exiting..." exit 1 fi echo "Starting IBC transfer from Agoric to Osmosis ..." -agoric-exec tx ibc-transfer transfer $AGORIC_OSMOSIS_PORT $AGORIC_OSMOSIS_CHANNEL $OSMOSIS_ADDRESS ${AGORIC_TOKEN_AMOUNT}${AGORIC_TOKEN_DENOM} --from $AGORIC_ADDRESS --yes +agoric-exec tx ibc-transfer transfer $AGORIC_OSMOSIS_PORT $AGORIC_OSMOSIS_CHANNEL $OSMOSIS_ADDRESS ${AGORIC_TOKEN_TRANSFER_AMOUNT}${AGORIC_TOKEN_DENOM} --from $AGORIC_ADDRESS --yes echo "Verifying if Osmosis wallet has the funds ..." for ((i = 1; i <= MAX_RETRIES; i++)); do @@ -75,14 +77,14 @@ for ((i = 1; i <= MAX_RETRIES; i++)); do osmosis_balances_json=$(osmosis-exec query bank balances $OSMOSIS_ADDRESS -o json) - balance_1=$(jq -r --arg denom "$POOL_ASSET_1_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") - balance_2=$(jq -r --arg denom "$POOL_ASSET_2_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") + balance_1=$(jq -r --arg denom "$TOKEN_IN_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") + balance_2=$(jq -r --arg denom "$TOKEN_OUT_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") # If not found, treat as zero balance_1=${balance_1:-0} balance_2=${balance_2:-0} - if [[ "$balance_1" -ge "$POOL_ASSET_1_AMOUNT" && "$balance_2" -ge "$POOL_ASSET_2_AMOUNT" ]]; then + if [[ "$balance_1" -ge "$TOKEN_IN_AMOUNT" && "$balance_2" -ge "$TOKEN_OUT_AMOUNT" ]]; then echo "Sufficient funds available." break fi @@ -126,41 +128,35 @@ for ((i = 1; i <= MAX_RETRIES; i++)); do sleep $DELAY done -SWAPROUTER_OWNER="genesis" -SWAPROUTER_OWNER_ADDRESS=$(osmosis-exec keys show ${SWAPROUTER_OWNER} -a) -SWAPROUTER_ADDRESS=$(osmo-cli "jq -r '.swaprouter.address' /contract-info.json") - +SWAPROUTER_ADDRESS=$(osmosis-cli "jq -r '.swaprouter.address' /contract-info.json") POOL_ID=$(jq -r '.pool | .id' <<< "$pool_info") -POOL_OUTPUT_DENOM=$POOL_ASSET_1_DENOM -POOL_INPUT_DENOM=$POOL_ASSET_2_DENOM - -SET_ROUTE_JSON=$( - cat << EOF -{ - "set_route": { - "input_denom": "$POOL_INPUT_DENOM", - "output_denom": "$POOL_OUTPUT_DENOM", - "pool_route": [ - { - "pool_id": "$POOL_ID", - "token_out_denom": "$POOL_OUTPUT_DENOM" - } - ] - } -} -EOF -) -GET_ROUTE_JSON=$( - cat << EOF -{ +SET_ROUTE_JSON=$(jq -n \ + --arg tokenIn "$TOKEN_IN_DENOM" \ + --arg tokenOut "$TOKEN_OUT_DENOM" \ + --arg poolId "$POOL_ID" \ + '{ + set_route: { + input_denom: $tokenIn, + output_denom: $tokenOut, + pool_route: [ + { + pool_id: $poolId, + token_out_denom: $tokenOut + } + ] + } + }') + +GET_ROUTE_JSON=$(jq -n \ + --arg tokenIn "$TOKEN_IN_DENOM" \ + --arg tokenOut "$TOKEN_OUT_DENOM" \ + '{ "get_route": { - "input_denom": "$POOL_INPUT_DENOM", - "output_denom": "$POOL_OUTPUT_DENOM" + "input_denom": $tokenIn, + "output_denom": $tokenOut } -} -EOF -) +}') echo "Storing pool on swaprouter contract ..." osmosis-exec tx wasm execute "$SWAPROUTER_ADDRESS" "$SET_ROUTE_JSON" --from "$SWAPROUTER_OWNER_ADDRESS" --chain-id osmosislocal --yes --fees 1000uosmo diff --git a/multichain-testing/scripts/setup-xcs-channel-link.sh b/multichain-testing/scripts/setup-xcs-channel-link.sh new file mode 100755 index 00000000000..c2aae3094b5 --- /dev/null +++ b/multichain-testing/scripts/setup-xcs-channel-link.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +set -euo pipefail +shopt -s expand_aliases + +alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" +alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" +alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" + +REGISTRY_ADDRESS=$(osmosis-cli "jq -r '.crosschain_registry.address' /contract-info.json") + +CHAIN_A="$1" +CHAIN_B="$2" + +CHANNEL_INFO=$(hermes-exec --json query channels --show-counterparty --chain "${CHAIN_A}local" \ + | jq --arg CHAIN_B_LOCAL "${CHAIN_B}local" '.result[] | select(.chain_id_b == $CHAIN_B_LOCAL)') + +CHAIN_A_CHAIN_B_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_a') +CHAIN_B_CHAIN_A_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_b') + +OSMOSIS_GENESIS_WALLET="genesis" +OSMOSIS_GENESIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_GENESIS_WALLET} -a) + +MAX_RETRIES="5" +DELAY="5" + +MODIFY_CHAIN_CHANNEL_LINKS=$(jq -n \ + --arg chainA "$CHAIN_A" \ + --arg chainB "$CHAIN_B" \ + --arg channelA "$CHAIN_A_CHAIN_B_CHANNEL" \ + --arg channelB "$CHAIN_B_CHAIN_A_CHANNEL" \ + '{ + modify_chain_channel_links: { + operations: [ + { + operation: "set", + source_chain: $chainA, + destination_chain: $chainB, + channel_id: $channelA + }, + { + operation: "set", + source_chain: $chainB, + destination_chain: $chainA, + channel_id: $channelB + } + ]} +}') + +GET_CHAIN_CHANNEL_LINKS=$(jq -n \ + --arg chainA "$CHAIN_A" \ + --arg chainB "$CHAIN_B" \ + '{ + get_channel_from_chain_pair: { + source_chain: $chainA, + destination_chain: $chainB, + } +}') + +echo "Modifying chain channel links ..." +osmosis-exec tx wasm execute "$REGISTRY_ADDRESS" "$MODIFY_CHAIN_CHANNEL_LINKS" --from "$OSMOSIS_GENESIS_ADDRESS" --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal + +echo "Querying chain channel links ..." +( + set +e + + for ((i = 1; i <= MAX_RETRIES; i++)); do + echo "Attempt $i of $MAX_RETRIES..." + chain_channel_link=$(osmosis-exec query wasm contract-state smart "$REGISTRY_ADDRESS" "$GET_CHAIN_CHANNEL_LINKS" 2> /dev/null) + + if [[ $? -eq 0 && $chain_channel_link = "{\"data\":\"$CHAIN_A_CHAIN_B_CHANNEL\"}" ]]; then + echo "Chain channel link found:" + echo "$chain_channel_link" + break + fi + + if [[ $i -eq MAX_RETRIES ]]; then + echo "Chain channel link not registered after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Query failed. Waiting $DELAY seconds before retrying..." + sleep "$DELAY" + done +) diff --git a/multichain-testing/scripts/setup-xcs-prefix.sh b/multichain-testing/scripts/setup-xcs-prefix.sh new file mode 100755 index 00000000000..37b328cdcde --- /dev/null +++ b/multichain-testing/scripts/setup-xcs-prefix.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +set -euo pipefail +shopt -s expand_aliases + +alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" +alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" +alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" + +REGISTRY_ADDRESS=$(osmosis-cli "jq -r '.crosschain_registry.address' /contract-info.json") + +OSMOSIS_GENESIS_WALLET="genesis" +OSMOSIS_GENESIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_GENESIS_WALLET} -a) + +MAX_RETRIES="5" +DELAY="5" + +MODIFY_BECH32_PREFIXES=$(jq -n \ + '{ + modify_bech32_prefixes: { + operations: [ + { + operation: "set", + chain_name: "osmosis", + prefix: "osmo" + }, + { + operation: "set", + chain_name: "agoric", + prefix: "agoric" + }, + { + operation: "set", + chain_name: "cosmoshub", + prefix: "cosmos" + } + ] + } +}') + +GET_BECH32_PREFIXES=$(jq -n \ + '{ + get_bech32_prefix_from_chain_name: { + chain_name: "osmosis", + } +}') + +echo "Modifying prefixes ..." +osmosis-exec tx wasm execute "$REGISTRY_ADDRESS" "$MODIFY_BECH32_PREFIXES" --from "$OSMOSIS_GENESIS_ADDRESS" --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal + +echo "Querying prefixes ..." +( + set +e + + for ((i = 1; i <= MAX_RETRIES; i++)); do + echo "Attempt $i of $MAX_RETRIES..." + chain_channel_link=$(osmosis-exec query wasm contract-state smart "$REGISTRY_ADDRESS" "$GET_BECH32_PREFIXES" 2> /dev/null) + + if [[ $? -eq 0 && $chain_channel_link = '{"data":"osmo"}' ]]; then + echo "Prefixes found:" + echo "$chain_channel_link" + break + fi + + if [[ $i -eq MAX_RETRIES ]]; then + echo "Prefixes not registered after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Query failed. Waiting $DELAY seconds before retrying..." + sleep "$DELAY" + done +) diff --git a/multichain-testing/scripts/setup-xcs.sh b/multichain-testing/scripts/setup-xcs.sh index 9753d05893f..53c0c3b727a 100755 --- a/multichain-testing/scripts/setup-xcs.sh +++ b/multichain-testing/scripts/setup-xcs.sh @@ -6,6 +6,8 @@ shopt -s expand_aliases alias osmo-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" alias osmo-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" +OSMOSIS_BRANCH="$1" + RPC=http://localhost:26655 TX_FLAGS="--keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal" OWNER=genesis @@ -66,8 +68,9 @@ cat ./scripts/download-wasm-artifacts.sh | osmo-cli "tee /download-wasm-artifact echo "Set newly created file's permissions..." osmo-cli "chmod 755 /download-wasm-artifacts.sh" +# Pass branch as argument TODO echo "Download artifacts for XCS..." -osmo-cli "/download-wasm-artifacts.sh osmosis-labs osmosis main tests/ibc-hooks/bytecode /wasm-artifacts crosschain_swaps.wasm swaprouter.wasm crosschain_registry.wasm" +osmo-cli "/download-wasm-artifacts.sh osmosis-labs osmosis $OSMOSIS_BRANCH tests/ibc-hooks/bytecode /wasm-artifacts crosschain_swaps.wasm swaprouter.wasm crosschain_registry.wasm" echo "Storing Swaprouter code..." osmo-exec tx wasm store /wasm-artifacts/swaprouter.wasm --from $OWNER $TX_FLAGS diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 84a0b12a1c5..03918ccfb5d 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -2,7 +2,7 @@ import anyTest from '@endo/ses-ava/prepare-endo.js'; import type { TestFn } from 'ava'; import { AmountMath } from '@agoric/ertp'; import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; -import { makeDoOffer } from '../../tools/e2e-tools.js'; +import { makeBlockTool, makeDoOffer } from '../../tools/e2e-tools.js'; import { commonSetup, type SetupContextWithWallets } from '../support.js'; import { makeQueryClient } from '../../tools/query.js'; import starshipChainInfo from '../../starship-chain-info.js'; @@ -13,6 +13,7 @@ import { import { execa } from 'execa'; import path from 'path'; import { fileURLToPath } from 'url'; +import { makeHttpClient } from '../../tools/makeHttpClient.js'; const test = anyTest as TestFn; @@ -89,10 +90,11 @@ const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); const setupXcsContracts = async t => { - console.log('Setting XXC Contracts ...'); + console.log('Setting XCS Contracts ...'); + const osmosisBranch = 'main'; try { const scriptPath = path.resolve(dirname, '../../scripts/setup-xcs.sh'); - const { stdout } = await execa(scriptPath); + const { stdout } = await execa(scriptPath, [osmosisBranch]); console.log('setup-xcs script output:', stdout); } catch (error) { t.fail(`setup-xcs script failed with error: ${error}`); @@ -101,58 +103,203 @@ const setupXcsContracts = async t => { const createOsmosisPool = async t => { console.log('Creating Osmosis Pool ...'); + const tokenInDenom = 'ubld'; + const tokenInAmount = '250000'; + const tokenInWeight = '1'; + const tokenOutDenom = 'uosmo'; + const tokenOutAmount = '250000'; + const tokenOutWeight = '1'; try { const scriptPath = path.resolve( dirname, '../../scripts/create-osmosis-pool.sh', ); - const { stdout } = await execa(scriptPath); + const { stdout } = await execa(scriptPath, [ + tokenInDenom, + tokenInAmount, + tokenInWeight, + tokenOutDenom, + tokenOutAmount, + tokenOutWeight, + ]); console.log('create-osmosis-pool script output:', stdout); } catch (error) { t.fail(`create-osmosis-pool failed with error: ${error}`); } }; -const setupXcsState = async t => { - console.log('Setting XXC State ...'); +const setupXcsChannelLink = async (t, chainA, chainB) => { + console.log('Setting XCS Channel Links ...'); try { - const { stdout } = await execa('make', ['tx-chain-channel-links'], { - cwd: dirname, - }); - console.log('tx-chain-channel-links target output:', stdout); + const scriptPath = path.resolve( + dirname, + '../../scripts/setup-xcs-channel-link.sh', + ); + const { stdout } = await execa(scriptPath, [chainA, chainB]); + console.log('channel link setup output:', stdout); } catch (error) { - t.fail(`tx-chain-channel-links failed with error: ${error}`); + t.fail(`channel link setup failed with error: ${error}`); } +}; +const setupXcsPrefix = async t => { + console.log('Setting XCS Prefixes ...'); try { - const { stdout } = await execa('make', ['tx-bec32-prefixes'], { - cwd: dirname, - }); - console.log('tx-bec32-prefixes target output:', stdout); + const scriptPath = path.resolve( + dirname, + '../../scripts/setup-xcs-prefix.sh', + ); + const { stdout } = await execa(scriptPath); + console.log('prefix setup output:', stdout); } catch (error) { - t.fail(`tx-bec32-prefixes failed with error: ${error}`); + t.fail(`prefix setup failed with error: ${error}`); } }; +const getXcsContractsAddress = async () => { + const osmosisCLI = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; + + const registryQuery = `${osmosisCLI} "jq -r '.crosschain_registry.address' /contract-info.json"`; + const swaprouterQuery = `${osmosisCLI} "jq -r '.swaprouter.address' /contract-info.json"`; + const swapQuery = `${osmosisCLI} "jq -r '.crosschain_swaps.address' /contract-info.json"`; + + const { stdout: registryAddress } = await execa(registryQuery, { + shell: true, + }); + const { stdout: swaprouterAddress } = await execa(swaprouterQuery, { + shell: true, + }); + const { stdout: swapAddress } = await execa(swapQuery, { shell: true }); + + return { registryAddress, swaprouterAddress, swapAddress }; +}; + +const getXcsState = async () => { + const { registryAddress } = await getXcsContractsAddress(); + + const osmosisExecQuery = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + + const channelObj = { + get_channel_from_chain_pair: { + source_chain: 'osmosis', + destination_chain: 'agoric', + }, + }; + const channelJson = `'${JSON.stringify(channelObj)}'`; + const channelQuery = `${osmosisExecQuery} ${registryAddress} ${channelJson}`; + + const { stdout: channel } = await execa(channelQuery, { + shell: true, + }); + + const prefixObj = { + get_bech32_prefix_from_chain_name: { + chain_name: 'osmosis', + }, + }; + const prefixJson = `'${JSON.stringify(prefixObj)}'`; + const prefixQuery = `${osmosisExecQuery} ${registryAddress} ${prefixJson}`; + + const { stdout: prefix } = await execa(prefixQuery, { + shell: true, + }); + + const channelData = JSON.parse(channel).data; + const prefixData = JSON.parse(prefix).data; + + return { channelData, prefixData }; +}; + +const getPoolRoute = async () => { + const { swaprouterAddress } = await getXcsContractsAddress(); + + const osmosisExecQuery = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + + const routeObj = { + get_route: { + input_denom: + 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', + output_denom: 'uosmo', + }, + }; + const routeJson = `'${JSON.stringify(routeObj)}'`; + const routeQuery = `${osmosisExecQuery} ${swaprouterAddress} ${routeJson}`; + + const { stdout } = await execa(routeQuery, { + shell: true, + }); + + const routeData = JSON.parse(stdout).data; + const route = routeData.pool_route[routeData.pool_route.length - 1]; + + return route; +}; + +const getPool = async poolId => { + const osmosisExec = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd'; + + const poolQuery = `${osmosisExec} query gamm pool ${poolId}`; + + const { stdout } = await execa(poolQuery, { + shell: true, + }); + + const pool = JSON.parse(stdout).pool; + + return pool; +}; + test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; + const { waitForBlock } = makeBlockTool({ + rpc: makeHttpClient('http://localhost:26657', fetch), + delay: ms => new Promise(resolve => setTimeout(resolve, ms)), + }); await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); console.log('WALLETS', wallets); - t.context = { ...common, wallets }; + // @ts-expect-error type + t.context = { ...common, wallets, waitForBlock }; await startContract(contractName, contractBuilder, commonBuilderOpts); await setupXcsContracts(t); await createOsmosisPool(t); - await setupXcsState(t); + await setupXcsChannelLink(t, 'agoric', 'osmosis'); + await setupXcsPrefix(t); }); -/** - * We could use this test to extract the contract addresses from the osmosis container - * (see make print-wasm-info) and some other verifications using the queries that we - * see useful. - */ -test.todo('verify-xcs-boot-correctly'); +test.serial('test osmosis xcs state', async t => { + const { useChain } = t.context; + + // verify if Osmosis XCS contracts were instantiated + const { registryAddress, swaprouterAddress, swapAddress } = + await getXcsContractsAddress(); + t.assert(registryAddress, 'crosschain_registry contract address not found'); + t.assert(swaprouterAddress, 'swaprouter contract address not found'); + t.assert(swapAddress, 'crosschain_swaps contract address not found'); + + // verify if Osmosis XCS State was modified + const osmosisChainId = useChain('osmosis').chain.chain_id; + const { + transferChannel: { channelId }, + } = starshipChainInfo.agoric.connections[osmosisChainId]; + + const { channelData, prefixData: osmosisPrefix } = await getXcsState(); + + t.is(osmosisPrefix, 'osmo'); + t.is(channelData, channelId); + + const { pool_id, token_out_denom } = await getPoolRoute(); + t.is(token_out_denom, 'uosmo'); + + // verify if Osmosis pool was created + const pool = await getPool(pool_id); + t.assert(pool); +}); test.serial('BLD for OSMO, receiver on Agoric', async t => { const { @@ -177,6 +324,8 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { transferChannel: { channelId }, } = starshipChainInfo.agoric.connections[osmosisChainId]; + const { swapAddress } = await getXcsContractsAddress(); + const doOffer = makeDoOffer(wdUser); // Verify deposit @@ -201,8 +350,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { }, offerArgs: { // TODO: get the contract address dynamically - destAddr: - 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', + destAddr: swapAddress, receiverAddr: wallets.agoricReceiver, outDenom: 'uosmo', slippage: { slippagePercentage: '20', windowSeconds: 10 }, @@ -213,7 +361,11 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { const { balances: agoricReceiverBalances } = await retryUntilCondition( () => queryClient.queryBalances(wallets.agoricReceiver), - ({ balances }) => balances.length > balancesBefore.length, + ({ balances }) => { + const balancesBeforeAmount = BigInt(balancesBefore[0]?.amount || 0); + const currentBalanceAmount = BigInt(balances[0]?.amount || 0); + return currentBalanceAmount > balancesBeforeAmount; + }, 'Deposit reflected in localOrchAccount balance', ); t.log(agoricReceiverBalances); @@ -233,6 +385,96 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); }); +test.serial('BLD for OSMO, receiver on CosmosHub', async t => { + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + const { client, address } = await createFundedWalletAndClient( + t.log, + 'cosmoshub', + useChain, + ); + + const balancesResult = await retryUntilCondition( + () => client.getAllBalances(address), + coins => !!coins?.length, + `Faucet balances found for ${address}`, + ); + console.log('Balances:', balancesResult); + + await setupXcsChannelLink(t, 'osmosis', 'cosmoshub'); + + // Provision the Agoric smart wallet + const agoricAddr = wallets.agoricSender; + const wdUser = await provisionSmartWallet(agoricAddr, { + BLD: 1000n, + IST: 1000n, + }); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + const { swapAddress } = await getXcsContractsAddress(); + + const doOffer = makeDoOffer(wdUser); + + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const bldBrand = Object.fromEntries(brands).BLD; + const swapInAmount = AmountMath.make(bldBrand, 125n); + + // Send swap offer + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; + await doOffer({ + id: makeAccountOfferId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeSendInvitation']], + }, + offerArgs: { + // TODO: get the contract address dynamically + destAddr: swapAddress, + receiverAddr: address, + outDenom: 'uosmo', + slippage: { slippagePercentage: '20', windowSeconds: 10 }, + onFailedDelivery: 'do_nothing', + }, + proposal: { give: { Send: swapInAmount } }, + }); + + const balancesResultAfter = await retryUntilCondition( + () => client.getAllBalances(address), + coins => coins?.length > 1, + `Faucet balances found for ${address}`, + ); + console.log('Balances:', balancesResultAfter); + + const cosmosChainId = useChain('cosmoshub').chain.chain_id; + const { + transferChannel: { channelId }, + } = starshipChainInfo.agoric.connections[cosmosChainId]; + + const apiUrl = await useChain('cosmoshub').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const { hash: expectedHash } = await queryClient.queryDenom( + `transfer/${channelId}`, + 'uosmo', + ); + + t.log('Expected denom hash:', expectedHash); + + t.regex(balancesResultAfter[0]?.denom, /^ibc/); + t.is( + balancesResultAfter[0]?.denom.split('ibc/')[1], + expectedHash, + 'got expected ibc denom hash', + ); +}); + /** * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this * until the ticket above is done @@ -271,8 +513,10 @@ test.skip('address hook - BLD for OSMO, receiver on Agoric', async t => { } = await vstorageClient.queryData('published.swap-anything'); t.log(baseAddress); + const { swapAddress } = await getXcsContractsAddress(); + const orcContractReceiverAddress = encodeAddressHook(baseAddress, { - destAddr: 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', + destAddr: swapAddress, receiverAddr: wallets.agoricReceiver, outDenom: 'uosmo', }); From dd8b0ebd877456802a0357826500ae95bedd2c2b Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Thu, 8 May 2025 18:36:23 +0100 Subject: [PATCH 08/24] chore: add helper functions to dedicated file --- .../test/xcs-swap-anything/helpers.ts | 237 ++++++++++++++++ .../xcs-swap-anything/swap-anything.test.ts | 257 ++---------------- 2 files changed, 256 insertions(+), 238 deletions(-) create mode 100644 multichain-testing/test/xcs-swap-anything/helpers.ts diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts new file mode 100644 index 00000000000..99cc5fa25ac --- /dev/null +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -0,0 +1,237 @@ +import { + createFundedWalletAndClient, + makeIBCTransferMsg, +} from '../../tools/ibc-transfer.js'; +import { execa } from 'execa'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +export const fundRemote = async ( + t, + destinationChain, + denomToTransfer = 'ubld', + amount = 100000000n, +) => { + const { retryUntilCondition, useChain } = t.context; + + const { client, address, wallet } = await createFundedWalletAndClient( + t.log, + destinationChain, + useChain, + ); + const balancesResult = await retryUntilCondition( + () => client.getAllBalances(address), + coins => !!coins?.length, + `Faucet balances found for ${address}`, + ); + console.log('Balances:', balancesResult); + + const { client: agoricClient, address: agoricAddress } = + await createFundedWalletAndClient(t.log, 'agoric', useChain); + + const balancesResultAg = await retryUntilCondition( + () => agoricClient.getAllBalances(agoricAddress), + coins => !!coins?.length, + `Faucet balances found for ${agoricAddress}`, + ); + console.log('Balances AGORIC:', balancesResultAg); + + const transferArgs = makeIBCTransferMsg( + { denom: denomToTransfer, value: amount }, + { address, chainName: destinationChain }, + { address: agoricAddress, chainName: 'agoric' }, + Date.now(), + useChain, + ); + console.log('Transfer Args:', transferArgs); + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await agoricClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ${denomToTransfer}`); + } + const { events: _events, ...txRest } = txRes; + console.log(txRest); + t.is(txRes.code, 0, `Transaction succeeded`); + t.log(`Funds transferred to ${agoricAddress}`); + + await retryUntilCondition( + () => client.getAllBalances(address), + coins => !!coins?.length, + `${denomToTransfer} transferred to ${address}`, + ); + + return { + client, + address, + wallet, + }; +}; + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); + +export const setupXcsContracts = async t => { + console.log('Setting XCS Contracts ...'); + const osmosisBranch = 'main'; + try { + const scriptPath = path.resolve(dirname, '../../scripts/setup-xcs.sh'); + const { stdout } = await execa(scriptPath, [osmosisBranch]); + console.log('setup-xcs script output:', stdout); + } catch (error) { + t.fail(`setup-xcs script failed with error: ${error}`); + } +}; + +export const createOsmosisPool = async t => { + console.log('Creating Osmosis Pool ...'); + const tokenInDenom = 'ubld'; + const tokenInAmount = '250000'; + const tokenInWeight = '1'; + const tokenOutDenom = 'uosmo'; + const tokenOutAmount = '250000'; + const tokenOutWeight = '1'; + try { + const scriptPath = path.resolve( + dirname, + '../../scripts/create-osmosis-pool.sh', + ); + const { stdout } = await execa(scriptPath, [ + tokenInDenom, + tokenInAmount, + tokenInWeight, + tokenOutDenom, + tokenOutAmount, + tokenOutWeight, + ]); + console.log('create-osmosis-pool script output:', stdout); + } catch (error) { + t.fail(`create-osmosis-pool failed with error: ${error}`); + } +}; + +export const setupXcsChannelLink = async (t, chainA, chainB) => { + console.log('Setting XCS Channel Links ...'); + try { + const scriptPath = path.resolve( + dirname, + '../../scripts/setup-xcs-channel-link.sh', + ); + const { stdout } = await execa(scriptPath, [chainA, chainB]); + console.log('channel link setup output:', stdout); + } catch (error) { + t.fail(`channel link setup failed with error: ${error}`); + } +}; + +export const setupXcsPrefix = async t => { + console.log('Setting XCS Prefixes ...'); + try { + const scriptPath = path.resolve( + dirname, + '../../scripts/setup-xcs-prefix.sh', + ); + const { stdout } = await execa(scriptPath); + console.log('prefix setup output:', stdout); + } catch (error) { + t.fail(`prefix setup failed with error: ${error}`); + } +}; + +export const getXcsContractsAddress = async () => { + const osmosisCLI = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; + + const registryQuery = `${osmosisCLI} "jq -r '.crosschain_registry.address' /contract-info.json"`; + const swaprouterQuery = `${osmosisCLI} "jq -r '.swaprouter.address' /contract-info.json"`; + const swapQuery = `${osmosisCLI} "jq -r '.crosschain_swaps.address' /contract-info.json"`; + + const { stdout: registryAddress } = await execa(registryQuery, { + shell: true, + }); + const { stdout: swaprouterAddress } = await execa(swaprouterQuery, { + shell: true, + }); + const { stdout: swapAddress } = await execa(swapQuery, { shell: true }); + + return { registryAddress, swaprouterAddress, swapAddress }; +}; + +export const getXcsState = async () => { + const { registryAddress } = await getXcsContractsAddress(); + + const osmosisExecQuery = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + + const channelObj = { + get_channel_from_chain_pair: { + source_chain: 'osmosis', + destination_chain: 'agoric', + }, + }; + const channelJson = `'${JSON.stringify(channelObj)}'`; + const channelQuery = `${osmosisExecQuery} ${registryAddress} ${channelJson}`; + + const { stdout: channel } = await execa(channelQuery, { + shell: true, + }); + + const prefixObj = { + get_bech32_prefix_from_chain_name: { + chain_name: 'osmosis', + }, + }; + const prefixJson = `'${JSON.stringify(prefixObj)}'`; + const prefixQuery = `${osmosisExecQuery} ${registryAddress} ${prefixJson}`; + + const { stdout: prefix } = await execa(prefixQuery, { + shell: true, + }); + + const channelData = JSON.parse(channel).data; + const prefixData = JSON.parse(prefix).data; + + return { channelData, prefixData }; +}; + +export const getPoolRoute = async () => { + const { swaprouterAddress } = await getXcsContractsAddress(); + + const osmosisExecQuery = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + + const routeObj = { + get_route: { + input_denom: + 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', + output_denom: 'uosmo', + }, + }; + const routeJson = `'${JSON.stringify(routeObj)}'`; + const routeQuery = `${osmosisExecQuery} ${swaprouterAddress} ${routeJson}`; + + const { stdout } = await execa(routeQuery, { + shell: true, + }); + + const routeData = JSON.parse(stdout).data; + const route = routeData.pool_route[routeData.pool_route.length - 1]; + + return route; +}; + +export const getPool = async poolId => { + const osmosisExec = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd'; + + const poolQuery = `${osmosisExec} query gamm pool ${poolId}`; + + const { stdout } = await execa(poolQuery, { + shell: true, + }); + + const pool = JSON.parse(stdout).pool; + + return pool; +}; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 03918ccfb5d..a7b17182ca3 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -10,10 +10,18 @@ import { createFundedWalletAndClient, makeIBCTransferMsg, } from '../../tools/ibc-transfer.js'; -import { execa } from 'execa'; -import path from 'path'; -import { fileURLToPath } from 'url'; import { makeHttpClient } from '../../tools/makeHttpClient.js'; +import { + fundRemote, + setupXcsContracts, + createOsmosisPool, + setupXcsChannelLink, + setupXcsPrefix, + getXcsContractsAddress, + getXcsState, + getPoolRoute, + getPool, +} from './helpers.js'; const test = anyTest as TestFn; @@ -23,236 +31,6 @@ const contractName = 'swapAnything'; const contractBuilder = '../packages/builders/scripts/testing/init-swap-anything.js'; -const fundRemote = async ( - t, - destinationChain, - denomToTransfer = 'ubld', - amount = 100000000n, -) => { - const { retryUntilCondition, useChain } = t.context; - - const { client, address, wallet } = await createFundedWalletAndClient( - t.log, - destinationChain, - useChain, - ); - const balancesResult = await retryUntilCondition( - () => client.getAllBalances(address), - coins => !!coins?.length, - `Faucet balances found for ${address}`, - ); - console.log('Balances:', balancesResult); - - const { client: agoricClient, address: agoricAddress } = - await createFundedWalletAndClient(t.log, 'agoric', useChain); - - const balancesResultAg = await retryUntilCondition( - () => agoricClient.getAllBalances(agoricAddress), - coins => !!coins?.length, - `Faucet balances found for ${agoricAddress}`, - ); - console.log('Balances AGORIC:', balancesResultAg); - - const transferArgs = makeIBCTransferMsg( - { denom: denomToTransfer, value: amount }, - { address, chainName: destinationChain }, - { address: agoricAddress, chainName: 'agoric' }, - Date.now(), - useChain, - ); - console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await agoricClient.sendIbcTokens(...transferArgs); - if (txRes && txRes.code !== 0) { - console.error(txRes); - throw Error(`failed to ibc transfer funds to ${denomToTransfer}`); - } - const { events: _events, ...txRest } = txRes; - console.log(txRest); - t.is(txRes.code, 0, `Transaction succeeded`); - t.log(`Funds transferred to ${agoricAddress}`); - - await retryUntilCondition( - () => client.getAllBalances(address), - coins => !!coins?.length, - `${denomToTransfer} transferred to ${address}`, - ); - - return { - client, - address, - wallet, - }; -}; - -const filename = fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); - -const setupXcsContracts = async t => { - console.log('Setting XCS Contracts ...'); - const osmosisBranch = 'main'; - try { - const scriptPath = path.resolve(dirname, '../../scripts/setup-xcs.sh'); - const { stdout } = await execa(scriptPath, [osmosisBranch]); - console.log('setup-xcs script output:', stdout); - } catch (error) { - t.fail(`setup-xcs script failed with error: ${error}`); - } -}; - -const createOsmosisPool = async t => { - console.log('Creating Osmosis Pool ...'); - const tokenInDenom = 'ubld'; - const tokenInAmount = '250000'; - const tokenInWeight = '1'; - const tokenOutDenom = 'uosmo'; - const tokenOutAmount = '250000'; - const tokenOutWeight = '1'; - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/create-osmosis-pool.sh', - ); - const { stdout } = await execa(scriptPath, [ - tokenInDenom, - tokenInAmount, - tokenInWeight, - tokenOutDenom, - tokenOutAmount, - tokenOutWeight, - ]); - console.log('create-osmosis-pool script output:', stdout); - } catch (error) { - t.fail(`create-osmosis-pool failed with error: ${error}`); - } -}; - -const setupXcsChannelLink = async (t, chainA, chainB) => { - console.log('Setting XCS Channel Links ...'); - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/setup-xcs-channel-link.sh', - ); - const { stdout } = await execa(scriptPath, [chainA, chainB]); - console.log('channel link setup output:', stdout); - } catch (error) { - t.fail(`channel link setup failed with error: ${error}`); - } -}; - -const setupXcsPrefix = async t => { - console.log('Setting XCS Prefixes ...'); - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/setup-xcs-prefix.sh', - ); - const { stdout } = await execa(scriptPath); - console.log('prefix setup output:', stdout); - } catch (error) { - t.fail(`prefix setup failed with error: ${error}`); - } -}; - -const getXcsContractsAddress = async () => { - const osmosisCLI = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; - - const registryQuery = `${osmosisCLI} "jq -r '.crosschain_registry.address' /contract-info.json"`; - const swaprouterQuery = `${osmosisCLI} "jq -r '.swaprouter.address' /contract-info.json"`; - const swapQuery = `${osmosisCLI} "jq -r '.crosschain_swaps.address' /contract-info.json"`; - - const { stdout: registryAddress } = await execa(registryQuery, { - shell: true, - }); - const { stdout: swaprouterAddress } = await execa(swaprouterQuery, { - shell: true, - }); - const { stdout: swapAddress } = await execa(swapQuery, { shell: true }); - - return { registryAddress, swaprouterAddress, swapAddress }; -}; - -const getXcsState = async () => { - const { registryAddress } = await getXcsContractsAddress(); - - const osmosisExecQuery = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; - - const channelObj = { - get_channel_from_chain_pair: { - source_chain: 'osmosis', - destination_chain: 'agoric', - }, - }; - const channelJson = `'${JSON.stringify(channelObj)}'`; - const channelQuery = `${osmosisExecQuery} ${registryAddress} ${channelJson}`; - - const { stdout: channel } = await execa(channelQuery, { - shell: true, - }); - - const prefixObj = { - get_bech32_prefix_from_chain_name: { - chain_name: 'osmosis', - }, - }; - const prefixJson = `'${JSON.stringify(prefixObj)}'`; - const prefixQuery = `${osmosisExecQuery} ${registryAddress} ${prefixJson}`; - - const { stdout: prefix } = await execa(prefixQuery, { - shell: true, - }); - - const channelData = JSON.parse(channel).data; - const prefixData = JSON.parse(prefix).data; - - return { channelData, prefixData }; -}; - -const getPoolRoute = async () => { - const { swaprouterAddress } = await getXcsContractsAddress(); - - const osmosisExecQuery = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; - - const routeObj = { - get_route: { - input_denom: - 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', - output_denom: 'uosmo', - }, - }; - const routeJson = `'${JSON.stringify(routeObj)}'`; - const routeQuery = `${osmosisExecQuery} ${swaprouterAddress} ${routeJson}`; - - const { stdout } = await execa(routeQuery, { - shell: true, - }); - - const routeData = JSON.parse(stdout).data; - const route = routeData.pool_route[routeData.pool_route.length - 1]; - - return route; -}; - -const getPool = async poolId => { - const osmosisExec = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd'; - - const poolQuery = `${osmosisExec} query gamm pool ${poolId}`; - - const { stdout } = await execa(poolQuery, { - shell: true, - }); - - const pool = JSON.parse(stdout).pool; - - return pool; -}; - test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; @@ -263,13 +41,16 @@ test.before(async t => { await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); console.log('WALLETS', wallets); - // @ts-expect-error type - t.context = { ...common, wallets, waitForBlock }; + await startContract(contractName, contractBuilder, commonBuilderOpts); + await setupXcsContracts(t); await createOsmosisPool(t); await setupXcsChannelLink(t, 'agoric', 'osmosis'); await setupXcsPrefix(t); + + // @ts-expect-error type + t.context = { ...common, wallets, waitForBlock }; }); test.serial('test osmosis xcs state', async t => { @@ -283,10 +64,10 @@ test.serial('test osmosis xcs state', async t => { t.assert(swapAddress, 'crosschain_swaps contract address not found'); // verify if Osmosis XCS State was modified - const osmosisChainId = useChain('osmosis').chain.chain_id; + const agoricChainId = useChain('agoric').chain.chain_id; const { transferChannel: { channelId }, - } = starshipChainInfo.agoric.connections[osmosisChainId]; + } = starshipChainInfo.osmosis.connections[agoricChainId]; const { channelData, prefixData: osmosisPrefix } = await getXcsState(); @@ -455,7 +236,7 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { const cosmosChainId = useChain('cosmoshub').chain.chain_id; const { transferChannel: { channelId }, - } = starshipChainInfo.agoric.connections[cosmosChainId]; + } = starshipChainInfo.osmosis.connections[cosmosChainId]; const apiUrl = await useChain('cosmoshub').getRestEndpoint(); const queryClient = makeQueryClient(apiUrl); From 00275c8aab4a5642d0f16d011632571aaa3d2293 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Fri, 9 May 2025 11:02:27 +0100 Subject: [PATCH 09/24] test: swap OSMO for BLD with receiver on Agoric chore: implement failing IBC msg test case Refs: #8863 --- .../scripts/create-osmosis-pool.sh | 56 ++++++ .../xcs-swap-anything/swap-anything.test.ts | 167 ++++++++++++++++++ .../src/examples/swap-anything.contract.js | 4 +- .../src/examples/swap-anything.flows.js | 5 +- 4 files changed, 229 insertions(+), 3 deletions(-) diff --git a/multichain-testing/scripts/create-osmosis-pool.sh b/multichain-testing/scripts/create-osmosis-pool.sh index 821a362e631..290c0e2a8b4 100755 --- a/multichain-testing/scripts/create-osmosis-pool.sh +++ b/multichain-testing/scripts/create-osmosis-pool.sh @@ -186,3 +186,59 @@ echo "Querying pool route ..." ) echo "Liquidity Pool open and stored on swaprouter successfully." + +SET_REVERSE_ROUTE_JSON=$(jq -n \ + --arg tokenIn "$TOKEN_OUT_DENOM" \ + --arg tokenOut "$TOKEN_IN_DENOM" \ + --arg poolId "$POOL_ID" \ + '{ + set_route: { + input_denom: $tokenIn, + output_denom: $tokenOut, + pool_route: [ + { + pool_id: $poolId, + token_out_denom: $tokenOut + } + ] + } + }') + +GET_REVERSE_ROUTE_JSON=$(jq -n \ + --arg tokenIn "$TOKEN_OUT_DENOM" \ + --arg tokenOut "$TOKEN_IN_DENOM" \ + '{ + "get_route": { + "input_denom": $tokenIn, + "output_denom": $tokenOut + } +}') + +echo "Storing reverse pool on swaprouter contract ..." +osmosis-exec tx wasm execute "$SWAPROUTER_ADDRESS" "$SET_REVERSE_ROUTE_JSON" --from "$SWAPROUTER_OWNER_ADDRESS" --chain-id osmosislocal --yes --fees 1000uosmo + +echo "Querying reverse pool route ..." +( + set +e # handle failure of "osmosis-exec query wasm contract-state smart" + + for ((i = 1; i <= MAX_RETRIES; i++)); do + echo "Attempt $i of $MAX_RETRIES..." + pool_route_json=$(osmosis-exec query wasm contract-state smart "$SWAPROUTER_ADDRESS" "$GET_REVERSE_ROUTE_JSON" 2> /dev/null) + + if [[ $? -eq 0 ]]; then + echo "Pool route found:" + echo "$pool_route_json" + break + fi + + if [[ $i -eq MAX_RETRIES ]]; then + echo "Pool not stored after $MAX_RETRIES attempts." + exit 1 + fi + + echo "Query failed. Waiting $DELAY seconds before retrying..." + sleep "$DELAY" + done +) + +echo "Reverse liquidity Pool open and stored on swaprouter successfully." diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index a7b17182ca3..13882d8737c 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -11,6 +11,7 @@ import { makeIBCTransferMsg, } from '../../tools/ibc-transfer.js'; import { makeHttpClient } from '../../tools/makeHttpClient.js'; +import type { OfferStatus } from '@agoric/smart-wallet/src/offers.js'; import { fundRemote, setupXcsContracts, @@ -166,6 +167,91 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); }); +test.serial('OSMO for BLD, receiver on Agoric', async t => { + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + // Provision the Agoric smart wallet + const agoricAddr = wallets.agoricReceiver; + const wdUser = await provisionSmartWallet(agoricAddr, { + BLD: 1000n, + IST: 1000n, + }); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + const { swapAddress } = await getXcsContractsAddress(); + + const doOffer = makeDoOffer(wdUser); + + // Verify deposit + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const bldBrand = Object.fromEntries(brands).OSMO; + const swapInAmount = AmountMath.make(bldBrand, 75n); + const { balances: balancesBefore } = await queryClient.queryBalances( + wallets.agoricReceiver, + ); + + const osmosisApiUrl = await useChain('osmosis').getRestEndpoint(); + const osmosisQueryClient = makeQueryClient(osmosisApiUrl); + + const agoricChainId = useChain('agoric').chain.chain_id; + + const { + transferChannel: { channelId }, + } = starshipChainInfo.osmosis.connections[agoricChainId]; + + const { hash: outDenomHash } = await osmosisQueryClient.queryDenom( + `transfer/${channelId}`, + 'ubld', + ); + + // Send swap offer + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; + await doOffer({ + id: makeAccountOfferId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeSendInvitation']], + }, + offerArgs: { + // TODO: get the contract address dynamically + destAddr: swapAddress, + receiverAddr: wallets.agoricReceiver, + outDenom: `ibc/${outDenomHash}`, + slippage: { slippagePercentage: '20', windowSeconds: 10 }, + onFailedDelivery: 'do_nothing', + }, + proposal: { give: { Send: swapInAmount } }, + }); + + const { balances: agoricReceiverBalances } = await retryUntilCondition( + () => queryClient.queryBalances(wallets.agoricReceiver), + ({ balances }) => { + const balancesBeforeAmount = BigInt(balancesBefore[0]?.amount || 0); + const currentBalanceAmount = BigInt(balances[0]?.amount || 0); + return currentBalanceAmount < balancesBeforeAmount; + }, + 'Deposit reflected in localOrchAccount balance', + ); + t.log(agoricReceiverBalances); + + t.assert( + BigInt(balancesBefore[0].amount) > BigInt(agoricReceiverBalances[0].amount), + ); + t.assert( + BigInt(balancesBefore[1].amount) < BigInt(agoricReceiverBalances[1].amount), + ); +}); + test.serial('BLD for OSMO, receiver on CosmosHub', async t => { const { wallets, @@ -256,6 +342,87 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { ); }); +test.serial('BLD for OSMO, receiver chain not registered to XCS, should throw', async t => { + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + // Provision the Agoric smart wallet + const agoricAddr = wallets.agoricSender; + const wdUser = await provisionSmartWallet(agoricAddr, { + BLD: 1000n, + IST: 1000n, + }); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const bldBrand = Object.fromEntries(brands).BLD; + const swapInAmount = AmountMath.make(bldBrand, 125n); + const { balance: bldBalanceBefore } = await queryClient.queryBalance( + agoricAddr, + 'ubld', + ); + + // Send swap offer + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; + const updates = wdUser.offers.executeOffer({ + id: makeAccountOfferId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeSendInvitation']], + }, + offerArgs: { + // TODO: get the contract address dynamically + destAddr: + 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', + receiverAddr: 'noble/noble1foo', + outDenom: 'uosmo', + slippage: { slippagePercentage: '20', windowSeconds: 10 }, + onFailedDelivery: 'do_nothing', + }, + proposal: { give: { Send: swapInAmount } }, + }); + + const { + // @ts-expect-error types + value: { + status: { error: errorMsg }, + }, + } = await retryUntilCondition( + // Prevent test from hanging when no new values are coming from updates.next() + () => + Promise.race([ + updates.next(), + new Promise(resolve => + setTimeout(async () => { + await updates.return(); + resolve('Done'); + }, 5000), + ), + ]), + (result: { value: { updated: string; status: OfferStatus } }) => { + return result.value.status.error !== undefined; + }, + 'Offer result did not fail as expect ed', + ); + + const { balance: bldBalanceAfter } = await queryClient.queryBalance( + agoricAddr, + 'ubld', + ); + + t.deepEqual(bldBalanceBefore, bldBalanceAfter); + t.regex(errorMsg, /^Error: IBC Transfer failed/); +}); + /** * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this * until the ticket above is done diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js index b11afd72e2c..7fc608e2acc 100644 --- a/packages/orchestration/src/examples/swap-anything.contract.js +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -51,8 +51,8 @@ export const contract = async ( // UNTIL https://github.com/Agoric/agoric-sdk/issues/9066 const logNode = E(privateArgs.storageNode).makeChildNode('log'); /** @type {(msg: string) => Vow} */ - const log = msg => - vowTools.watch(E(logNode).setValue(JSON.stringify({ msg }))); + const log = (msg, level = 'info') => + vowTools.watch(E(logNode).setValue(JSON.stringify({ msg, level }))); const makeLocalAccount = orchestrate( 'makeLocalAccount', diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js index ef3f26bd503..3af69bd9d9c 100644 --- a/packages/orchestration/src/examples/swap-anything.flows.js +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -70,7 +70,7 @@ const buildXCSMemo = swapInfo => { * @param {GuestInterface} ctx.chainHub * @param {Promise>} ctx.sharedLocalAccountP * @param {GuestInterface} ctx.zoeTools - * @param {GuestOf<(msg: string) => Vow>} ctx.log + * @param {GuestOf<(msg: string, level?: string) => Vow>} ctx.log * @param {ZCFSeat} seat * @param {SwapInfo} offerArgs */ @@ -124,6 +124,7 @@ export const swapIt = async ( await withdrawToSeat(sharedLocalAccount, seat, give); const errorMsg = `IBC Transfer failed ${q(e)}`; trace(`ERROR: ${errorMsg}`); + void log(errorMsg, 'error'); seat.fail(errorMsg); throw makeError(errorMsg); }; @@ -142,6 +143,7 @@ export const swapIt = async ( try { const memo = buildXCSMemo(offerArgs); trace(memo); + void log(`sending transfer with ${q(memo)}`); await sharedLocalAccount.transfer( { @@ -154,6 +156,7 @@ export const swapIt = async ( ); trace(`completed transfer to ${destAddr}`); } catch (e) { + void log(`transfer error ${q(e)}`, 'error'); return recoverFailedTransfer(e); } From a2c8920e313dadc8cf74d04ae3486de301be874c Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Fri, 9 May 2025 13:46:13 +0300 Subject: [PATCH 10/24] fix: exclude swap-anything from the main ava config fix: format fixes chore: invitation name and tests updated, tests use dynamic xcs address Refs: #8863 --- multichain-testing/ava.rest.config.js | 1 + .../xcs-swap-anything/swap-anything.test.ts | 171 +++++++++--------- .../src/examples/swap-anything.contract.js | 8 +- .../test/examples/swap-anything.test.ts | 8 +- 4 files changed, 99 insertions(+), 89 deletions(-) diff --git a/multichain-testing/ava.rest.config.js b/multichain-testing/ava.rest.config.js index 59186d607b1..da6fa81664f 100644 --- a/multichain-testing/ava.rest.config.js +++ b/multichain-testing/ava.rest.config.js @@ -13,5 +13,6 @@ export default { '!test/fast-usdc/**/*.test.*', '!test/queries/**/*.test.*', '!test/staking/**/*.test.*', + '!test/xcs-swap-anything/**/*.test.*', ], }; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 13882d8737c..d22d7839a41 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -128,7 +128,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { invitationSpec: { source: 'agoricContract', instancePath: [contractName], - callPipe: [['makeSendInvitation']], + callPipe: [['makeSwapInvitation']], }, offerArgs: { // TODO: get the contract address dynamically @@ -220,7 +220,7 @@ test.serial('OSMO for BLD, receiver on Agoric', async t => { invitationSpec: { source: 'agoricContract', instancePath: [contractName], - callPipe: [['makeSendInvitation']], + callPipe: [['makeSwapInvitation']], }, offerArgs: { // TODO: get the contract address dynamically @@ -299,7 +299,7 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { invitationSpec: { source: 'agoricContract', instancePath: [contractName], - callPipe: [['makeSendInvitation']], + callPipe: [['makeSwapInvitation']], }, offerArgs: { // TODO: get the contract address dynamically @@ -342,86 +342,91 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { ); }); -test.serial('BLD for OSMO, receiver chain not registered to XCS, should throw', async t => { - const { - wallets, - provisionSmartWallet, - vstorageClient, - retryUntilCondition, - useChain, - } = t.context; - - // Provision the Agoric smart wallet - const agoricAddr = wallets.agoricSender; - const wdUser = await provisionSmartWallet(agoricAddr, { - BLD: 1000n, - IST: 1000n, - }); - t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); - - const apiUrl = await useChain('agoric').getRestEndpoint(); - const queryClient = makeQueryClient(apiUrl); - - const brands = await vstorageClient.queryData('published.agoricNames.brand'); - const bldBrand = Object.fromEntries(brands).BLD; - const swapInAmount = AmountMath.make(bldBrand, 125n); - const { balance: bldBalanceBefore } = await queryClient.queryBalance( - agoricAddr, - 'ubld', - ); - - // Send swap offer - const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; - const updates = wdUser.offers.executeOffer({ - id: makeAccountOfferId, - invitationSpec: { - source: 'agoricContract', - instancePath: [contractName], - callPipe: [['makeSendInvitation']], - }, - offerArgs: { - // TODO: get the contract address dynamically - destAddr: - 'osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8', - receiverAddr: 'noble/noble1foo', - outDenom: 'uosmo', - slippage: { slippagePercentage: '20', windowSeconds: 10 }, - onFailedDelivery: 'do_nothing', - }, - proposal: { give: { Send: swapInAmount } }, - }); - - const { - // @ts-expect-error types - value: { - status: { error: errorMsg }, - }, - } = await retryUntilCondition( - // Prevent test from hanging when no new values are coming from updates.next() - () => - Promise.race([ - updates.next(), - new Promise(resolve => - setTimeout(async () => { - await updates.return(); - resolve('Done'); - }, 5000), - ), - ]), - (result: { value: { updated: string; status: OfferStatus } }) => { - return result.value.status.error !== undefined; - }, - 'Offer result did not fail as expect ed', - ); - - const { balance: bldBalanceAfter } = await queryClient.queryBalance( - agoricAddr, - 'ubld', - ); - - t.deepEqual(bldBalanceBefore, bldBalanceAfter); - t.regex(errorMsg, /^Error: IBC Transfer failed/); -}); +test.serial( + 'BLD for OSMO, receiver chain not registered to XCS, should throw', + async t => { + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + // Provision the Agoric smart wallet + const agoricAddr = wallets.agoricSender; + const wdUser = await provisionSmartWallet(agoricAddr, { + BLD: 1000n, + IST: 1000n, + }); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const brands = await vstorageClient.queryData( + 'published.agoricNames.brand', + ); + const bldBrand = Object.fromEntries(brands).BLD; + const swapInAmount = AmountMath.make(bldBrand, 125n); + const { balance: bldBalanceBefore } = await queryClient.queryBalance( + agoricAddr, + 'ubld', + ); + + const { swapAddress } = await getXcsContractsAddress(); + + // Send swap offer + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; + const updates = wdUser.offers.executeOffer({ + id: makeAccountOfferId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeSwapInvitation']], + }, + offerArgs: { + destAddr: swapAddress, + receiverAddr: 'noble/noble1foo', // bad swap receiver + outDenom: 'uosmo', + slippage: { slippagePercentage: '20', windowSeconds: 10 }, + onFailedDelivery: 'do_nothing', + }, + proposal: { give: { Send: swapInAmount } }, + }); + + const { + // @ts-expect-error types + value: { + status: { error: errorMsg }, + }, + } = await retryUntilCondition( + // Prevent test from hanging when no new values are coming from updates.next() + () => + Promise.race([ + updates.next(), + new Promise(resolve => + setTimeout(async () => { + await updates.return(); + resolve('Done'); + }, 5000), + ), + ]), + (result: { value: { updated: string; status: OfferStatus } }) => { + return result.value.status.error !== undefined; + }, + 'Offer result did not fail as expect ed', + ); + + const { balance: bldBalanceAfter } = await queryClient.queryBalance( + agoricAddr, + 'ubld', + ); + + t.deepEqual(bldBalanceBefore, bldBalanceAfter); + t.regex(errorMsg, /^Error: IBC Transfer failed/); + }, +); /** * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js index 7fc608e2acc..25ba08715e3 100644 --- a/packages/orchestration/src/examples/swap-anything.contract.js +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -83,12 +83,12 @@ export const contract = async ( }); const publicFacet = zone.exo( - 'Send PF', - M.interface('Send PF', { - makeSendInvitation: M.callWhen().returns(InvitationShape), + 'Swap Anything PF', + M.interface('Swap Anything PF', { + makeSwapInvitation: M.callWhen().returns(InvitationShape), }), { - makeSendInvitation() { + makeSwapInvitation() { return zcf.makeInvitation( swapAnythingOffer, 'swap', diff --git a/packages/orchestration/test/examples/swap-anything.test.ts b/packages/orchestration/test/examples/swap-anything.test.ts index 9693c8bfaf5..f6c354b9389 100644 --- a/packages/orchestration/test/examples/swap-anything.test.ts +++ b/packages/orchestration/test/examples/swap-anything.test.ts @@ -108,7 +108,7 @@ test('swap BLD for Osmo, receiver on Agoric', async t => { } = await bootstrapOrchestration(t); const publicFacet = await E(zoe).getPublicFacet(swapKit.instance); - const inv = E(publicFacet).makeSendInvitation(); + const inv = E(publicFacet).makeSwapInvitation(); const amt = await E(zoe).getInvitationDetails(inv); t.is(amt.description, 'swap'); @@ -144,7 +144,11 @@ test('swap BLD for Osmo, receiver on Agoric', async t => { ); }); -test('trigger osmosis swap from an address hook', async t => { +/** + * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this + * until the ticket above is done + */ +test.skip('trigger osmosis swap from an address hook', async t => { const { bootstrap: { storage }, transferBridge, From ba5b9ed9ba04bdf29ac4b97b6631ad81d5817953 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Wed, 14 May 2025 16:00:53 +0300 Subject: [PATCH 11/24] chore: bring back address hooks Refs: #8863 --- .../xcs-swap-anything/swap-anything.test.ts | 8 +- .../src/examples/swap-anything.contract.js | 81 ++++++++++++++++++- .../src/examples/swap-anything.flows.js | 13 ++- 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index d22d7839a41..ab00f334745 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -428,11 +428,7 @@ test.serial( }, ); -/** - * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51, we are skipping this - * until the ticket above is done - */ -test.skip('address hook - BLD for OSMO, receiver on Agoric', async t => { +test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { const { wallets, vstorageClient, retryUntilCondition, useChain } = t.context; const { getRestEndpoint, chain: cosmosChain } = useChain('cosmoshub'); @@ -507,7 +503,7 @@ test.skip('address hook - BLD for OSMO, receiver on Agoric', async t => { const currentBalanceAmount = BigInt(balances[0]?.amount || 0); return currentBalanceAmount > balancesBeforeAmount; }, - 'Deposit reflected in localOrchAccount balance', + 'Osmosis swap output reflected on Agoric receiver balance', ); t.log(agoricReceiverBalances); diff --git a/packages/orchestration/src/examples/swap-anything.contract.js b/packages/orchestration/src/examples/swap-anything.contract.js index 25ba08715e3..400f0e933ff 100644 --- a/packages/orchestration/src/examples/swap-anything.contract.js +++ b/packages/orchestration/src/examples/swap-anything.contract.js @@ -2,20 +2,21 @@ import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; import { makeTracer } from '@agoric/internal'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; +import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js'; import { withOrchestration } from '../utils/start-helper.js'; import * as sharedFlows from './shared.flows.js'; -import { swapIt } from './swap-anything.flows.js'; +import { swapAnythingViaHook, swapIt } from './swap-anything.flows.js'; import { AnyNatAmountShape } from '../typeGuards.js'; import { registerChainsAndAssets } from '../utils/chain-hub-helper.js'; const trace = makeTracer('SwapAnything.Contract'); - +const interfaceTODO = undefined; /** * @import {Remote, Vow} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; * @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js'; - * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; + * @import {CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration'; */ export const SingleNatAmountRecord = M.and( @@ -48,6 +49,11 @@ export const contract = async ( ) => { const creatorFacet = prepareChainHubAdmin(zone, chainHub); + /** + * @type {OrchestrationAccount<{ chainId: 'agoric' }>} ; + */ + let sharedLocalAccount; + // UNTIL https://github.com/Agoric/agoric-sdk/issues/9066 const logNode = E(privateArgs.storageNode).makeChildNode('log'); /** @type {(msg: string) => Vow} */ @@ -74,7 +80,74 @@ export const contract = async ( swapIt, ); - void vowTools.when(sharedLocalAccountP, async sharedLocalAccount => { + const swapAnythingAddressHook = orchestrate( + 'swapAnythingViaHook', + { + chainHub, + sharedLocalAccountP, + log, + }, + swapAnythingViaHook, + ); + + const tap = zone.makeOnce('tapPosition', _key => { + console.log('making tap'); + return zone.exo('tap', interfaceTODO, { + /** + * @param {import('@agoric/vats').VTransferIBCEvent} event + */ + async receiveUpcall(event) { + await null; + trace('receiveUpcall', event); + + if (event.event !== 'writeAcknowledgement') return; + trace('Moving on...'); + + const { + amount, + extra: { receiver: origReceiver }, + } = await vowTools.when( + E(sharedLocalAccount).parseInboundTransfer(event.packet), + ); + + const { baseAddress, query } = decodeAddressHook(origReceiver); + + /** + * @type {{ + * destAddr: string; + * receiverAddr: string; + * outDenom: string; + * }} + */ + // @ts-expect-error + const { destAddr, receiverAddr, outDenom } = query; + + trace({ + baseAddress, + destAddr, + receiverAddr, + outDenom, + }); + + if (!receiverAddr || !destAddr || !outDenom) return; + // Invoke the flow to perform swap and end up at the final destination. + return swapAnythingAddressHook(amount, { + destAddr, + receiverAddr, + outDenom, // swapOutDenom + onFailedDelivery: 'do_nothing', + slippage: { + slippagePercentage: '20', + windowSeconds: 10, + }, + }); + }, + }); + }); + + void vowTools.when(sharedLocalAccountP, async lca => { + sharedLocalAccount = lca; + await sharedLocalAccount.monitorTransfers(tap); const encoded = await E(privateArgs.marshaller).toCapData({ sharedLocalAccount: sharedLocalAccount.getAddress(), }); diff --git a/packages/orchestration/src/examples/swap-anything.flows.js b/packages/orchestration/src/examples/swap-anything.flows.js index 3af69bd9d9c..cc7cb423bda 100644 --- a/packages/orchestration/src/examples/swap-anything.flows.js +++ b/packages/orchestration/src/examples/swap-anything.flows.js @@ -22,7 +22,7 @@ const { entries } = Object; * @import {Vow} from '@agoric/vow'; * @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js'; * @import {ZoeTools} from '../utils/zoe-tools.js'; - * @import {Orchestrator, OrchestrationFlow, ChainHub, CosmosChainInfo} from '../types.js'; + * @import {Orchestrator, OrchestrationFlow, ChainHub, CosmosChainInfo, DenomAmount} from '../types.js'; */ const denomForBrand = async (orch, brand) => { @@ -166,21 +166,18 @@ export const swapIt = async ( harden(swapIt); /** - * UNTIL https://github.com/Agoric/BytePitchPartnerEng/issues/51 is done, we - * can't demonstrate this - * * @satisfies {OrchestrationFlow} * @param {Orchestrator} _orch * @param {object} ctx * @param {GuestInterface} ctx.chainHub * @param {Promise>} ctx.sharedLocalAccountP - * @param {{ denom: string; amount: string }} transferInfo + * @param {DenomAmount} transferInfo * @param {SwapInfo} memoArgs */ export const swapAnythingViaHook = async ( _orch, { chainHub, sharedLocalAccountP }, - { denom, amount }, + { denom, value }, memoArgs, ) => { mustMatch( @@ -198,7 +195,7 @@ export const swapAnythingViaHook = async ( ); const { receiverAddr, destAddr } = memoArgs; - trace(`sending {${amount}} from osmosis to ${receiverAddr}`); + trace(`sending {${value}} from osmosis to ${receiverAddr}`); /** * @type {any} XXX methods returning vows @@ -222,7 +219,7 @@ export const swapAnythingViaHook = async ( encoding: 'bech32', chainId: /** @type {CosmosChainInfo} */ (osmosisChainInfo).chainId, }, - { denom, value: BigInt(amount) }, + { denom, value }, { memo }, ); From 65732310e650ab03d058877b33b2982112a95d21 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Thu, 22 May 2025 16:01:02 +0100 Subject: [PATCH 12/24] chore(orchestration): refactor xcs swap helper functions chore: refactor xcs swap helper functions chore: refactor xcs swap tests with new helpers chore: remove unused xcs swap scripts chore: update gitignore chore: remove need for waitForBlock mehtod chore: lint fix chore: import missing packages fix: address conflicts on @cosmjs/proto-signing chore: improve xcs swap logging chore: add waitForBlock between setPoolRoute txs chore(multichain): create pool by default and update names for clarity chore(multichain): do not create osmosis pool by default chore: refactor test tooling for osmosis xcs ref: #8863 --- multichain-testing/.gitignore | 6 +- multichain-testing/package.json | 2 + .../scripts/create-osmosis-pool.sh | 244 --- .../scripts/setup-xcs-channel-link.sh | 85 - .../scripts/setup-xcs-prefix.sh | 73 - multichain-testing/scripts/setup-xcs.sh | 137 -- .../test/xcs-swap-anything/Makefile | 108 -- .../download-wasm-artifacts.sh | 0 .../test/xcs-swap-anything/helpers.ts | 950 ++++++++--- .../xcs-swap-anything/swap-anything.test.ts | 325 ++-- multichain-testing/yarn.lock | 1451 ++++++++--------- 11 files changed, 1664 insertions(+), 1717 deletions(-) delete mode 100755 multichain-testing/scripts/create-osmosis-pool.sh delete mode 100755 multichain-testing/scripts/setup-xcs-channel-link.sh delete mode 100755 multichain-testing/scripts/setup-xcs-prefix.sh delete mode 100755 multichain-testing/scripts/setup-xcs.sh delete mode 100644 multichain-testing/test/xcs-swap-anything/Makefile rename multichain-testing/{scripts => test/xcs-swap-anything}/download-wasm-artifacts.sh (100%) diff --git a/multichain-testing/.gitignore b/multichain-testing/.gitignore index 908eb1b7c1a..5689a053e09 100644 --- a/multichain-testing/.gitignore +++ b/multichain-testing/.gitignore @@ -8,5 +8,7 @@ start* eval-* # ci logs for archive upload logs/ -# osmosis pool configuration -*-pool-config.json +# osmosis contracts info +/test/xcs-swap-anything/xcs-contracts-info.json +# osmosis contracts artifacts +/test/xcs-swap-anything/wasm-artifacts/* diff --git a/multichain-testing/package.json b/multichain-testing/package.json index f94afcc20a1..22b2b2b9242 100644 --- a/multichain-testing/package.json +++ b/multichain-testing/package.json @@ -17,6 +17,7 @@ "@agoric/cosmic-proto": "dev", "@agoric/fast-usdc": "dev", "@cosmjs/amino": "npm:^0.32.4", + "@cosmjs/cosmwasm-stargate": "^0.33.1", "@cosmjs/crypto": "^0.33.0", "@cosmjs/proto-signing": "^0.33.0", "@cosmjs/stargate": "^0.33.0", @@ -34,6 +35,7 @@ "eslint-config-prettier": "^10.1.1", "execa": "^9.5.2", "fs-extra": "^11.2.0", + "osmojs": "^16.15.0", "starshipjs": "2.4.1", "ts-blank-space": "^0.4.4", "typescript": "~5.8.2" diff --git a/multichain-testing/scripts/create-osmosis-pool.sh b/multichain-testing/scripts/create-osmosis-pool.sh deleted file mode 100755 index 290c0e2a8b4..00000000000 --- a/multichain-testing/scripts/create-osmosis-pool.sh +++ /dev/null @@ -1,244 +0,0 @@ -#!/bin/bash - -set -euo pipefail -shopt -s expand_aliases - -alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" -alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" -alias agoric-exec="kubectl exec -i agoriclocal-genesis-0 -c validator -- agd" -alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" - -AGORIC_WALLET="test1" -AGORIC_ADDRESS=$(agoric-exec keys show ${AGORIC_WALLET} -a) -OSMOSIS_WALLET="test1" -OSMOSIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_WALLET} -a) -SWAPROUTER_OWNER_WALLET="genesis" -SWAPROUTER_OWNER_ADDRESS=$(osmosis-exec keys show ${SWAPROUTER_OWNER_WALLET} -a) - -CHANNEL_INFO=$(hermes-exec --json query channels --show-counterparty --chain agoriclocal \ - | jq '[.][] | select(.result) | .result[] | select(.chain_id_b == "osmosislocal")') -AGORIC_OSMOSIS_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_a') -OSMOSIS_AGORIC_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_b') -AGORIC_OSMOSIS_PORT="transfer" - -AGORIC_TOKEN_DENOM="$1" -AGORIC_TOKEN_TRANSFER_AMOUNT="250000000000" - -IBC_DENOM=$(echo -n "$AGORIC_OSMOSIS_PORT/$OSMOSIS_AGORIC_CHANNEL/$AGORIC_TOKEN_DENOM" | shasum -a 256 | awk '{print toupper($1)}') - -TOKEN_IN_DENOM="ibc/$IBC_DENOM" -TOKEN_IN_AMOUNT="$2" -TOKEN_IN_WEIGHT="$3" -TOKEN_OUT_DENOM="$4" -TOKEN_OUT_AMOUNT="$5" -TOKEN_OUT_WEIGHT="$6" -SWAP_FEE="0.01" -EXIT_FEE="0.00" -FUTURE_GOVERNOR="" - -POOL_CONFIG_FILE="$AGORIC_TOKEN_DENOM-$TOKEN_OUT_DENOM-pool-config.json" -POOL_CONFIG_DEST="/opt/$POOL_CONFIG_FILE" - -MAX_RETRIES="5" -DELAY="5" - -echo "Generating pool configuration file ..." -jq -n \ - --arg weight1 "${TOKEN_IN_WEIGHT}${TOKEN_IN_DENOM}" \ - --arg weight2 "${TOKEN_OUT_WEIGHT}${TOKEN_OUT_DENOM}" \ - --arg amount1 "${TOKEN_IN_AMOUNT}${TOKEN_IN_DENOM}" \ - --arg amount2 "${TOKEN_OUT_AMOUNT}${TOKEN_OUT_DENOM}" \ - --arg swapFee "$SWAP_FEE" \ - --arg exitFee "$EXIT_FEE" \ - --arg futureGovernor "$FUTURE_GOVERNOR" \ - '{ - "weights": "\($weight1),\($weight2)", - "initial-deposit": "\($amount1),\($amount2)", - "swap-fee": $swapFee, - "exit-fee": $exitFee, - "future-governor": $futureGovernor - }' > "$POOL_CONFIG_FILE" - -echo "Verifying if Agoric wallet has enough funds ..." -agoric_balance_json=$(agoric-exec query bank balances $AGORIC_ADDRESS --denom $AGORIC_TOKEN_DENOM -o json) -agoric_balance=$(jq -r '.amount' <<< "$agoric_balance_json") - -if [ "$agoric_balance" -le "$AGORIC_TOKEN_TRANSFER_AMOUNT" ]; then - echo "Balance is NOT sufficient. Exiting..." - exit 1 -fi - -echo "Starting IBC transfer from Agoric to Osmosis ..." -agoric-exec tx ibc-transfer transfer $AGORIC_OSMOSIS_PORT $AGORIC_OSMOSIS_CHANNEL $OSMOSIS_ADDRESS ${AGORIC_TOKEN_TRANSFER_AMOUNT}${AGORIC_TOKEN_DENOM} --from $AGORIC_ADDRESS --yes - -echo "Verifying if Osmosis wallet has the funds ..." -for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - - osmosis_balances_json=$(osmosis-exec query bank balances $OSMOSIS_ADDRESS -o json) - - balance_1=$(jq -r --arg denom "$TOKEN_IN_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") - balance_2=$(jq -r --arg denom "$TOKEN_OUT_DENOM" '.balances[] | select(.denom == $denom) | .amount' <<< "$osmosis_balances_json") - - # If not found, treat as zero - balance_1=${balance_1:-0} - balance_2=${balance_2:-0} - - if [[ "$balance_1" -ge "$TOKEN_IN_AMOUNT" && "$balance_2" -ge "$TOKEN_OUT_AMOUNT" ]]; then - echo "Sufficient funds available." - break - fi - - if [[ $i -eq $MAX_RETRIES ]]; then - echo "Insufficient funds after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Waiting $DELAY seconds before retrying..." - sleep $DELAY -done - -# Record amount of existing pools before creating a new one -query_command='osmosis-exec query gamm num-pools -o json' -pool_count_json=$(eval "$query_command") -pool_count=$(jq -r '.num_pools' <<< "$pool_count_json") - -echo "Copying pool configuration to Osmosis ..." -kubectl cp "${POOL_CONFIG_FILE}" osmosislocal-genesis-0:"${POOL_CONFIG_DEST}" - -echo "Creating liquidity pool on Osmosis ..." -osmosis-exec tx gamm create-pool --pool-file $POOL_CONFIG_DEST --from $OSMOSIS_ADDRESS --chain-id osmosislocal --gas auto --gas-adjustment 1.2 --gas-prices=0.5uosmo --yes - -echo "Verifying pool details ..." -for ((i = 1; i <= MAX_RETRIES; i++)); do - current_pool_count_json=$(eval "$query_command") - current_pool_count=$(jq -r '.num_pools' <<< "$current_pool_count_json") - - if [ "$current_pool_count" -gt "$pool_count" ]; then - pool_info=$(osmosis-exec query gamm pool $current_pool_count) - break - fi - - if [[ $i -eq $MAX_RETRIES ]]; then - echo "Pool not created after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Waiting $DELAY seconds before retrying..." - sleep $DELAY -done - -SWAPROUTER_ADDRESS=$(osmosis-cli "jq -r '.swaprouter.address' /contract-info.json") -POOL_ID=$(jq -r '.pool | .id' <<< "$pool_info") - -SET_ROUTE_JSON=$(jq -n \ - --arg tokenIn "$TOKEN_IN_DENOM" \ - --arg tokenOut "$TOKEN_OUT_DENOM" \ - --arg poolId "$POOL_ID" \ - '{ - set_route: { - input_denom: $tokenIn, - output_denom: $tokenOut, - pool_route: [ - { - pool_id: $poolId, - token_out_denom: $tokenOut - } - ] - } - }') - -GET_ROUTE_JSON=$(jq -n \ - --arg tokenIn "$TOKEN_IN_DENOM" \ - --arg tokenOut "$TOKEN_OUT_DENOM" \ - '{ - "get_route": { - "input_denom": $tokenIn, - "output_denom": $tokenOut - } -}') - -echo "Storing pool on swaprouter contract ..." -osmosis-exec tx wasm execute "$SWAPROUTER_ADDRESS" "$SET_ROUTE_JSON" --from "$SWAPROUTER_OWNER_ADDRESS" --chain-id osmosislocal --yes --fees 1000uosmo - -echo "Querying pool route ..." -( - set +e # handle failure of "osmosis-exec query wasm contract-state smart" - - for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - pool_route_json=$(osmosis-exec query wasm contract-state smart "$SWAPROUTER_ADDRESS" "$GET_ROUTE_JSON" 2> /dev/null) - - if [[ $? -eq 0 ]]; then - echo "Pool route found:" - echo "$pool_route_json" - break - fi - - if [[ $i -eq MAX_RETRIES ]]; then - echo "Pool not stored after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Query failed. Waiting $DELAY seconds before retrying..." - sleep "$DELAY" - done -) - -echo "Liquidity Pool open and stored on swaprouter successfully." - -SET_REVERSE_ROUTE_JSON=$(jq -n \ - --arg tokenIn "$TOKEN_OUT_DENOM" \ - --arg tokenOut "$TOKEN_IN_DENOM" \ - --arg poolId "$POOL_ID" \ - '{ - set_route: { - input_denom: $tokenIn, - output_denom: $tokenOut, - pool_route: [ - { - pool_id: $poolId, - token_out_denom: $tokenOut - } - ] - } - }') - -GET_REVERSE_ROUTE_JSON=$(jq -n \ - --arg tokenIn "$TOKEN_OUT_DENOM" \ - --arg tokenOut "$TOKEN_IN_DENOM" \ - '{ - "get_route": { - "input_denom": $tokenIn, - "output_denom": $tokenOut - } -}') - -echo "Storing reverse pool on swaprouter contract ..." -osmosis-exec tx wasm execute "$SWAPROUTER_ADDRESS" "$SET_REVERSE_ROUTE_JSON" --from "$SWAPROUTER_OWNER_ADDRESS" --chain-id osmosislocal --yes --fees 1000uosmo - -echo "Querying reverse pool route ..." -( - set +e # handle failure of "osmosis-exec query wasm contract-state smart" - - for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - pool_route_json=$(osmosis-exec query wasm contract-state smart "$SWAPROUTER_ADDRESS" "$GET_REVERSE_ROUTE_JSON" 2> /dev/null) - - if [[ $? -eq 0 ]]; then - echo "Pool route found:" - echo "$pool_route_json" - break - fi - - if [[ $i -eq MAX_RETRIES ]]; then - echo "Pool not stored after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Query failed. Waiting $DELAY seconds before retrying..." - sleep "$DELAY" - done -) - -echo "Reverse liquidity Pool open and stored on swaprouter successfully." diff --git a/multichain-testing/scripts/setup-xcs-channel-link.sh b/multichain-testing/scripts/setup-xcs-channel-link.sh deleted file mode 100755 index c2aae3094b5..00000000000 --- a/multichain-testing/scripts/setup-xcs-channel-link.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -set -euo pipefail -shopt -s expand_aliases - -alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" -alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" -alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" - -REGISTRY_ADDRESS=$(osmosis-cli "jq -r '.crosschain_registry.address' /contract-info.json") - -CHAIN_A="$1" -CHAIN_B="$2" - -CHANNEL_INFO=$(hermes-exec --json query channels --show-counterparty --chain "${CHAIN_A}local" \ - | jq --arg CHAIN_B_LOCAL "${CHAIN_B}local" '.result[] | select(.chain_id_b == $CHAIN_B_LOCAL)') - -CHAIN_A_CHAIN_B_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_a') -CHAIN_B_CHAIN_A_CHANNEL=$(echo "$CHANNEL_INFO" | jq -r '.channel_b') - -OSMOSIS_GENESIS_WALLET="genesis" -OSMOSIS_GENESIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_GENESIS_WALLET} -a) - -MAX_RETRIES="5" -DELAY="5" - -MODIFY_CHAIN_CHANNEL_LINKS=$(jq -n \ - --arg chainA "$CHAIN_A" \ - --arg chainB "$CHAIN_B" \ - --arg channelA "$CHAIN_A_CHAIN_B_CHANNEL" \ - --arg channelB "$CHAIN_B_CHAIN_A_CHANNEL" \ - '{ - modify_chain_channel_links: { - operations: [ - { - operation: "set", - source_chain: $chainA, - destination_chain: $chainB, - channel_id: $channelA - }, - { - operation: "set", - source_chain: $chainB, - destination_chain: $chainA, - channel_id: $channelB - } - ]} -}') - -GET_CHAIN_CHANNEL_LINKS=$(jq -n \ - --arg chainA "$CHAIN_A" \ - --arg chainB "$CHAIN_B" \ - '{ - get_channel_from_chain_pair: { - source_chain: $chainA, - destination_chain: $chainB, - } -}') - -echo "Modifying chain channel links ..." -osmosis-exec tx wasm execute "$REGISTRY_ADDRESS" "$MODIFY_CHAIN_CHANNEL_LINKS" --from "$OSMOSIS_GENESIS_ADDRESS" --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal - -echo "Querying chain channel links ..." -( - set +e - - for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - chain_channel_link=$(osmosis-exec query wasm contract-state smart "$REGISTRY_ADDRESS" "$GET_CHAIN_CHANNEL_LINKS" 2> /dev/null) - - if [[ $? -eq 0 && $chain_channel_link = "{\"data\":\"$CHAIN_A_CHAIN_B_CHANNEL\"}" ]]; then - echo "Chain channel link found:" - echo "$chain_channel_link" - break - fi - - if [[ $i -eq MAX_RETRIES ]]; then - echo "Chain channel link not registered after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Query failed. Waiting $DELAY seconds before retrying..." - sleep "$DELAY" - done -) diff --git a/multichain-testing/scripts/setup-xcs-prefix.sh b/multichain-testing/scripts/setup-xcs-prefix.sh deleted file mode 100755 index 37b328cdcde..00000000000 --- a/multichain-testing/scripts/setup-xcs-prefix.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -set -euo pipefail -shopt -s expand_aliases - -alias osmosis-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" -alias osmosis-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" -alias hermes-exec="kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes" - -REGISTRY_ADDRESS=$(osmosis-cli "jq -r '.crosschain_registry.address' /contract-info.json") - -OSMOSIS_GENESIS_WALLET="genesis" -OSMOSIS_GENESIS_ADDRESS=$(osmosis-exec keys show ${OSMOSIS_GENESIS_WALLET} -a) - -MAX_RETRIES="5" -DELAY="5" - -MODIFY_BECH32_PREFIXES=$(jq -n \ - '{ - modify_bech32_prefixes: { - operations: [ - { - operation: "set", - chain_name: "osmosis", - prefix: "osmo" - }, - { - operation: "set", - chain_name: "agoric", - prefix: "agoric" - }, - { - operation: "set", - chain_name: "cosmoshub", - prefix: "cosmos" - } - ] - } -}') - -GET_BECH32_PREFIXES=$(jq -n \ - '{ - get_bech32_prefix_from_chain_name: { - chain_name: "osmosis", - } -}') - -echo "Modifying prefixes ..." -osmosis-exec tx wasm execute "$REGISTRY_ADDRESS" "$MODIFY_BECH32_PREFIXES" --from "$OSMOSIS_GENESIS_ADDRESS" --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal - -echo "Querying prefixes ..." -( - set +e - - for ((i = 1; i <= MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - chain_channel_link=$(osmosis-exec query wasm contract-state smart "$REGISTRY_ADDRESS" "$GET_BECH32_PREFIXES" 2> /dev/null) - - if [[ $? -eq 0 && $chain_channel_link = '{"data":"osmo"}' ]]; then - echo "Prefixes found:" - echo "$chain_channel_link" - break - fi - - if [[ $i -eq MAX_RETRIES ]]; then - echo "Prefixes not registered after $MAX_RETRIES attempts." - exit 1 - fi - - echo "Query failed. Waiting $DELAY seconds before retrying..." - sleep "$DELAY" - done -) diff --git a/multichain-testing/scripts/setup-xcs.sh b/multichain-testing/scripts/setup-xcs.sh deleted file mode 100755 index 53c0c3b727a..00000000000 --- a/multichain-testing/scripts/setup-xcs.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/bash - -set -euo pipefail -shopt -s expand_aliases - -alias osmo-exec="kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd" -alias osmo-cli="kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c" - -OSMOSIS_BRANCH="$1" - -RPC=http://localhost:26655 -TX_FLAGS="--keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal" -OWNER=genesis -OWNER_ADDRESS=$(osmo-exec keys show genesis -a) -CONTRACT_INFO_HEX=636F6E74726163745F696E666F - -COMMON_INSTANTIATE_MSG="{\"owner\": \"$OWNER_ADDRESS\"}" - -wait_for_blocks() { - local num_blocks="$1" - local rpc="${2:-$RPC}" - - echo "Fetching current height from $rpc..." - - local start_height - start_height=$(curl -s "$rpc/status" | jq -r '.result.sync_info.latest_block_height') - - if [[ -z "$start_height" || "$start_height" == "null" ]]; then - echo "Failed to fetch block height" - return 1 - fi - - local target_height=$((start_height + num_blocks)) - echo "Waiting for $num_blocks blocks... (target: $target_height)" - - while true; do - local current_height - current_height=$(curl -s "$rpc/status" | jq -r '.result.sync_info.latest_block_height') - - if [[ "$current_height" -ge "$target_height" ]]; then - echo "Reached target height: $current_height" - break - else - echo "Current height: $current_height — waiting..." - sleep 2 - fi - done -} - -check_data_not_null() { - local json="$1" - local error_message="${2:-'data is null'}" - - local data - data=$(echo "$json" | jq -r '.data') - - if [[ "$data" == "null" ]]; then - echo "$error_message" - exit 1 - else - echo "contract initiated successfully: $(echo $data | base64 -d)" - fi -} - -echo "Prepare download script inside osmosislocal-genesis-0 pod so that we can deploy wasm contracts..." -cat ./scripts/download-wasm-artifacts.sh | osmo-cli "tee /download-wasm-artifacts.sh > /dev/null" - -echo "Set newly created file's permissions..." -osmo-cli "chmod 755 /download-wasm-artifacts.sh" - -# Pass branch as argument TODO -echo "Download artifacts for XCS..." -osmo-cli "/download-wasm-artifacts.sh osmosis-labs osmosis $OSMOSIS_BRANCH tests/ibc-hooks/bytecode /wasm-artifacts crosschain_swaps.wasm swaprouter.wasm crosschain_registry.wasm" - -echo "Storing Swaprouter code..." -osmo-exec tx wasm store /wasm-artifacts/swaprouter.wasm --from $OWNER $TX_FLAGS -wait_for_blocks 5 - -SWAPROUTER_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') - -echo "Instantiating Swaprouter..." -osmo-exec tx wasm instantiate "$SWAPROUTER_CODE_ID" "$COMMON_INSTANTIATE_MSG" --from $OWNER --label swaprouter --admin $OWNER_ADDRESS $TX_FLAGS -wait_for_blocks 5 - -SWAPROUTER_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$SWAPROUTER_CODE_ID" -o json | jq -r '.contracts | [last][0]') -echo "Swaprouter address: $SWAPROUTER_ADDRESS" - -echo "Storing Crosschain Registry code..." -osmo-exec tx wasm store /wasm-artifacts/crosschain_registry.wasm --from $OWNER $TX_FLAGS -wait_for_blocks 5 -CROSSCHAIN_REGISTRY_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') - -echo "Crosschain Registry code id: $CROSSCHAIN_REGISTRY_CODE_ID" - -echo "Instantiating Crosschain Registry..." -osmo-exec tx wasm instantiate "$CROSSCHAIN_REGISTRY_CODE_ID" "$COMMON_INSTANTIATE_MSG" --from $OWNER --label crosschain_registry --admin $OWNER_ADDRESS $TX_FLAGS -wait_for_blocks 5 - -CROSSCHAIN_REGISTRY_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$CROSSCHAIN_REGISTRY_CODE_ID" -o json | jq -r '.contracts | [last][0]') -echo "Crosschain Registry address: $CROSSCHAIN_REGISTRY_ADDRESS" - -echo "Storing Crosschain Swaps code..." -osmo-exec tx wasm store /wasm-artifacts/crosschain_swaps.wasm --from $OWNER $TX_FLAGS -wait_for_blocks 5 -CROSSCHAIN_SWAPS_CODE_ID=$(osmo-exec query wasm list-code -o json | jq -r '.code_infos[-1].code_id') - -XCS_INSTANTIATE_MSG="{\"swap_contract\": \"$SWAPROUTER_ADDRESS\", \"governor\": \"$OWNER_ADDRESS\", \"registry_contract\": \"$CROSSCHAIN_REGISTRY_ADDRESS\"}" - -echo "Instantiating Crosschain Swaps contract..." -osmo-exec tx wasm instantiate "$CROSSCHAIN_SWAPS_CODE_ID" "$XCS_INSTANTIATE_MSG" --from $OWNER --label crosschain_swaps --admin $OWNER_ADDRESS $TX_FLAGS -wait_for_blocks 5 - -CROSSCHAIN_SWAPS_ADDRESS=$(osmo-exec query wasm list-contract-by-code "$CROSSCHAIN_SWAPS_CODE_ID" -o json | jq -r '.contracts | [last][0]') -echo "Crosschain Swaps address: $CROSSCHAIN_SWAPS_ADDRESS" - -echo "Persist contract information..." - -osmo-cli 'cat >/contract-info.json' << EOF -{ - "swaprouter": {"codeId": "${SWAPROUTER_CODE_ID}", "address": "${SWAPROUTER_ADDRESS}"}, - "crosschain_registry": {"codeId": "${CROSSCHAIN_REGISTRY_CODE_ID}", "address": "${CROSSCHAIN_REGISTRY_ADDRESS}"}, - "crosschain_swaps": {"codeId": "${CROSSCHAIN_SWAPS_CODE_ID}", "address": "${CROSSCHAIN_SWAPS_ADDRESS}"} -} -EOF - -echo "Contract Information" -osmo-cli 'cat /contract-info.json' - -echo "Check instantiations..." -swaprouterContractInfo=$(osmo-exec q wasm contract-state raw $SWAPROUTER_ADDRESS $CONTRACT_INFO_HEX -o json) -check_data_not_null $swaprouterContractInfo "swaprouter not instantiated correctly" - -registryContractInfo=$(osmo-exec q wasm contract-state raw $CROSSCHAIN_REGISTRY_ADDRESS $CONTRACT_INFO_HEX -o json) -check_data_not_null $registryContractInfo "crosschain_registry not instantiated correctly" - -xcsContractInfo=$(osmo-exec q wasm contract-state raw $CROSSCHAIN_SWAPS_ADDRESS $CONTRACT_INFO_HEX -o json) -check_data_not_null $xcsContractInfo "crosschain_swaps not instantiated correctly" diff --git a/multichain-testing/test/xcs-swap-anything/Makefile b/multichain-testing/test/xcs-swap-anything/Makefile deleted file mode 100644 index 4b340da2b70..00000000000 --- a/multichain-testing/test/xcs-swap-anything/Makefile +++ /dev/null @@ -1,108 +0,0 @@ -cli-hermes=kubectl exec -i hermes-agoric-osmosis-0 -c relayer -- hermes -exec-agd=kubectl exec -i agoriclocal-genesis-0 -c validator -- agd -exec-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd -cli-osmo=kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c - -AGORIC_TEST_ADDRESS=$(shell $(exec-agd) keys show test1 -a --keyring-backend test) -AGORIC_GENESIS_ADDRESS=$(shell $(exec-agd) keys show genesis -a --keyring-backend test) -OSMOSIS_TEST_ADDRESS=$(shell $(exec-osmo) keys show test1 -a --keyring-backend test) -OSMOSIS_GENESIS_ADDRESS = $(shell $(exec-osmo) keys show genesis -a --keyring-backend test) - -TX_FLAGS=--from $(OSMOSIS_GENESIS_ADDRESS) --keyring-backend=test --gas=auto --gas-prices 0.1uosmo --gas-adjustment 1.3 --yes --chain-id osmosislocal -AGD_TX_FLAGS=--from $(AGORIC_GENESIS_ADDRESS) --keyring-backend=test --gas=auto --gas-prices 0.1ubld --gas-adjustment 1.3 --yes --chain-id agoriclocal - -CHANNEL_INFO=$(shell $(cli-hermes) --json query channels --show-counterparty --chain agoriclocal \ - | jq '[.][] | select(.result) | .result[] | select(.chain_id_b == "osmosislocal")') -AGORIC_OSMOSIS_CHANNEL=$(shell echo '$(CHANNEL_INFO)' | jq -r '.channel_a') -OSMOSIS_AGORIC_CHANNEL=$(shell echo '$(CHANNEL_INFO)' | jq -r '.channel_b') - -REGISTRY_ADDRESS="osmo1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqvlx82r" -SWAPROUTER_ADDRESS="osmo14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sq2r9g9" -SWAP_ADDRESS="osmo17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgs5yczr8" - -POOL_ASSET_1_DENOM="uosmo" -POOL_ASSET_1_AMOUNT="250000" -POOL_ASSET_2_DENOM="ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596" - -GET_ROUTE_JSON = '{"get_route":{"input_denom":$(POOL_ASSET_2_DENOM),"output_denom":$(POOL_ASSET_1_DENOM)}}' -SET_CHAIN_CHANNEL_LINKS='{"modify_chain_channel_links":{"operations":[{"operation":"set","source_chain":"agoric","destination_chain":"osmosis","channel_id":"$(AGORIC_OSMOSIS_CHANNEL)"},{"operation":"set","source_chain":"osmosis","destination_chain":"agoric","channel_id":"$(OSMOSIS_AGORIC_CHANNEL)"}]}}' -SET_PREFIXES_MSG='{"modify_bech32_prefixes":{"operations":[{"operation":"set","chain_name":"osmosis","prefix":"osmo"},{"operation":"set","chain_name":"agoric","prefix":"agoric"}]}}' -GET_CHANNEL_FROM_CHAINS_MSG='{"get_channel_from_chain_pair":{"source_chain":"osmosis","destination_chain":"agoric"}}' -GET_PREFIX_FROM_CHAIN_MSG='{"get_bech32_prefix_from_chain_name":{"chain_name":"osmosis"}}' - -GOOD_SWAP_MEMO='{"wasm":{"contract":$(SWAP_ADDRESS),"msg":{"osmosis_swap":{"output_denom":"uosmo","slippage":{"twap":{"window_seconds":10,"slippage_percentage":"20"}},"receiver":"agoric1elueec97as0uwavlxpmj75u5w7yq9dgphq47zx","on_failed_delivery":"do_nothing", "next_memo":{}}}}}' -BAD_SWAP_MEMO=' \ -{"wasm":{ \ - "contract":"$(SWAP_ADDRESS)", \ - "msg":{ \ - "osmosis_swap":{ \ - "output_denom":"uosmo", \ - "slippage":{ \ - "twap":{ \ - "window_seconds":10, \ - "slippage_percentage":"20" \ - } \ - }, \ - "receiver":"$(AGORIC_GENESIS_ADDRESS)", \ - "on_failed_delivery":"do_nothing", \ - "next_memo":{} \ - } \ - } \ -}}' - -print-wasm-info: - $(cli-osmo) "cat /contract-info.json" - -print-channel-info: - @echo $(CHANNEL_INFO) - -print-agoric-channel: - @echo $(AGORIC_OSMOSIS_CHANNEL) - -print-osmosis-channel: - @echo $(OSMOSIS_AGORIC_CHANNEL) - -print-osmosis-address: - echo '$(AGORIC_GENESIS_ADDRESS)' - -versions: - $(cli-hermes) --version - $(exec-agd) version - $(exec-osmo) version - -query-channels: - $(cli-hermes) query channels --show-counterparty --chain $(CHAIN) - -query-balance-osmo: - $(exec-osmo) query bank balances $(OSMOSIS_TEST_ADDRESS) | jq - -query-balance-agoric: - $(exec-agd) query bank balances agoric1elueec97as0uwavlxpmj75u5w7yq9dgphq47zx | jq - -query-route: - $(exec-osmo) q wasm contract-state smart $(SWAPROUTER_ADDRESS) $(GET_ROUTE_JSON) - -query-pool-balance: - $(exec-osmo) q gamm pool 1 | jq - -query-tx-osmo: - $(exec-osmo) q tx $(TX_HASH) | jq . - -query-tx-agoric: - $(exec-agd) q tx $(TX_HASH) | jq . - -query-channel-from-registry: - $(exec-osmo) q wasm contract-state smart $(REGISTRY_ADDRESS) $(GET_CHANNEL_FROM_CHAINS_MSG) | jq . - -query-prefix-from-registry: - $(exec-osmo) q wasm contract-state smart $(REGISTRY_ADDRESS) $(GET_PREFIX_FROM_CHAIN_MSG) | jq . - -tx-chain-channel-links: - $(exec-osmo) tx wasm execute $(REGISTRY_ADDRESS) $(SET_CHAIN_CHANNEL_LINKS) $(TX_FLAGS) - -tx-bec32-prefixes: - $(exec-osmo) tx wasm execute $(REGISTRY_ADDRESS) $(SET_PREFIXES_MSG) $(TX_FLAGS) - -tx-send-xcs-ibc-transfer: - $(exec-agd) tx ibc-transfer transfer transfer $(AGORIC_OSMOSIS_CHANNEL) $(SWAP_ADDRESS) 125ubld \ - --memo $(GOOD_SWAP_MEMO) $(AGD_TX_FLAGS) \ No newline at end of file diff --git a/multichain-testing/scripts/download-wasm-artifacts.sh b/multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh similarity index 100% rename from multichain-testing/scripts/download-wasm-artifacts.sh rename to multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index 99cc5fa25ac..7d3a1001343 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -1,237 +1,813 @@ +import { osmosis } from 'osmojs'; +import { + MsgStoreCode, + MsgExecuteContract, + MsgInstantiateContract, + MsgStoreCodeResponse, + MsgInstantiateContractResponse, +} from 'cosmjs-types/cosmwasm/wasm/v1/tx.js'; +import type { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; +import type { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin.js'; +import type { SigningStargateClient } from '@cosmjs/stargate'; +import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'; +import { toUtf8 } from '@cosmjs/encoding'; +import { execa } from 'execa'; +import { writeFileSync } from 'fs'; +import fs from 'fs/promises'; +import path from 'path'; import { createFundedWalletAndClient, makeIBCTransferMsg, } from '../../tools/ibc-transfer.js'; -import { execa } from 'execa'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import starshipChainInfo from '../../starship-chain-info.js'; +import { makeQueryClient } from '../../tools/query.js'; +import type { SetupContextWithWallets } from '../support.js'; +import { makeBlockTool } from '../../tools/e2e-tools.js'; +import { makeHttpClient } from '../../tools/makeHttpClient.js'; + +export type SetupOsmosisContext = Awaited>; +export type SetupOsmosisContextWithCommon = SetupOsmosisContext & + SetupContextWithWallets; + +export type Prefix = { + chain: string; + prefix: string; +}; -export const fundRemote = async ( - t, - destinationChain, - denomToTransfer = 'ubld', - amount = 100000000n, -) => { - const { retryUntilCondition, useChain } = t.context; +export type Channel = { + primary: string; + counterParty: string; +}; - const { client, address, wallet } = await createFundedWalletAndClient( - t.log, - destinationChain, - useChain, - ); - const balancesResult = await retryUntilCondition( - () => client.getAllBalances(address), - coins => !!coins?.length, - `Faucet balances found for ${address}`, - ); - console.log('Balances:', balancesResult); +export type OsmosisPool = { + issuingChain: string; + issuingDenom: string; +}; - const { client: agoricClient, address: agoricAddress } = - await createFundedWalletAndClient(t.log, 'agoric', useChain); +type ContractInfoBase = { + codeId: number | null; + address: string | null; + label: string; + instantiateArgs: TArgs; +}; - const balancesResultAg = await retryUntilCondition( - () => agoricClient.getAllBalances(agoricAddress), - coins => !!coins?.length, - `Faucet balances found for ${agoricAddress}`, - ); - console.log('Balances AGORIC:', balancesResultAg); +type CommonArgs = { + owner: string; +}; + +type CrosschainSwapsArgs = { + swap_contract: string | null; + registry_contract: string | null; + governor: string; +}; + +type Contracts = { + swaprouter: ContractInfoBase; + crosschain_registry: ContractInfoBase; + crosschain_swaps: ContractInfoBase; +}; + +export const osmosisSwapTools = async t => { + const { useChain, retryUntilCondition } = t.context; + + const { waitForBlock } = makeBlockTool({ + rpc: makeHttpClient('http://localhost:26657', fetch), + delay: ms => new Promise(resolve => setTimeout(resolve, ms)), + }); + + const osmosisBranch = 'main'; + const scriptLocalPath = './test/xcs-swap-anything/download-wasm-artifacts.sh'; + const xcsArtifactsPath = './test/xcs-swap-anything/wasm-artifacts'; + + const osmosisMnemonic = + 'run leaf ritual orchard traffic kit kidney gaze diamond large brass believe wreck trade plate alter fox party flavor reform hospital powder art have'; - const transferArgs = makeIBCTransferMsg( - { denom: denomToTransfer, value: amount }, - { address, chainName: destinationChain }, - { address: agoricAddress, chainName: 'agoric' }, - Date.now(), + const { + client: osmosisClient, + address: osmosisAddress, + wallet: osmosisWallet, + } = await createFundedWalletAndClient( + t.log, + 'osmosis', useChain, + osmosisMnemonic, ); - console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await agoricClient.sendIbcTokens(...transferArgs); - if (txRes && txRes.code !== 0) { - console.error(txRes); - throw Error(`failed to ibc transfer funds to ${denomToTransfer}`); - } - const { events: _events, ...txRest } = txRes; - console.log(txRest); - t.is(txRes.code, 0, `Transaction succeeded`); - t.log(`Funds transferred to ${agoricAddress}`); await retryUntilCondition( - () => client.getAllBalances(address), - coins => !!coins?.length, - `${denomToTransfer} transferred to ${address}`, + () => osmosisClient.getAllBalances(osmosisAddress), + (coins: Coin[]) => !!coins?.length, + `Faucet balances found for ${osmosisAddress}`, ); - return { - client, - address, - wallet, + const { getRpcEndpoint } = useChain('osmosis'); + const osmosisRpcEndpoint = await getRpcEndpoint(); + + let xcsContracts: Contracts = { + swaprouter: { + codeId: null, + address: null, + label: 'swaprouter', + instantiateArgs: { owner: osmosisAddress }, + }, + crosschain_registry: { + codeId: null, + address: null, + label: 'crosschain_registry', + instantiateArgs: { owner: osmosisAddress }, + }, + crosschain_swaps: { + codeId: null, + address: null, + label: 'crosschain_swaps', + instantiateArgs: { + swap_contract: null, + registry_contract: null, + governor: osmosisAddress, + }, + }, }; -}; -const filename = fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); + const fundRemote = async ( + issuingChain: string, + issuingDenom: string = 'ubld', + destinationChain?: string, + amount: bigint = 100000000n, + ) => { + const { client: issuingClient, address: issuingAddress } = + await createFundedWalletAndClient(t.log, issuingChain, useChain); + + await retryUntilCondition( + () => issuingClient.getAllBalances(issuingAddress), + (coins: Coin[]) => !!coins?.length, + `Faucet balances not found for issuing address: ${issuingAddress}`, + ); -export const setupXcsContracts = async t => { - console.log('Setting XCS Contracts ...'); - const osmosisBranch = 'main'; - try { - const scriptPath = path.resolve(dirname, '../../scripts/setup-xcs.sh'); - const { stdout } = await execa(scriptPath, [osmosisBranch]); - console.log('setup-xcs script output:', stdout); - } catch (error) { - t.fail(`setup-xcs script failed with error: ${error}`); - } -}; + let destinationClient: SigningStargateClient; + let destinationAddress: string; + let destinationWallet: DirectSecp256k1HdWallet; + + if (destinationChain) { + const { client, address, wallet } = await createFundedWalletAndClient( + t.log, + destinationChain, + useChain, + ); + + await retryUntilCondition( + () => client.getAllBalances(address), + (coins: Coin[]) => !!coins?.length, + `Faucet balances not found for destination address: ${address}`, + ); + + destinationClient = client; + destinationAddress = address; + destinationWallet = wallet; + } else { + destinationChain = 'osmosis'; + destinationClient = osmosisClient; + destinationAddress = osmosisAddress; + destinationWallet = osmosisWallet; + } + + const destinationBalanceBefore = + await destinationClient.getAllBalances(destinationAddress); + t.log( + 'destination wallet balances before transfer: ', + destinationBalanceBefore, + ); -export const createOsmosisPool = async t => { - console.log('Creating Osmosis Pool ...'); - const tokenInDenom = 'ubld'; - const tokenInAmount = '250000'; - const tokenInWeight = '1'; - const tokenOutDenom = 'uosmo'; - const tokenOutAmount = '250000'; - const tokenOutWeight = '1'; - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/create-osmosis-pool.sh', + const transferArgs = makeIBCTransferMsg( + { denom: issuingDenom, value: amount }, + { address: destinationAddress, chainName: destinationChain }, + { address: issuingAddress, chainName: issuingChain }, + Date.now(), + useChain, ); - const { stdout } = await execa(scriptPath, [ - tokenInDenom, - tokenInAmount, - tokenInWeight, - tokenOutDenom, - tokenOutAmount, - tokenOutWeight, - ]); - console.log('create-osmosis-pool script output:', stdout); - } catch (error) { - t.fail(`create-osmosis-pool failed with error: ${error}`); - } -}; -export const setupXcsChannelLink = async (t, chainA, chainB) => { - console.log('Setting XCS Channel Links ...'); - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/setup-xcs-channel-link.sh', + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await issuingClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ${destinationAddress}`); + } + t.is(txRes.code, 0, `Transaction succeeded`); + console.log('sendIbcTokens TxResponse: ', txRes); + + const denom = await getDenomHash( + destinationChain, + issuingChain, + issuingDenom, ); - const { stdout } = await execa(scriptPath, [chainA, chainB]); - console.log('channel link setup output:', stdout); - } catch (error) { - t.fail(`channel link setup failed with error: ${error}`); - } -}; -export const setupXcsPrefix = async t => { - console.log('Setting XCS Prefixes ...'); - try { - const scriptPath = path.resolve( - dirname, - '../../scripts/setup-xcs-prefix.sh', + const getDenomAmount = balances => { + const balance = balances.find(coin => coin.denom === `ibc/${denom}`); + const amount = balance ? Number(balance.amount) : 0; + return amount; + }; + + await retryUntilCondition( + () => destinationClient.getAllBalances(destinationAddress), + (coins: Coin[]) => { + const before = getDenomAmount(destinationBalanceBefore); + const current = getDenomAmount(coins); + return current > before; + }, + `Transferred tokens not found on destination address: ${destinationAddress}`, ); - const { stdout } = await execa(scriptPath); - console.log('prefix setup output:', stdout); - } catch (error) { - t.fail(`prefix setup failed with error: ${error}`); - } -}; + console.log( + `Transferred tokens found on destination address: ${destinationAddress}`, + ); + + return { + client: destinationClient, + address: destinationAddress, + wallet: destinationWallet, + }; + }; -export const getXcsContractsAddress = async () => { - const osmosisCLI = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; + const invokeOsmosisContract = async (contractAddress: string, txMsg) => { + const clientRegistry = osmosisClient.registry; + clientRegistry.register(MsgExecuteContract.typeUrl, MsgExecuteContract); + + const fee = { + amount: [{ denom: 'uosmo', amount: '1000' }], + gas: '200000', + }; + + const message = MsgExecuteContract.fromPartial({ + sender: osmosisAddress, + contract: contractAddress, + msg: toUtf8(JSON.stringify(txMsg)), + funds: [], + }); + + const encodeObjects: Array = [ + { + typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', + value: message, + }, + ]; + + const response = await osmosisClient.signAndBroadcast( + osmosisAddress, + encodeObjects, + fee, + ); + console.log("invokeOsmosisContract DeliverTxResponse: ", response); - const registryQuery = `${osmosisCLI} "jq -r '.crosschain_registry.address' /contract-info.json"`; - const swaprouterQuery = `${osmosisCLI} "jq -r '.swaprouter.address' /contract-info.json"`; - const swapQuery = `${osmosisCLI} "jq -r '.crosschain_swaps.address' /contract-info.json"`; - const { stdout: registryAddress } = await execa(registryQuery, { - shell: true, - }); - const { stdout: swaprouterAddress } = await execa(swaprouterQuery, { - shell: true, - }); - const { stdout: swapAddress } = await execa(swapQuery, { shell: true }); + const { msgResponses, code } = response - return { registryAddress, swaprouterAddress, swapAddress }; -}; + if (code !== 0) { + throw Error(`Failed to execute osmosis contract with message ${message}`); + } -export const getXcsState = async () => { - const { registryAddress } = await getXcsContractsAddress(); + return msgResponses; + }; - const osmosisExecQuery = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + const queryOsmosisContract = async (contractAddress: string, queryMsg) => { + const wasmClient = await CosmWasmClient.connect(osmosisRpcEndpoint); + const result = await wasmClient.queryContractSmart( + contractAddress, + queryMsg, + ); - const channelObj = { - get_channel_from_chain_pair: { - source_chain: 'osmosis', - destination_chain: 'agoric', - }, + return result; }; - const channelJson = `'${JSON.stringify(channelObj)}'`; - const channelQuery = `${osmosisExecQuery} ${registryAddress} ${channelJson}`; - const { stdout: channel } = await execa(channelQuery, { - shell: true, - }); + const downloadXcsContracts = async ( + xcsContracts, + branch: string = osmosisBranch, + scriptPath: string = scriptLocalPath, + artifactsPath: string = xcsArtifactsPath, + ) => { + const wasmFiles: string[] = []; + for (const contract in xcsContracts) { + if (Object.prototype.hasOwnProperty.call(xcsContracts, contract)) { + const { label } = xcsContracts[contract]; + wasmFiles.push(`${label}.wasm`); + } + } + + try { + await execa('bash', [ + scriptPath, + 'osmosis-labs', + 'osmosis', + branch, + 'tests/ibc-hooks/bytecode', + artifactsPath, + ...wasmFiles, + ]); + } catch (error) { + throw Error(`Failed to download XCS artifacts: ${error}`); + } + }; - const prefixObj = { - get_bech32_prefix_from_chain_name: { - chain_name: 'osmosis', - }, + const instantiateSingleXcsContract = async ( + contractLabel: string, + instantiateArgs: CommonArgs | CrosschainSwapsArgs, + ) => { + const clientRegistry = osmosisClient.registry; + clientRegistry.register(MsgStoreCode.typeUrl, MsgStoreCode); + + clientRegistry.register( + MsgInstantiateContract.typeUrl, + MsgInstantiateContract, + ); + + const contractPath = `${xcsArtifactsPath}/${contractLabel}.wasm`; + + const wasmPath = path.resolve(contractPath); + const wasmByteCode = await fs.readFile(wasmPath); + + const fee = { + amount: [{ denom: 'uosmo', amount: '100000' }], + gas: '10000000', + }; + + const storeMessage = MsgStoreCode.fromPartial({ + sender: osmosisAddress, + wasmByteCode, + }); + + const storeEncodeObjects: Array< + import('@cosmjs/proto-signing').EncodeObject + > = [ + { + typeUrl: MsgStoreCode.typeUrl, + value: storeMessage, + }, + ]; + + const storeResult = await osmosisClient.signAndBroadcast( + osmosisAddress, + storeEncodeObjects, + fee, + ); + + if (storeResult.msgResponses[0] && storeResult.code !== 0) { + throw Error(`Failed to store ${contractLabel} contract`); + } + + const codeId = MsgStoreCodeResponse.decode( + storeResult.msgResponses[0].value, + ).codeId; + + const instantiateMessage = MsgInstantiateContract.fromPartial({ + sender: osmosisAddress, + admin: osmosisAddress, + codeId, + label: contractLabel, + msg: toUtf8(JSON.stringify(instantiateArgs)), + }); + + const instantiateEncodeObjects: Array< + import('@cosmjs/proto-signing').EncodeObject + > = [ + { + typeUrl: MsgInstantiateContract.typeUrl, + value: instantiateMessage, + }, + ]; + + const instantiateResult = await osmosisClient.signAndBroadcast( + osmosisAddress, + instantiateEncodeObjects, + fee, + ); + + if (instantiateResult.msgResponses[0] && instantiateResult.code !== 0) { + throw Error(`Failed to instantiate ${contractLabel} contract`); + } + + const address = MsgInstantiateContractResponse.decode( + instantiateResult.msgResponses[0].value, + ).address; + + return { codeId, address }; }; - const prefixJson = `'${JSON.stringify(prefixObj)}'`; - const prefixQuery = `${osmosisExecQuery} ${registryAddress} ${prefixJson}`; - const { stdout: prefix } = await execa(prefixQuery, { - shell: true, - }); + const persistXcsInfo = async () => { + try { + const sanitizedContracts = JSON.parse( + JSON.stringify(xcsContracts, (_, v) => + typeof v === 'bigint' ? Number(v) : v, + ), + ); + writeFileSync( + './test/xcs-swap-anything/xcs-contracts-info.json', + JSON.stringify(sanitizedContracts), + ); + + await execa('kubectl', [ + 'cp', + './test/xcs-swap-anything/xcs-contracts-info.json', + 'osmosislocal-genesis-0:/', + ]); + } catch (error) { + throw Error(`Failed to store XCS info: ${error}`); + } + }; - const channelData = JSON.parse(channel).data; - const prefixData = JSON.parse(prefix).data; + const areContractsInstantiated = async () => { + let contractInfo; + try { + contractInfo = await queryContractsInfo(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + return false; + } + + const sanitizedContracts = JSON.parse( + JSON.stringify(xcsContracts, (_, v) => + typeof v === 'bigint' ? Number(v) : v, + ), + ); + if (JSON.stringify(contractInfo) != JSON.stringify(sanitizedContracts)) { + xcsContracts = contractInfo; + } + return true; + }; - return { channelData, prefixData }; -}; + const setupXcsChannelLink = async ( + primaryChain: string, + counterPartyChain: string, + ) => { + const chainId = useChain(counterPartyChain).chain.chain_id; + const registryAddress = xcsContracts.crosschain_registry.address; + if (!registryAddress) { + throw new Error('crosschain_registry contract address not found'); + } + + const { + transferChannel: { channelId, counterPartyChannelId }, + } = starshipChainInfo[primaryChain].connections[chainId]; + + const txMsg = { + modify_chain_channel_links: { + operations: [ + { + operation: 'set', + source_chain: primaryChain, + destination_chain: counterPartyChain, + channel_id: channelId, + }, + { + operation: 'set', + source_chain: counterPartyChain, + destination_chain: primaryChain, + channel_id: counterPartyChannelId, + }, + ], + }, + }; + + await invokeOsmosisContract(registryAddress, txMsg); + }; -export const getPoolRoute = async () => { - const { swaprouterAddress } = await getXcsContractsAddress(); + const setupXcsPrefix = async (name: string, prefix: string) => { + const registryAddress = xcsContracts.crosschain_registry.address; + if (!registryAddress) { + throw new Error('crosschain_registry contract address not found'); + } + + const txMsg = { + modify_bech32_prefixes: { + operations: [ + { + operation: 'set', + chain_name: name, + prefix: prefix, + }, + ], + }, + }; + + await invokeOsmosisContract(registryAddress, txMsg); + }; - const osmosisExecQuery = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd query wasm contract-state smart'; + const isXcsStateSet = async (channelList: Channel[]) => { + try { + for (const channel of channelList) { + await getXcsState(channel); + t.log( + `Xcs State verified for ${channel.primary} ${channel.counterParty}`, + ); + } + return true; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + return false; + } + }; - const routeObj = { - get_route: { - input_denom: - 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', - output_denom: 'uosmo', - }, + const createPoolAgainstOsmo = async ( + issuingChain: string, + issuingDenom: string, + tokensAmount: string = '1000000', + ) => { + const clientRegistry = osmosisClient.registry; + osmosis.gamm.poolmodels.balancer.v1beta1.load(clientRegistry); + + const MsgCreateBalancerPool = + osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPool; + const MsgCreateBalancerPoolResponse = + osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPoolResponse; + + const fee = { + amount: [{ denom: 'uosmo', amount: '10000' }], + gas: '1000000', + }; + + const hash = await getDenomHash('osmosis', issuingChain, issuingDenom); + + const message = MsgCreateBalancerPool.fromPartial({ + sender: osmosisAddress, + poolParams: { swapFee: '0.01', exitFee: '0.00' }, + poolAssets: [ + { token: { denom: 'uosmo', amount: tokensAmount }, weight: '1' }, + { + token: { + denom: `ibc/${hash}`, + amount: tokensAmount, + }, + weight: '1', + }, + ], + futurePoolGovernor: '', + }); + /** @type {Array} */ + const encodeObjects = [ + { + typeUrl: + '/osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPool', + value: message, + }, + ]; + + const response = await osmosisClient.signAndBroadcast( + osmosisAddress, + encodeObjects, + fee, + ); + + console.log("createPoolAgainstOsmo DeliverTxResponse: ", response); + + + const { msgResponses, code } = response + + if (msgResponses[0] && code !== 0) { + throw Error(`Failed to create pool with uosmo and ${issuingDenom}`); + } + + const poolId = MsgCreateBalancerPoolResponse.decode( + msgResponses[0].value, + ).poolId; + + return { poolId, hash }; }; - const routeJson = `'${JSON.stringify(routeObj)}'`; - const routeQuery = `${osmosisExecQuery} ${swaprouterAddress} ${routeJson}`; - const { stdout } = await execa(routeQuery, { - shell: true, - }); + const setPoolRoute = async ( + tokenIn: string, + tokenOut: string, + poolId: string, + ) => { + const swaprouterAddress = xcsContracts.swaprouter.address; + if (!swaprouterAddress) { + throw new Error('swaprouter contract address not found'); + } + + const txMsg = { + set_route: { + input_denom: tokenIn, + output_denom: tokenOut, + pool_route: [ + { + pool_id: poolId, + token_out_denom: tokenOut, + }, + ], + }, + }; + + await invokeOsmosisContract(swaprouterAddress, txMsg); + }; - const routeData = JSON.parse(stdout).data; - const route = routeData.pool_route[routeData.pool_route.length - 1]; + const isRouteSet = async (pool: OsmosisPool) => { + try { + await getPoolRoute(pool); + return true; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + return false; + } + }; - return route; -}; + const queryContractsInfo = async () => { + const osmosisCLI = + 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; -export const getPool = async poolId => { - const osmosisExec = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- osmosisd'; + const info = `${osmosisCLI} "jq . /xcs-contracts-info.json"`; - const poolQuery = `${osmosisExec} query gamm pool ${poolId}`; + const { stdout } = await execa(info, { + shell: true, + }); - const { stdout } = await execa(poolQuery, { - shell: true, - }); + return JSON.parse(stdout); + }; - const pool = JSON.parse(stdout).pool; + /* + * Note: `getDenomHash` should only be called after the issuingDenom token has been successfully + * transferred from the issuingChain to currentChain (e.g., using fundRemote() or a similar mechanism). + * If no such transfer has occurred, the function will return 'undefined' because the denomination + * is not yet recognized on the currentChain. + */ + const getDenomHash = async ( + currentChain: string, + issuingChain: string, + issuingDenom: string, + ) => { + const chainId = useChain(issuingChain).chain.chain_id; + + const { + transferChannel: { channelId }, + } = starshipChainInfo[currentChain].connections[chainId]; + + const apiUrl = await useChain(currentChain).getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const { hash } = await queryClient.queryDenom( + `transfer/${channelId}`, + issuingDenom, + ); - return pool; -}; + return hash; + }; + + const getPools = async () => { + const { createRPCQueryClient } = osmosis.ClientFactory; + const client = await createRPCQueryClient({ + rpcEndpoint: osmosisRpcEndpoint, + }); + const { pools } = await client.osmosis.gamm.v1beta1.pools(); + return pools; + }; + + const getXcsState = async (channel: Channel) => { + const registryAddress = xcsContracts.crosschain_registry.address; + if (!registryAddress) { + throw new Error('crosschain_registry contract address not found'); + } + + const { primary, counterParty } = channel; + + const channelQuery = { + get_channel_from_chain_pair: { + source_chain: primary, + destination_chain: counterParty, + }, + }; + + const channelId = await queryOsmosisContract(registryAddress, channelQuery); + + const prefixQuery = { + get_bech32_prefix_from_chain_name: { + chain_name: counterParty, + }, + }; + const prefix = await queryOsmosisContract(registryAddress, prefixQuery); + + return { channelId, prefix }; + }; + + const getPoolRoute = async (pool: OsmosisPool) => { + const swaprouterAddress = xcsContracts.swaprouter.address; + if (!swaprouterAddress) { + throw new Error('swaprouter contract address not found'); + } + + const { issuingChain, issuingDenom } = pool; + + const hash = await getDenomHash('osmosis', issuingChain, issuingDenom); + const queryMsg = { + get_route: { + input_denom: `ibc/${hash}`, + output_denom: 'uosmo', + }, + }; + + const { pool_route } = await queryOsmosisContract( + swaprouterAddress, + queryMsg, + ); + + return pool_route; + }; + + const getContractsInfo = () => xcsContracts; + + const getOsmosisAccount = () => { + return { + client: osmosisClient, + address: osmosisAddress, + wallet: osmosisWallet, + }; + }; + + const setupXcsContracts = async (forceInstall = false) => { + console.log('Seeting XCS contracts ...'); + if (!(await areContractsInstantiated()) || forceInstall) { + console.log(`XCS contracts being downloaded ...`); + await downloadXcsContracts(xcsContracts); + + console.log(`XCS contracts being instantiated ...`); + for (const contract in xcsContracts) { + const { label, instantiateArgs } = xcsContracts[contract]; + const { codeId, address } = await instantiateSingleXcsContract( + label, + instantiateArgs, + ); + xcsContracts[contract].codeId = codeId; + xcsContracts[contract].address = address; + + if (label === 'swaprouter') { + xcsContracts.crosschain_swaps.instantiateArgs.swap_contract = address; + } else if (label === 'crosschain_registry') { + xcsContracts.crosschain_swaps.instantiateArgs.registry_contract = + address; + } + } + + console.log(`XCS contracts being persisted ...`); + await persistXcsInfo(); + } + + console.log('XCS contracts instantiation completed!'); + + return xcsContracts; + }; + + const setupXcsState = async ( + prefixList: Prefix[], + channelList: Channel[], + ) => { + console.log('Seeting XCS state ...'); + + if (!(await isXcsStateSet(channelList))) { + for (const { chain, prefix } of prefixList) { + console.log(`Seeting Prefix for ${chain} ...`); + await setupXcsPrefix(chain, prefix); + } + + for (const { primary, counterParty } of channelList) { + console.log( + `Seeting Channel Link for ${primary} and ${counterParty} ...`, + ); + await setupXcsChannelLink(primary, counterParty); + } + } + + console.log('XCS state updated!'); + }; + + const setupOsmosisPools = async (osmosisPoolList: OsmosisPool[]) => { + for (const pool of osmosisPoolList) { + const { issuingChain, issuingDenom } = pool; + console.log(`Setting Osmosis pool for uosmo, ${issuingDenom} ...`); + + if (!(await isRouteSet(pool))) { + console.log(`Funding osmosis wallet with ${issuingDenom} ...`); + await fundRemote(issuingChain, issuingDenom); + + console.log(`Creating new pool ...`); + const { poolId, hash } = await createPoolAgainstOsmo( + issuingChain, + issuingDenom, + ); + + console.log(`Setting pool routes ...`); + const denomHash = `ibc/${hash}`; + await setPoolRoute('uosmo', denomHash, poolId.toString()); + await waitForBlock(5); + await setPoolRoute(denomHash, 'uosmo', poolId.toString()); + } + + console.log(`Osmosis pool for uosmo, ${issuingDenom} available!`); + } + }; + + return { + setupXcsContracts, + setupXcsState, + setupOsmosisPools, + fundRemote, + getDenomHash, + getContractsInfo, + getOsmosisAccount, + getPools, + getXcsState, + getPoolRoute, + }; +}; \ No newline at end of file diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index ab00f334745..c49909df956 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -3,28 +3,23 @@ import type { TestFn } from 'ava'; import { AmountMath } from '@agoric/ertp'; import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { makeBlockTool, makeDoOffer } from '../../tools/e2e-tools.js'; -import { commonSetup, type SetupContextWithWallets } from '../support.js'; +import { commonSetup } from '../support.js'; import { makeQueryClient } from '../../tools/query.js'; import starshipChainInfo from '../../starship-chain-info.js'; import { createFundedWalletAndClient, makeIBCTransferMsg, } from '../../tools/ibc-transfer.js'; -import { makeHttpClient } from '../../tools/makeHttpClient.js'; import type { OfferStatus } from '@agoric/smart-wallet/src/offers.js'; import { - fundRemote, - setupXcsContracts, - createOsmosisPool, - setupXcsChannelLink, - setupXcsPrefix, - getXcsContractsAddress, - getXcsState, - getPoolRoute, - getPool, + osmosisSwapTools, + type Prefix, + type Channel, + type SetupOsmosisContextWithCommon, + type OsmosisPool, } from './helpers.js'; -const test = anyTest as TestFn; +const test = anyTest as TestFn; const accounts = ['agoricSender', 'agoricReceiver']; @@ -32,55 +27,78 @@ const contractName = 'swapAnything'; const contractBuilder = '../packages/builders/scripts/testing/init-swap-anything.js'; +const prefixList: Prefix[] = [ + { chain: 'agoric', prefix: 'agoric' }, + { chain: 'osmosis', prefix: 'osmo' }, + { chain: 'cosmoshub', prefix: 'cosmos' }, +]; + +const channelList: Channel[] = [ + { primary: 'agoric', counterParty: 'osmosis' }, + { primary: 'agoric', counterParty: 'cosmoshub' }, + { primary: 'cosmoshub', counterParty: 'osmosis' }, +]; + +const osmosisPoolList: OsmosisPool[] = [ + { issuingChain: 'agoric', issuingDenom: 'ubld' }, + { issuingChain: 'cosmoshub', issuingDenom: 'uatom' }, +]; + test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - const { waitForBlock } = makeBlockTool({ - rpc: makeHttpClient('http://localhost:26657', fetch), - delay: ms => new Promise(resolve => setTimeout(resolve, ms)), - }); await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); console.log('WALLETS', wallets); await startContract(contractName, contractBuilder, commonBuilderOpts); - await setupXcsContracts(t); - await createOsmosisPool(t); - await setupXcsChannelLink(t, 'agoric', 'osmosis'); - await setupXcsPrefix(t); + //@ts-expect-error missing swap tools + t.context = { ...common, wallets }; - // @ts-expect-error type - t.context = { ...common, wallets, waitForBlock }; + const swapTools = await osmosisSwapTools(t); + const { setupXcsContracts, setupXcsState, setupOsmosisPools } = swapTools; + + await setupXcsContracts(); + await setupXcsState(prefixList, channelList); + await setupOsmosisPools(osmosisPoolList); + + t.context = { ...t.context, ...swapTools }; }); test.serial('test osmosis xcs state', async t => { - const { useChain } = t.context; + const { useChain, getContractsInfo, getXcsState, getPoolRoute, getPools } = + t.context; // verify if Osmosis XCS contracts were instantiated - const { registryAddress, swaprouterAddress, swapAddress } = - await getXcsContractsAddress(); - t.assert(registryAddress, 'crosschain_registry contract address not found'); - t.assert(swaprouterAddress, 'swaprouter contract address not found'); - t.assert(swapAddress, 'crosschain_swaps contract address not found'); + const { swaprouter, crosschain_registry, crosschain_swaps } = + getContractsInfo(); + t.assert(swaprouter.address, 'swaprouter contract address not found'); + t.assert( + crosschain_registry.address, + 'crosschain_registry contract address not found', + ); + t.assert( + crosschain_swaps.address, + 'crosschain_swaps contract address not found', + ); // verify if Osmosis XCS State was modified - const agoricChainId = useChain('agoric').chain.chain_id; - const { - transferChannel: { channelId }, - } = starshipChainInfo.osmosis.connections[agoricChainId]; + const chainId = useChain('osmosis').chain.chain_id; + const { transferChannel } = starshipChainInfo.agoric.connections[chainId]; - const { channelData, prefixData: osmosisPrefix } = await getXcsState(); + const { channelId, prefix } = await getXcsState(channelList[0]); - t.is(osmosisPrefix, 'osmo'); - t.is(channelData, channelId); + t.is(prefix, 'osmo'); + t.is(channelId, transferChannel.channelId); - const { pool_id, token_out_denom } = await getPoolRoute(); - t.is(token_out_denom, 'uosmo'); + // Verify if Pool was succefuly created + const pool_route = await getPoolRoute(osmosisPoolList[0]); + t.is(pool_route[0].token_out_denom, 'uosmo'); - // verify if Osmosis pool was created - const pool = await getPool(pool_id); - t.assert(pool); + // TODO: fix this assertion + const pools = await getPools(); + t.assert(pools, 'No Osmosis Pool found'); }); test.serial('BLD for OSMO, receiver on Agoric', async t => { @@ -90,29 +108,32 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { vstorageClient, retryUntilCondition, useChain, + getContractsInfo, + getDenomHash, } = t.context; + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + // Provision the Agoric smart wallet const agoricAddr = wallets.agoricSender; const wdUser = await provisionSmartWallet(agoricAddr, { BLD: 1000n, IST: 1000n, }); - t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); - - const osmosisChainId = useChain('osmosis').chain.chain_id; - - const { - transferChannel: { channelId }, - } = starshipChainInfo.agoric.connections[osmosisChainId]; - - const { swapAddress } = await getXcsContractsAddress(); - - const doOffer = makeDoOffer(wdUser); // Verify deposit - const apiUrl = await useChain('agoric').getRestEndpoint(); - const queryClient = makeQueryClient(apiUrl); + await retryUntilCondition( + () => queryClient.queryBalances(agoricAddr), + ({ balances }) => { + const balance = BigInt(balances[0]?.amount || 0); + return balance > 125n; + }, + 'agoricSender wallet not provisioned', + ); + t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); + + // Send swap offer const brands = await vstorageClient.queryData('published.agoricNames.brand'); const bldBrand = Object.fromEntries(brands).BLD; @@ -120,8 +141,13 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { const { balances: balancesBefore } = await queryClient.queryBalances( wallets.agoricReceiver, ); + t.log(`agoric Receiver balances before: `, balancesBefore); // Send swap offer + const doOffer = makeDoOffer(wdUser); + + const { crosschain_swaps } = getContractsInfo(); + const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; await doOffer({ id: makeAccountOfferId, @@ -132,7 +158,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { }, offerArgs: { // TODO: get the contract address dynamically - destAddr: swapAddress, + destAddr: crosschain_swaps.address, receiverAddr: wallets.agoricReceiver, outDenom: 'uosmo', slippage: { slippagePercentage: '20', windowSeconds: 10 }, @@ -152,11 +178,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); t.log(agoricReceiverBalances); - const { hash: expectedHash } = await queryClient.queryDenom( - `transfer/${channelId}`, - 'uosmo', - ); - + const expectedHash = await getDenomHash('agoric', 'osmosis', 'uosmo'); t.log('Expected denom hash:', expectedHash); t.regex(agoricReceiverBalances[0]?.denom, /^ibc/); @@ -174,6 +196,8 @@ test.serial('OSMO for BLD, receiver on Agoric', async t => { vstorageClient, retryUntilCondition, useChain, + getContractsInfo, + getDenomHash, } = t.context; // Provision the Agoric smart wallet @@ -184,8 +208,6 @@ test.serial('OSMO for BLD, receiver on Agoric', async t => { }); t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); - const { swapAddress } = await getXcsContractsAddress(); - const doOffer = makeDoOffer(wdUser); // Verify deposit @@ -199,19 +221,9 @@ test.serial('OSMO for BLD, receiver on Agoric', async t => { wallets.agoricReceiver, ); - const osmosisApiUrl = await useChain('osmosis').getRestEndpoint(); - const osmosisQueryClient = makeQueryClient(osmosisApiUrl); + const outDenomHash = await getDenomHash('osmosis', 'agoric', 'ubld'); - const agoricChainId = useChain('agoric').chain.chain_id; - - const { - transferChannel: { channelId }, - } = starshipChainInfo.osmosis.connections[agoricChainId]; - - const { hash: outDenomHash } = await osmosisQueryClient.queryDenom( - `transfer/${channelId}`, - 'ubld', - ); + const { crosschain_swaps } = getContractsInfo(); // Send swap offer const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; @@ -224,7 +236,7 @@ test.serial('OSMO for BLD, receiver on Agoric', async t => { }, offerArgs: { // TODO: get the contract address dynamically - destAddr: swapAddress, + destAddr: crosschain_swaps.address, receiverAddr: wallets.agoricReceiver, outDenom: `ibc/${outDenomHash}`, slippage: { slippagePercentage: '20', windowSeconds: 10 }, @@ -259,23 +271,22 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { vstorageClient, retryUntilCondition, useChain, + getContractsInfo, } = t.context; - const { client, address } = await createFundedWalletAndClient( + const { client, address: cosmosAddress } = await createFundedWalletAndClient( t.log, 'cosmoshub', useChain, ); const balancesResult = await retryUntilCondition( - () => client.getAllBalances(address), + () => client.getAllBalances(cosmosAddress), coins => !!coins?.length, - `Faucet balances found for ${address}`, + `Faucet balances found for ${cosmosAddress}`, ); console.log('Balances:', balancesResult); - await setupXcsChannelLink(t, 'osmosis', 'cosmoshub'); - // Provision the Agoric smart wallet const agoricAddr = wallets.agoricSender; const wdUser = await provisionSmartWallet(agoricAddr, { @@ -284,7 +295,7 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { }); t.log(`Provisioned Agoric smart wallet for ${agoricAddr}`); - const { swapAddress } = await getXcsContractsAddress(); + const { crosschain_swaps } = getContractsInfo(); const doOffer = makeDoOffer(wdUser); @@ -303,8 +314,8 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { }, offerArgs: { // TODO: get the contract address dynamically - destAddr: swapAddress, - receiverAddr: address, + destAddr: crosschain_swaps.address, + receiverAddr: cosmosAddress, outDenom: 'uosmo', slippage: { slippagePercentage: '20', windowSeconds: 10 }, onFailedDelivery: 'do_nothing', @@ -313,9 +324,9 @@ test.serial('BLD for OSMO, receiver on CosmosHub', async t => { }); const balancesResultAfter = await retryUntilCondition( - () => client.getAllBalances(address), + () => client.getAllBalances(cosmosAddress), coins => coins?.length > 1, - `Faucet balances found for ${address}`, + `Faucet balances found for ${cosmosAddress}`, ); console.log('Balances:', balancesResultAfter); @@ -351,6 +362,7 @@ test.serial( vstorageClient, retryUntilCondition, useChain, + getContractsInfo, } = t.context; // Provision the Agoric smart wallet @@ -374,7 +386,7 @@ test.serial( 'ubld', ); - const { swapAddress } = await getXcsContractsAddress(); + const { crosschain_swaps } = getContractsInfo(); // Send swap offer const makeAccountOfferId = `swap-ubld-uosmo-${Date.now()}`; @@ -386,7 +398,7 @@ test.serial( callPipe: [['makeSwapInvitation']], }, offerArgs: { - destAddr: swapAddress, + destAddr: crosschain_swaps.address, receiverAddr: 'noble/noble1foo', // bad swap receiver outDenom: 'uosmo', slippage: { slippagePercentage: '20', windowSeconds: 10 }, @@ -429,20 +441,23 @@ test.serial( ); test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { - const { wallets, vstorageClient, retryUntilCondition, useChain } = t.context; - const { getRestEndpoint, chain: cosmosChain } = useChain('cosmoshub'); + const { + wallets, + vstorageClient, + retryUntilCondition, + useChain, + fundRemote, + getDenomHash, + getContractsInfo, + } = t.context; const { address: cosmosHubAddr, client: cosmosHubClient } = await fundRemote( - t, + 'agoric', + 'ubld', 'cosmoshub', ); - const cosmosHubApiUrl = await getRestEndpoint(); - const cosmosHubQueryClient = makeQueryClient(cosmosHubApiUrl); - - const { - transferChannel: { counterPartyChannelId }, - } = starshipChainInfo.agoric.connections[cosmosChain.chain_id]; + const bldDenomOnHub = await getDenomHash('cosmoshub', 'agoric', 'ubld'); const apiUrl = await useChain('agoric').getRestEndpoint(); const queryClient = makeQueryClient(apiUrl); @@ -451,21 +466,15 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { wallets.agoricReceiver, ); - const { hash: bldDenomOnHub } = await cosmosHubQueryClient.queryDenom( - `transfer/${counterPartyChannelId}`, - 'ubld', - ); - t.log({ bldDenomOnHub, counterPartyChannelId }); - const { sharedLocalAccount: { value: baseAddress }, } = await vstorageClient.queryData('published.swap-anything'); t.log(baseAddress); - const { swapAddress } = await getXcsContractsAddress(); + const { crosschain_swaps } = getContractsInfo(); const orcContractReceiverAddress = encodeAddressHook(baseAddress, { - destAddr: swapAddress, + destAddr: crosschain_swaps.address, receiverAddr: wallets.agoricReceiver, outDenom: 'uosmo', }); @@ -490,12 +499,6 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { t.is(txRes.code, 0, `Transaction succeeded`); t.log(`Funds transferred to ${orcContractReceiverAddress}`); - const osmosisChainId = useChain('osmosis').chain.chain_id; - - const { - transferChannel: { channelId }, - } = starshipChainInfo.agoric.connections[osmosisChainId]; - const { balances: agoricReceiverBalances } = await retryUntilCondition( () => queryClient.queryBalances(wallets.agoricReceiver), ({ balances }) => { @@ -507,11 +510,7 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { ); t.log(agoricReceiverBalances); - const { hash: expectedHash } = await queryClient.queryDenom( - `transfer/${channelId}`, - 'uosmo', - ); - + const expectedHash = await getDenomHash('agoric', 'osmosis', 'uosmo'); t.log('Expected denom hash:', expectedHash); t.regex(agoricReceiverBalances[0]?.denom, /^ibc/); @@ -522,6 +521,104 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { ); }); +test.serial('bad swapOut receiver, via addressHooks', async t => { + const { + vstorageClient, + useChain, + fundRemote, + getDenomHash, + getContractsInfo, + retryUntilCondition, + } = t.context; + + const { address: cosmosHubAddr, client: cosmosHubClient } = await fundRemote( + 'agoric', + 'ubld', + 'cosmoshub', + ); + + const bldDenomOnHub = await getDenomHash('cosmoshub', 'agoric', 'ubld'); + + const cosmosHubApiUrl = await useChain('cosmoshub').getRestEndpoint(); + const cosmosHubQueryClient = makeQueryClient(cosmosHubApiUrl); + + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const { + sharedLocalAccount: { value: baseAddress }, + } = await vstorageClient.queryData('published.swap-anything'); + t.log(baseAddress); + + // local account balances + const localOrchAccountBalancesBefore = + await queryClient.queryBalances(baseAddress); + // sender balances + const senderBalancesBefore = + await cosmosHubQueryClient.queryBalances(cosmosHubAddr); + + const { crosschain_swaps } = getContractsInfo(); + + const orcContractReceiverAddress = encodeAddressHook(baseAddress, { + destAddr: crosschain_swaps.address, + receiverAddr: 'noble/noble1foo', // bad receiver, should throw + outDenom: 'uosmo', + }); + + const transferArgs = makeIBCTransferMsg( + { denom: `ibc/${bldDenomOnHub}`, value: 125n }, + { address: orcContractReceiverAddress, chainName: 'agoric' }, + { address: cosmosHubAddr, chainName: 'cosmoshub' }, + Date.now(), + useChain, + ); + console.log('Transfer Args:', transferArgs); + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ibc/${bldDenomOnHub}`); + } + const { events: _events, ...txRest } = txRes; + console.log(txRest); + t.is(txRes.code, 0, `Transaction succeeded`); + t.log(`Funds transferred to ${orcContractReceiverAddress}`); + + // TODO; consider replacing with waitforcondition (baseAddress balance) + await retryUntilCondition( + () => queryClient.queryBalances(baseAddress), + ({ balances }) => { + return balances.length > 0; + }, + 'swap-anything balance reflected transferred tokens', + ); + + // local account balances + const localOrchAccountBalancesAfter = + await queryClient.queryBalances(baseAddress); + // sender balances + const senderBalancesAfter = + await cosmosHubQueryClient.queryBalances(cosmosHubAddr); + + t.log( + JSON.stringify( + { + localOrchAccountBalances: { + before: localOrchAccountBalancesBefore, + after: localOrchAccountBalancesAfter, + }, + senderBalances: { + before: senderBalancesBefore, + after: senderBalancesAfter, + }, + }, + null, + 2, + ), + ); +}); + test.after(async t => { const { deleteTestKeys } = t.context; deleteTestKeys(accounts); diff --git a/multichain-testing/yarn.lock b/multichain-testing/yarn.lock index f4c1be8f833..52f7f45c24d 100644 --- a/multichain-testing/yarn.lock +++ b/multichain-testing/yarn.lock @@ -507,52 +507,52 @@ __metadata: languageName: node linkType: soft -"@babel/code-frame@npm:^7.25.9": - version: 7.26.2 - resolution: "@babel/code-frame@npm:7.26.2" +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/code-frame@npm:7.27.1" dependencies: - "@babel/helper-validator-identifier": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.27.1" js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.0.0" - checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 + picocolors: "npm:^1.1.1" + checksum: 10c0/5dd9a18baa5fce4741ba729acc3a3272c49c25cb8736c4b18e113099520e7ef7b545a4096a26d600e4416157e63e87d66db46aa3fbf0a5f2286da2705c12da00 languageName: node linkType: hard "@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.3": - version: 7.27.0 - resolution: "@babel/generator@npm:7.27.0" + version: 7.27.1 + resolution: "@babel/generator@npm:7.27.1" dependencies: - "@babel/parser": "npm:^7.27.0" - "@babel/types": "npm:^7.27.0" + "@babel/parser": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^3.0.2" - checksum: 10c0/7cb10693d2b365c278f109a745dc08856cae139d262748b77b70ce1d97da84627f79648cab6940d847392c0e5d180441669ed958b3aee98d9c7d274b37c553bd + checksum: 10c0/c4156434b21818f558ebd93ce45f027c53ee570ce55a84fd2d9ba45a79ad204c17e0bff753c886fb6c07df3385445a9e34dc7ccb070d0ac7e80bb91c8b57f423 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-string-parser@npm:7.25.9" - checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6 +"@babel/helper-string-parser@npm:^7.25.9, @babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-identifier@npm:7.25.9" - checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d +"@babel/helper-validator-identifier@npm:^7.25.9, @babel/helper-validator-identifier@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-identifier@npm:7.27.1" + checksum: 10c0/c558f11c4871d526498e49d07a84752d1800bf72ac0d3dad100309a2eaba24efbf56ea59af5137ff15e3a00280ebe588560534b0e894a4750f8b1411d8f78b84 languageName: node linkType: hard -"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.27.0": - version: 7.27.0 - resolution: "@babel/parser@npm:7.27.0" +"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.27.1, @babel/parser@npm:^7.27.2": + version: 7.27.2 + resolution: "@babel/parser@npm:7.27.2" dependencies: - "@babel/types": "npm:^7.27.0" + "@babel/types": "npm:^7.27.1" bin: parser: ./bin/babel-parser.js - checksum: 10c0/ba2ed3f41735826546a3ef2a7634a8d10351df221891906e59b29b0a0cd748f9b0e7a6f07576858a9de8e77785aad925c8389ddef146de04ea2842047c9d2859 + checksum: 10c0/3c06692768885c2f58207fc8c2cbdb4a44df46b7d93135a083f6eaa49310f7ced490ce76043a2a7606cdcc13f27e3d835e141b692f2f6337a2e7f43c1dbb04b4 languageName: node linkType: hard @@ -568,22 +568,20 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.21.0": - version: 7.24.7 - resolution: "@babel/runtime@npm:7.24.7" - dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + version: 7.27.1 + resolution: "@babel/runtime@npm:7.27.1" + checksum: 10c0/530a7332f86ac5a7442250456823a930906911d895c0b743bf1852efc88a20a016ed4cd26d442d0ca40ae6d5448111e02a08dd638a4f1064b47d080e2875dc05 languageName: node linkType: hard "@babel/template@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/template@npm:7.25.9" + version: 7.27.2 + resolution: "@babel/template@npm:7.27.2" dependencies: - "@babel/code-frame": "npm:^7.25.9" - "@babel/parser": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10c0/ebe677273f96a36c92cc15b7aa7b11cc8bc8a3bb7a01d55b2125baca8f19cae94ff3ce15f1b1880fb8437f3a690d9f89d4e91f16fc1dc4d3eb66226d128983ab + "@babel/code-frame": "npm:^7.27.1" + "@babel/parser": "npm:^7.27.2" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/ed9e9022651e463cc5f2cc21942f0e74544f1754d231add6348ff1b472985a3b3502041c0be62dc99ed2d12cfae0c51394bf827452b98a2f8769c03b87aadc81 languageName: node linkType: hard @@ -602,13 +600,13 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.0": - version: 7.27.0 - resolution: "@babel/types@npm:7.27.0" +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/types@npm:7.27.1" dependencies: - "@babel/helper-string-parser": "npm:^7.25.9" - "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10c0/6f1592eabe243c89a608717b07b72969be9d9d2fce1dee21426238757ea1fa60fdfc09b29de9e48d8104311afc6e6fb1702565a9cc1e09bc1e76f2b2ddb0f6e1 + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.27.1" + checksum: 10c0/ed736f14db2fdf0d36c539c8e06b6bb5e8f9649a12b5c0e1c516fed827f27ef35085abe08bf4d1302a4e20c9a254e762eed453bce659786d4a6e01ba26a91377 languageName: node linkType: hard @@ -644,18 +642,18 @@ __metadata: languageName: node linkType: hard -"@chain-registry/types@npm:^0.44.4": - version: 0.44.4 - resolution: "@chain-registry/types@npm:0.44.4" - checksum: 10c0/9ea3cd0232271c695ea148c1ee80e2a4ce7764e1696de69bc15ea2d1fb7e432c67441eedbdd3ceaac84ad933fcb23d8d1916185e40adfc518b31102aa62f51c1 +"@chain-registry/types@npm:^0.50.136": + version: 0.50.136 + resolution: "@chain-registry/types@npm:0.50.136" + checksum: 10c0/bd5406cdba8b057c6055a538ba50bdd95c8291fef8abbfaf75673f826718064e22e8d2a74c462070bd162dfc5c80a9c7ff94a0f555bddee61cee3cdf9d27e135 languageName: node linkType: hard "@chain-registry/utils@npm:^1.17.0": - version: 1.45.4 - resolution: "@chain-registry/utils@npm:1.45.4" + version: 1.51.136 + resolution: "@chain-registry/utils@npm:1.51.136" dependencies: - "@chain-registry/types": "npm:^0.44.4" + "@chain-registry/types": "npm:^0.50.136" bignumber.js: "npm:9.1.2" sha.js: "npm:^2.4.11" checksum: 10c0/c28e5ab6ce893108600cab5d7a758c40cf9cbfe68359d6eb93f3ebf201336c5eca13746df8700952021e44547f88679964e98ea664ee6330939c14eb78dafd85 @@ -686,15 +684,33 @@ __metadata: languageName: node linkType: hard -"@cosmjs/amino@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/amino@npm:0.33.0" +"@cosmjs/amino@npm:^0.33.0, @cosmjs/amino@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/amino@npm:0.33.1" dependencies: - "@cosmjs/crypto": "npm:^0.33.0" - "@cosmjs/encoding": "npm:^0.33.0" - "@cosmjs/math": "npm:^0.33.0" - "@cosmjs/utils": "npm:^0.33.0" - checksum: 10c0/35a4bc76aeb98b133a79cf015d2aaca7e2412f2fa6821efc0cadcd81a847f472fbdb24b0d3fe6aae06ec65058d3636137d67f55ec72d5311f6c4cef4ddb76d05 + "@cosmjs/crypto": "npm:^0.33.1" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" + checksum: 10c0/52ba52a7240ab41c967cfa10aae19a6410121994acf225261ddf1b2dbf84d2a54b45951afa0f589d206901270683f244864a64af4fbec6f21576e3738c251bf9 + languageName: node + linkType: hard + +"@cosmjs/cosmwasm-stargate@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/cosmwasm-stargate@npm:0.33.1" + dependencies: + "@cosmjs/amino": "npm:^0.33.1" + "@cosmjs/crypto": "npm:^0.33.1" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/proto-signing": "npm:^0.33.1" + "@cosmjs/stargate": "npm:^0.33.1" + "@cosmjs/tendermint-rpc": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" + cosmjs-types: "npm:^0.9.0" + pako: "npm:^2.0.2" + checksum: 10c0/56e604ae8c8b66523e16cace759fd5db160f4d3cb10c44ff894bd22a2c87224cfa31fd2472a849ce3c68d77647d017f723af6d15960452790695c82fe5799332 languageName: node linkType: hard @@ -713,18 +729,18 @@ __metadata: languageName: node linkType: hard -"@cosmjs/crypto@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/crypto@npm:0.33.0" +"@cosmjs/crypto@npm:^0.33.0, @cosmjs/crypto@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/crypto@npm:0.33.1" dependencies: - "@cosmjs/encoding": "npm:^0.33.0" - "@cosmjs/math": "npm:^0.33.0" - "@cosmjs/utils": "npm:^0.33.0" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" "@noble/hashes": "npm:^1" bn.js: "npm:^5.2.0" - elliptic: "npm:^6.5.4" + elliptic: "npm:^6.6.1" libsodium-wrappers-sumo: "npm:^0.7.11" - checksum: 10c0/548006f8d028d5f931fd1fba4f919f2ed1b364cc3134f1c68a996503cf4124b3b0d27cbd7471cbbed2c88d014dffdb0cc61946417cf810f54476f5f62aeee10e + checksum: 10c0/1af80987a747ae6f619849d9e8b41190a418d9ac302c9df38ac7c8d538d0d0d75ad618b6a846989887f477ee484125b26fec2476de97cc67a7040d50d43a19b3 languageName: node linkType: hard @@ -750,24 +766,34 @@ __metadata: languageName: node linkType: hard -"@cosmjs/encoding@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/encoding@npm:0.33.0" +"@cosmjs/encoding@npm:^0.33.0, @cosmjs/encoding@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/encoding@npm:0.33.1" dependencies: base64-js: "npm:^1.3.0" bech32: "npm:^1.1.4" readonly-date: "npm:^1.0.0" - checksum: 10c0/c9586bea69da5b7a4eaa14f98522956bb8847ba6b3465b9f5adcd97ffa0cb25675dd5b8710feaae1a3fcd37c6709483a344fd6dc12689d1955fb83b82c03d59b + checksum: 10c0/d589a969e45cd41d8662ed1b29d1e84cda2c11dabb505c7158b0b649800a4224db80757afa2ab74cdf086b987c1a8ac727e5572d8f4898214d82d335ecaf3215 languageName: node linkType: hard -"@cosmjs/json-rpc@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/json-rpc@npm:0.33.0" +"@cosmjs/json-rpc@npm:^0.32.3": + version: 0.32.4 + resolution: "@cosmjs/json-rpc@npm:0.32.4" + dependencies: + "@cosmjs/stream": "npm:^0.32.4" + xstream: "npm:^11.14.0" + checksum: 10c0/b3ebd240f4fb21260e284d2e503ecc61bac898842187ab717f0efb9a5f21272f161f267cc145629caeb9735f80946844384e2bd410275a4744147a44518c0fa0 + languageName: node + linkType: hard + +"@cosmjs/json-rpc@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/json-rpc@npm:0.33.1" dependencies: - "@cosmjs/stream": "npm:^0.33.0" + "@cosmjs/stream": "npm:^0.33.1" xstream: "npm:^11.14.0" - checksum: 10c0/3f38317bc9da31c65a6631b8494843cc6be265e93df65727fc0c4b9121d1847bd2ec19fe1b77ad25df47e7e7160bae4792ecea335e5f4661feb9d43054a8f763 + checksum: 10c0/a6e059c9d40c7ff215b19f96cb09174754f3e673a509ea168c8f6c3515d4b5565de9561c476abf077d65a5c1cf0aa406fcb3799d67a3a916adceed5396b1736a languageName: node linkType: hard @@ -789,16 +815,16 @@ __metadata: languageName: node linkType: hard -"@cosmjs/math@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/math@npm:0.33.0" +"@cosmjs/math@npm:^0.33.0, @cosmjs/math@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/math@npm:0.33.1" dependencies: bn.js: "npm:^5.2.0" - checksum: 10c0/03cfe1f177ee2f365f559419e60506b193a18e7535bfdf932f2ab10111cd114e96a6df7e8e2686d4fe4942093cc76f5dcf655722cacf0965194d88590a9e0303 + checksum: 10c0/49db16cb4d49271afad8bf13f91a2da054af07631f455cc03740a3ca741b7f1fd69b025a5c94b8258a422731a350ef824209ca7e10cdefb7dae4ddd686f146f0 languageName: node linkType: hard -"@cosmjs/proto-signing@npm:@cosmjs/proto-signing@0.33.0, @cosmjs/proto-signing@npm:^0.33.0": +"@cosmjs/proto-signing@npm:0.33.0": version: 0.33.0 resolution: "@cosmjs/proto-signing@npm:0.33.0" dependencies: @@ -812,58 +838,97 @@ __metadata: languageName: node linkType: hard -"@cosmjs/socket@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/socket@npm:0.33.0" +"@cosmjs/socket@npm:^0.32.3": + version: 0.32.4 + resolution: "@cosmjs/socket@npm:0.32.4" dependencies: - "@cosmjs/stream": "npm:^0.33.0" + "@cosmjs/stream": "npm:^0.32.4" isomorphic-ws: "npm:^4.0.1" ws: "npm:^7" xstream: "npm:^11.14.0" - checksum: 10c0/6d3b135eebe7292e07b4df6d2c0de980cfee9da4377c668d7bbdfa7103fbaefafd14c55db76799312af670a85ee85a61d0dbe06edc5e33780fe9fa17fef7fedf + checksum: 10c0/2d94c1fb39016bea3c7c145f4565c8a0fed20c805ac569ea604cd3646c15147b82b8db18a4e3c832d6ae0c3dd14363d4db3d91bcacac922679efba164ed49386 languageName: node linkType: hard -"@cosmjs/stargate@npm:@cosmjs/stargate@0.33.0, @cosmjs/stargate@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/stargate@npm:0.33.0" +"@cosmjs/socket@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/socket@npm:0.33.1" dependencies: - "@cosmjs/amino": "npm:^0.33.0" - "@cosmjs/encoding": "npm:^0.33.0" - "@cosmjs/math": "npm:^0.33.0" - "@cosmjs/proto-signing": "npm:^0.33.0" - "@cosmjs/stream": "npm:^0.33.0" - "@cosmjs/tendermint-rpc": "npm:^0.33.0" - "@cosmjs/utils": "npm:^0.33.0" + "@cosmjs/stream": "npm:^0.33.1" + isomorphic-ws: "npm:^4.0.1" + ws: "npm:^7" + xstream: "npm:^11.14.0" + checksum: 10c0/928254ee44aaf9ed24ebf9835ab44bfa479a77b739700a23e05b9a840e08e9d16c5de29c5a9c5db035df59483c42ab9e13e3d359ca3b723d655300780189c0db + languageName: node + linkType: hard + +"@cosmjs/stargate@npm:^0.33.0": + version: 0.33.1 + resolution: "@cosmjs/stargate@npm:0.33.1" + dependencies: + "@cosmjs/amino": "npm:^0.33.1" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/proto-signing": "npm:^0.33.1" + "@cosmjs/stream": "npm:^0.33.1" + "@cosmjs/tendermint-rpc": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" cosmjs-types: "npm:^0.9.0" - checksum: 10c0/5f1a93f91a146cfb7c3588271c78ee5102628a8c8948b5df42f5fde7d67cd0610d83bc26654dd535f2af43095a27577e00ea5b8f5cb0aa3f1fdcd4683cc235ab + checksum: 10c0/685fbf4bbffb719be9754dbcc5760f4ee24ff355c7aba395909f058dbcc8b17a47d87b6f081b524f8d4d41369e433dc8852f43e816cbdcc0376b5fb034bb64ce languageName: node linkType: hard -"@cosmjs/stream@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/stream@npm:0.33.0" +"@cosmjs/stream@npm:^0.32.3, @cosmjs/stream@npm:^0.32.4": + version: 0.32.4 + resolution: "@cosmjs/stream@npm:0.32.4" dependencies: xstream: "npm:^11.14.0" - checksum: 10c0/707ed2e9846eedb815fe7b56e79ad5a22055600b1be78754374d2613967dd68520773e3253e5dd4a0db4e8a3cd771d090d1c9e820bf9e0dd4fb146b138185198 + checksum: 10c0/c677c53f9101c2a36fa03a475d92dea2fa69c475f896751b5e18a5d07087eeecbf6bca2e62a8940003da53fa235a9b2dd78c8257bf19c3f96e3f69fa8d5f183d languageName: node linkType: hard -"@cosmjs/tendermint-rpc@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/tendermint-rpc@npm:0.33.0" +"@cosmjs/stream@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/stream@npm:0.33.1" dependencies: - "@cosmjs/crypto": "npm:^0.33.0" - "@cosmjs/encoding": "npm:^0.33.0" - "@cosmjs/json-rpc": "npm:^0.33.0" - "@cosmjs/math": "npm:^0.33.0" - "@cosmjs/socket": "npm:^0.33.0" - "@cosmjs/stream": "npm:^0.33.0" - "@cosmjs/utils": "npm:^0.33.0" + xstream: "npm:^11.14.0" + checksum: 10c0/02f9767a22846c4c948e33b5e775a8b924eee14ac1ee3fa8c567ef9ca83472c869ba3c6b87d286f7e743edcbb1c6b0cd75509ad53e6e9da1897be085fbfef4e4 + languageName: node + linkType: hard + +"@cosmjs/tendermint-rpc@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/tendermint-rpc@npm:0.32.3" + dependencies: + "@cosmjs/crypto": "npm:^0.32.3" + "@cosmjs/encoding": "npm:^0.32.3" + "@cosmjs/json-rpc": "npm:^0.32.3" + "@cosmjs/math": "npm:^0.32.3" + "@cosmjs/socket": "npm:^0.32.3" + "@cosmjs/stream": "npm:^0.32.3" + "@cosmjs/utils": "npm:^0.32.3" axios: "npm:^1.6.0" readonly-date: "npm:^1.0.0" xstream: "npm:^11.14.0" - checksum: 10c0/bf6bdfc96659527085cefd5d91a28e6a250b76dd4db00dc5958f1539e17f43240ea340e90322b4029f6101fc2d0ceb93cdc0a7262f8dda48142bc1ae0e85b57c + checksum: 10c0/9ccde526456e9c4be7a2562c3def25a016267404a057e807ecc0f520aeb0cbfc5bf04bfca58ceecd6f7bf61b7089924c7949c13a7d685efc7ad946b71388c3df + languageName: node + linkType: hard + +"@cosmjs/tendermint-rpc@npm:^0.33.0, @cosmjs/tendermint-rpc@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/tendermint-rpc@npm:0.33.1" + dependencies: + "@cosmjs/crypto": "npm:^0.33.1" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/json-rpc": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/socket": "npm:^0.33.1" + "@cosmjs/stream": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" + axios: "npm:^1.6.0" + readonly-date: "npm:^1.0.0" + xstream: "npm:^11.14.0" + checksum: 10c0/346f16bf197fb09eb7f9ab76c8b185fe04d27a3da6d186610ff20f2d0df1e61f816e7d72373f0287b3fbef1d8437ed0609a05a7aba856751c3334768d20686af languageName: node linkType: hard @@ -874,10 +939,19 @@ __metadata: languageName: node linkType: hard -"@cosmjs/utils@npm:^0.33.0": - version: 0.33.0 - resolution: "@cosmjs/utils@npm:0.33.0" - checksum: 10c0/9cf4ac04031fcfa4bee8732bdff17d15a5bad76a208fabed3e85d9187f5ff483f9efcf0979751745278c35f4f3537005c9a124598c8e0ed4734524e73f5090a7 +"@cosmjs/utils@npm:^0.33.0, @cosmjs/utils@npm:^0.33.1": + version: 0.33.1 + resolution: "@cosmjs/utils@npm:0.33.1" + checksum: 10c0/fe675de1caa1028ece747ea6a96a8a4f5475084982adf5f200abfdf0c2bb5173668ea6437c03cd03bf5639c8540363ac934cf4868686f6577f2640c9d468b8d1 + languageName: node + linkType: hard + +"@cosmology/lcd@npm:^0.13.3": + version: 0.13.5 + resolution: "@cosmology/lcd@npm:0.13.5" + dependencies: + axios: "npm:1.7.4" + checksum: 10c0/c862cb2d33f3d470ff07ac48f1b9c7ea437be1dd4e99cf238056e28fec1f6a1925d7241ce983ee4560bdaa501bdb289842ba9526757d34d07967730b07ee6953 languageName: node linkType: hard @@ -1170,14 +1244,14 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.7.0": + version: 4.7.0 + resolution: "@eslint-community/eslint-utils@npm:4.7.0" dependencies: - eslint-visitor-keys: "npm:^3.3.0" + eslint-visitor-keys: "npm:^3.4.3" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/7e559c4ce59cd3a06b1b5a517b593912e680a7f981ae7affab0d01d709e99cd5647019be8fafa38c350305bc32f1f7d42c7073edde2ab536c745e365f37b607e + checksum: 10c0/c0f4f2bd73b7b7a9de74b716a664873d08ab71ab439e51befe77d61915af41a81ecec93b408778b3a7856185244c34c2c8ee28912072ec14def84ba2dec70adf languageName: node linkType: hard @@ -1188,36 +1262,36 @@ __metadata: languageName: node linkType: hard -"@eslint/config-array@npm:^0.19.2": - version: 0.19.2 - resolution: "@eslint/config-array@npm:0.19.2" +"@eslint/config-array@npm:^0.20.0": + version: 0.20.0 + resolution: "@eslint/config-array@npm:0.20.0" dependencies: "@eslint/object-schema": "npm:^2.1.6" debug: "npm:^4.3.1" minimatch: "npm:^3.1.2" - checksum: 10c0/dd68da9abb32d336233ac4fe0db1e15a0a8d794b6e69abb9e57545d746a97f6f542496ff9db0d7e27fab1438546250d810d90b1904ac67677215b8d8e7573f3d + checksum: 10c0/94bc5d0abb96dc5295ff559925242ff75a54eacfb3576677e95917e42f7175e1c4b87bf039aa2a872f949b4852ad9724bf2f7529aaea6b98f28bb3fca7f1d659 languageName: node linkType: hard -"@eslint/config-helpers@npm:^0.1.0": - version: 0.1.0 - resolution: "@eslint/config-helpers@npm:0.1.0" - checksum: 10c0/3562b5325f42740fc83b0b92b7d13a61b383f8db064915143eec36184f09a09fad73eca6c2955ab6c248b0d04fa03c140f9af2f2c4c06770781a6b79f300a01e +"@eslint/config-helpers@npm:^0.2.1": + version: 0.2.2 + resolution: "@eslint/config-helpers@npm:0.2.2" + checksum: 10c0/98f7cefe484bb754674585d9e73cf1414a3ab4fd0783c385465288d13eb1a8d8e7d7b0611259fc52b76b396c11a13517be5036d1f48eeb877f6f0a6b9c4f03ad languageName: node linkType: hard -"@eslint/core@npm:^0.12.0": - version: 0.12.0 - resolution: "@eslint/core@npm:0.12.0" +"@eslint/core@npm:^0.14.0": + version: 0.14.0 + resolution: "@eslint/core@npm:0.14.0" dependencies: "@types/json-schema": "npm:^7.0.15" - checksum: 10c0/d032af81195bb28dd800c2b9617548c6c2a09b9490da3c5537fd2a1201501666d06492278bb92cfccac1f7ac249e58601dd87f813ec0d6a423ef0880434fa0c3 + checksum: 10c0/259f279445834ba2d2cbcc18e9d43202a4011fde22f29d5fb802181d66e0f6f0bd1f6b4b4b46663451f545d35134498231bd5e656e18d9034a457824b92b7741 languageName: node linkType: hard -"@eslint/eslintrc@npm:^3.3.0": - version: 3.3.0 - resolution: "@eslint/eslintrc@npm:3.3.0" +"@eslint/eslintrc@npm:^3.3.1": + version: 3.3.1 + resolution: "@eslint/eslintrc@npm:3.3.1" dependencies: ajv: "npm:^6.12.4" debug: "npm:^4.3.2" @@ -1228,14 +1302,14 @@ __metadata: js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: 10c0/215de990231b31e2fe6458f225d8cea0f5c781d3ecb0b7920703501f8cd21b3101fc5ef2f0d4f9a38865d36647b983e0e8ce8bf12fd2bcdd227fc48a5b1a43be + checksum: 10c0/b0e63f3bc5cce4555f791a4e487bf999173fcf27c65e1ab6e7d63634d8a43b33c3693e79f192cbff486d7df1be8ebb2bd2edc6e70ddd486cbfa84a359a3e3b41 languageName: node linkType: hard -"@eslint/js@npm:9.22.0": - version: 9.22.0 - resolution: "@eslint/js@npm:9.22.0" - checksum: 10c0/5bcd009bb579dc6c6ed760703bdd741e08a48cd9decd677aa2cf67fe66236658cb09a00185a0369f3904e5cffba9e6e0f2ff4d9ba4fdf598fcd81d34c49213a5 +"@eslint/js@npm:9.27.0": + version: 9.27.0 + resolution: "@eslint/js@npm:9.27.0" + checksum: 10c0/79b219ceda79182732954b52f7a494f49995a9a6419c7ae0316866e324d3706afeb857e1306bb6f35a4caaf176a5174d00228fc93d36781a570d32c587736564 languageName: node linkType: hard @@ -1246,13 +1320,13 @@ __metadata: languageName: node linkType: hard -"@eslint/plugin-kit@npm:^0.2.7": - version: 0.2.7 - resolution: "@eslint/plugin-kit@npm:0.2.7" +"@eslint/plugin-kit@npm:^0.3.1": + version: 0.3.1 + resolution: "@eslint/plugin-kit@npm:0.3.1" dependencies: - "@eslint/core": "npm:^0.12.0" + "@eslint/core": "npm:^0.14.0" levn: "npm:^0.4.1" - checksum: 10c0/0a1aff1ad63e72aca923217e556c6dfd67d7cd121870eb7686355d7d1475d569773528a8b2111b9176f3d91d2ea81f7413c34600e8e5b73d59e005d70780b633 + checksum: 10c0/a75f0b5d38430318a551b83e27bee570747eb50beeb76b03f64b0e78c2c27ef3d284cfda3443134df028db3251719bc0850c105f778122f6ad762d5270ec8063 languageName: node linkType: hard @@ -1288,9 +1362,9 @@ __metadata: linkType: hard "@humanwhocodes/retry@npm:^0.4.2": - version: 0.4.2 - resolution: "@humanwhocodes/retry@npm:0.4.2" - checksum: 10c0/0235525d38f243bee3bf8b25ed395fbf957fb51c08adae52787e1325673071abe856c7e18e530922ed2dd3ce12ed82ba01b8cee0279ac52a3315fcdc3a69ef0c + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 languageName: node linkType: hard @@ -1359,22 +1433,20 @@ __metadata: languageName: node linkType: hard -"@mapbox/node-pre-gyp@npm:^1.0.11": - version: 1.0.11 - resolution: "@mapbox/node-pre-gyp@npm:1.0.11" +"@mapbox/node-pre-gyp@npm:^2.0.0": + version: 2.0.0 + resolution: "@mapbox/node-pre-gyp@npm:2.0.0" dependencies: + consola: "npm:^3.2.3" detect-libc: "npm:^2.0.0" - https-proxy-agent: "npm:^5.0.0" - make-dir: "npm:^3.1.0" + https-proxy-agent: "npm:^7.0.5" node-fetch: "npm:^2.6.7" - nopt: "npm:^5.0.0" - npmlog: "npm:^5.0.1" - rimraf: "npm:^3.0.2" - semver: "npm:^7.3.5" - tar: "npm:^6.1.11" + nopt: "npm:^8.0.0" + semver: "npm:^7.5.3" + tar: "npm:^7.4.0" bin: node-pre-gyp: bin/node-pre-gyp - checksum: 10c0/2b24b93c31beca1c91336fa3b3769fda98e202fb7f9771f0f4062588d36dcc30fcf8118c36aa747fa7f7610d8cf601872bdaaf62ce7822bb08b545d1bbe086cc + checksum: 10c0/7d874c7f6f5560a87be7207f28d9a4e53b750085a82167608fd573aab8073645e95b3608f69e244df0e1d24e90a66525aeae708aba82ca73ff668ed0ab6abda6 languageName: node linkType: hard @@ -1519,9 +1591,9 @@ __metadata: linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": - version: 1.0.6 - resolution: "@types/estree@npm:1.0.6" - checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10c0/be815254316882f7c40847336cd484c3bc1c3e34f710d197160d455dc9d6d050ffbf4c3bc76585dba86f737f020ab20bdb137ebe0e9116b0c86c7c0342221b8c languageName: node linkType: hard @@ -1555,8 +1627,8 @@ __metadata: version: 22.7.8 resolution: "@types/node@npm:22.7.8" dependencies: - undici-types: "npm:~6.19.2" - checksum: 10c0/3d3b3a2ec5a57ca4fd37b34dce415620993ca5f87cea2c728ffe73aa31446dbfe19c53171c478447bd7d78011ef4845a46ab2f0dc38e699cc75b3d100a60c690 + undici-types: "npm:~6.21.0" + checksum: 10c0/f092bbccda2131c2b2c8f720338080aa0ef1d928f5f1062c03954a4f7dafa7ee3ed29bc3e51bd4e2584473b3d943c637a2b39ad7174898970818270187cf10c1 languageName: node linkType: hard @@ -1570,150 +1642,143 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.26.1" + version: 8.32.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.32.1" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.26.1" - "@typescript-eslint/type-utils": "npm:8.26.1" - "@typescript-eslint/utils": "npm:8.26.1" - "@typescript-eslint/visitor-keys": "npm:8.26.1" + "@typescript-eslint/scope-manager": "npm:8.32.1" + "@typescript-eslint/type-utils": "npm:8.32.1" + "@typescript-eslint/utils": "npm:8.32.1" + "@typescript-eslint/visitor-keys": "npm:8.32.1" graphemer: "npm:^1.4.0" - ignore: "npm:^5.3.1" + ignore: "npm:^7.0.0" natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.0.1" + ts-api-utils: "npm:^2.1.0" peerDependencies: "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0" - checksum: 10c0/412f41aafd503a1faea91edd03a68717ca8a49ed6683700b8386115c67b86110c9826d10005d3a0341b78cdee41a6ef08842716ced2b58af03f91eb1b8cc929c + checksum: 10c0/29dbafc1f02e1167e6d1e92908de6bf7df1cc1fc9ae1de3f4d4abf5d2b537be16b173bcd05770270529eb2fd17a3ac63c2f40d308f7fbbf6d6f286ba564afd64 languageName: node linkType: hard "@typescript-eslint/parser@npm:^8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/parser@npm:8.26.1" + version: 8.32.1 + resolution: "@typescript-eslint/parser@npm:8.32.1" dependencies: - "@typescript-eslint/scope-manager": "npm:8.26.1" - "@typescript-eslint/types": "npm:8.26.1" - "@typescript-eslint/typescript-estree": "npm:8.26.1" - "@typescript-eslint/visitor-keys": "npm:8.26.1" + "@typescript-eslint/scope-manager": "npm:8.32.1" + "@typescript-eslint/types": "npm:8.32.1" + "@typescript-eslint/typescript-estree": "npm:8.32.1" + "@typescript-eslint/visitor-keys": "npm:8.32.1" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0" - checksum: 10c0/21fe4306b6017bf183d92cdd493edacd302816071e29e1400452f3ccd224ab8111b75892507b9731545e98e6e4d153e54dab568b3433f6c9596b6cb2f7af922f + checksum: 10c0/01095f5b6e0a2e0631623be3f44be0f2960ceb24de33b64cb790e24a1468018d2b4d6874d1fa08a4928c2a02f208dd66cbc49735c7e8b54d564e420daabf84d1 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/scope-manager@npm:8.26.1" +"@typescript-eslint/scope-manager@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/scope-manager@npm:8.32.1" dependencies: - "@typescript-eslint/types": "npm:8.26.1" - "@typescript-eslint/visitor-keys": "npm:8.26.1" - checksum: 10c0/ecd30eb615c7384f01cea8f2c8e8dda7507ada52ad0d002d3701bdd9d06f6d14cefb31c6c26ef55708adfaa2045a01151e8685656240268231a4bac8f792afe4 + "@typescript-eslint/types": "npm:8.32.1" + "@typescript-eslint/visitor-keys": "npm:8.32.1" + checksum: 10c0/d2cb1f7736388972137d6e510b2beae4bac033fcab274e04de90ebba3ce466c71fe47f1795357e032e4a6c8b2162016b51b58210916c37212242c82d35352e9f languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/type-utils@npm:8.26.1" +"@typescript-eslint/type-utils@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/type-utils@npm:8.32.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.26.1" - "@typescript-eslint/utils": "npm:8.26.1" + "@typescript-eslint/typescript-estree": "npm:8.32.1" + "@typescript-eslint/utils": "npm:8.32.1" debug: "npm:^4.3.4" - ts-api-utils: "npm:^2.0.1" + ts-api-utils: "npm:^2.1.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0" - checksum: 10c0/17553b4333246e1ffd447dab78a4cbc565c129c9baf32326387760c9790120a99d955acf84888b7ef96e73c82fc22a3e08e80f0bd65d21e3cf2fe002f977aba1 + checksum: 10c0/f10186340ce194681804d9a57feb6d8d6c3adbd059c70df58f4656b0d9efd412fb0c2d80c182f9db83bad1a301754e0c24fe26f3354bef3a1795ab9c835cb763 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/types@npm:8.26.1" - checksum: 10c0/805b239b57854fc12eae9e2bec6ccab24bac1d30a762c455f22c73b777a5859c64c58b4750458bd0ab4aadd664eb95cbef091348a071975acac05b15ebea9f1b +"@typescript-eslint/types@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/types@npm:8.32.1" + checksum: 10c0/86f59b29c12e7e8abe45a1659b6fae5e7b0cfaf09ab86dd596ed9d468aa61082bbccd509d25f769b197fbfdf872bbef0b323a2ded6ceaca351f7c679f1ba3bd3 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.26.1" +"@typescript-eslint/typescript-estree@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.32.1" dependencies: - "@typescript-eslint/types": "npm:8.26.1" - "@typescript-eslint/visitor-keys": "npm:8.26.1" + "@typescript-eslint/types": "npm:8.32.1" + "@typescript-eslint/visitor-keys": "npm:8.32.1" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" minimatch: "npm:^9.0.4" semver: "npm:^7.6.0" - ts-api-utils: "npm:^2.0.1" + ts-api-utils: "npm:^2.1.0" peerDependencies: typescript: ">=4.8.4 <5.9.0" - checksum: 10c0/adc95e4735a8ded05ad35d7b4fae68c675afdd4b3531bc4a51eab5efe793cf80bc75f56dfc8022af4c0a5b316eec61f8ce6b77c2ead45fc675fea7e28cd52ade + checksum: 10c0/b5ae0d91ef1b46c9f3852741e26b7a14c28bb58ee8a283b9530ac484332ca58a7216b9d22eda23c5449b5fd69c6e4601ef3ebbd68e746816ae78269036c08cda languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/utils@npm:8.26.1" +"@typescript-eslint/utils@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/utils@npm:8.32.1" dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.26.1" - "@typescript-eslint/types": "npm:8.26.1" - "@typescript-eslint/typescript-estree": "npm:8.26.1" + "@eslint-community/eslint-utils": "npm:^4.7.0" + "@typescript-eslint/scope-manager": "npm:8.32.1" + "@typescript-eslint/types": "npm:8.32.1" + "@typescript-eslint/typescript-estree": "npm:8.32.1" peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0" - checksum: 10c0/a5cb3bdf253cc8e8474a2ed8666c0a6194abe56f44039c6623bef0459ed17d0276ed6e40c70d35bd8ec4d41bafc255e4d3025469f32ac692ba2d89e7579c2a26 + checksum: 10c0/a2b90c0417cd3a33c6e22f9cc28c356f251bb8928ef1d25e057feda007d522d281bdc37a9a0d05b70312f00a7b3f350ca06e724867025ea85bba5a4c766732e7 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.26.1": - version: 8.26.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.26.1" +"@typescript-eslint/visitor-keys@npm:8.32.1": + version: 8.32.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.32.1" dependencies: - "@typescript-eslint/types": "npm:8.26.1" + "@typescript-eslint/types": "npm:8.32.1" eslint-visitor-keys: "npm:^4.2.0" - checksum: 10c0/51b1016d06cd2b9eac0a213de418b0a26022fd3b71478014541bfcbc2a3c4d666552390eb9c209fa9e52c868710d9f1b21a2c789d35c650239438c366a27a239 + checksum: 10c0/9c05053dfd048f681eb96e09ceefa8841a617b8b5950eea05e0844b38fe3510a284eb936324caa899c3ceb4bc23efe56ac01437fab378ac1beeb1c6c00404978 languageName: node linkType: hard -"@vercel/nft@npm:^0.27.5": - version: 0.27.7 - resolution: "@vercel/nft@npm:0.27.7" +"@vercel/nft@npm:^0.29.2": + version: 0.29.3 + resolution: "@vercel/nft@npm:0.29.3" dependencies: - "@mapbox/node-pre-gyp": "npm:^1.0.11" + "@mapbox/node-pre-gyp": "npm:^2.0.0" "@rollup/pluginutils": "npm:^5.1.3" acorn: "npm:^8.6.0" acorn-import-attributes: "npm:^1.9.5" async-sema: "npm:^3.1.1" bindings: "npm:^1.4.0" estree-walker: "npm:2.0.2" - glob: "npm:^7.1.3" + glob: "npm:^10.4.5" graceful-fs: "npm:^4.2.9" - micromatch: "npm:^4.0.8" node-gyp-build: "npm:^4.2.2" + picomatch: "npm:^4.0.2" resolve-from: "npm:^5.0.0" bin: nft: out/cli.js - checksum: 10c0/bf6c1572e436e46e83d38c837fd715603b816fdfc5109f55f9898ed25011dfaba6c1cc979457db81238021854db5ba60c3b5bb263b843e24c4ebedb02b6ec2fe - languageName: node - linkType: hard - -"abbrev@npm:1": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: 10c0/3f762677702acb24f65e813070e306c61fafe25d4b2583f9dfc935131f774863f3addd5741572ed576bd69cabe473c5af18e1e108b829cb7b6b4747884f726e6 + checksum: 10c0/05e5e5fcd3fcf9129406e4feda81debc0373cc1efe3e7d8f7aee1be7df523128d9e676024e2bc4ae189a0f880a3f13e510ae6547c2e8786889d5a15222b22a26 languageName: node linkType: hard -"abbrev@npm:^2.0.0": - version: 2.0.0 - resolution: "abbrev@npm:2.0.0" - checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 +"abbrev@npm:^3.0.0": + version: 3.0.1 + resolution: "abbrev@npm:3.0.1" + checksum: 10c0/21ba8f574ea57a3106d6d35623f2c4a9111d9ee3e9a5be47baed46ec2457d2eac46e07a5c4a60186f88cb98abbe3e24f2d4cca70bc2b12f1692523e2209a9ccf languageName: node linkType: hard @@ -1744,12 +1809,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.13.0, acorn@npm:^8.14.0, acorn@npm:^8.6.0": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" +"acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.14.1, acorn@npm:^8.6.0": + version: 8.14.1 + resolution: "acorn@npm:8.14.1" bin: acorn: bin/acorn - checksum: 10c0/6d4ee461a7734b2f48836ee0fbb752903606e576cc100eb49340295129ca0b452f3ba91ddd4424a1d4406a98adfb2ebb6bd0ff4c49d7a0930c10e462719bbfd7 + checksum: 10c0/dbd36c1ed1d2fa3550140000371fcf721578095b18777b85a79df231ca093b08edc6858d75d6e48c73e431c174dcf9214edbd7e6fa5911b93bd8abfa54e47123 languageName: node linkType: hard @@ -1760,15 +1825,6 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:6": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: "npm:4" - checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 - languageName: node - linkType: hard - "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.3 resolution: "agent-base@npm:7.1.3" @@ -1796,9 +1852,9 @@ __metadata: linkType: hard "ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 + version: 6.1.0 + resolution: "ansi-regex@npm:6.1.0" + checksum: 10c0/a91daeddd54746338478eef88af3439a7edf30f8e23196e2d6ed182da9add559c601266dbef01c2efa46a958ad6f1f8b176799657616c702b5b02e799e7fd8dc languageName: node linkType: hard @@ -1825,23 +1881,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 10c0/d06e26384a8f6245d8c8896e138c0388824e259a329e0c9f196b4fa533c82502a6fd449586e3604950a0c42921832a458bb3aa0aa9f0ba449cfd4f50fd0d09b5 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^2.0.0": - version: 2.0.0 - resolution: "are-we-there-yet@npm:2.0.0" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^3.6.0" - checksum: 10c0/375f753c10329153c8d66dc95e8f8b6c7cc2aa66e05cb0960bd69092b10dae22900cacc7d653ad11d26b3ecbdbfe1e8bfb6ccf0265ba8077a7d979970f16b99c - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -1885,42 +1924,42 @@ __metadata: linkType: hard "ava@npm:^6.2.0": - version: 6.2.0 - resolution: "ava@npm:6.2.0" + version: 6.3.0 + resolution: "ava@npm:6.3.0" dependencies: - "@vercel/nft": "npm:^0.27.5" - acorn: "npm:^8.13.0" + "@vercel/nft": "npm:^0.29.2" + acorn: "npm:^8.14.1" acorn-walk: "npm:^8.3.4" ansi-styles: "npm:^6.2.1" arrgv: "npm:^1.0.2" arrify: "npm:^3.0.0" callsites: "npm:^4.2.0" - cbor: "npm:^9.0.2" - chalk: "npm:^5.3.0" + cbor: "npm:^10.0.3" + chalk: "npm:^5.4.1" chunkd: "npm:^2.0.1" - ci-info: "npm:^4.0.0" + ci-info: "npm:^4.2.0" ci-parallel-vars: "npm:^1.0.1" cli-truncate: "npm:^4.0.0" code-excerpt: "npm:^4.0.0" common-path-prefix: "npm:^3.0.0" concordance: "npm:^5.0.4" currently-unhandled: "npm:^0.4.1" - debug: "npm:^4.3.7" - emittery: "npm:^1.0.3" + debug: "npm:^4.4.0" + emittery: "npm:^1.1.0" figures: "npm:^6.1.0" - globby: "npm:^14.0.2" + globby: "npm:^14.1.0" ignore-by-default: "npm:^2.1.0" indent-string: "npm:^5.0.0" is-plain-object: "npm:^5.0.0" is-promise: "npm:^4.0.0" matcher: "npm:^5.0.0" - memoize: "npm:^10.0.0" + memoize: "npm:^10.1.0" ms: "npm:^2.1.3" - p-map: "npm:^7.0.2" + p-map: "npm:^7.0.3" package-config: "npm:^5.0.0" picomatch: "npm:^4.0.2" plur: "npm:^5.1.0" - pretty-ms: "npm:^9.1.0" + pretty-ms: "npm:^9.2.0" resolve-cwd: "npm:^3.0.0" stack-utils: "npm:^2.0.6" strip-ansi: "npm:^7.1.0" @@ -1935,7 +1974,7 @@ __metadata: optional: true bin: ava: entrypoints/cli.mjs - checksum: 10c0/25a37413c9ee1b5322dc5a266f546236ea4b52e5c04ae4b52a7b26db9263eebe2dbcda687bf4d464867e558e9148e4567aa09a7ec91d46e3218ab93204e3c653 + checksum: 10c0/10abc34f2d323b74b27fa6cb3ba808603c898459b0807d506be22ced15c32e977c278de119612838718179511df91fed2bfa1767238255829cf0bafe4fd3b721 languageName: node linkType: hard @@ -2058,16 +2097,16 @@ __metadata: linkType: hard "bn.js@npm:^4.11.9": - version: 4.12.0 - resolution: "bn.js@npm:4.12.0" - checksum: 10c0/9736aaa317421b6b3ed038ff3d4491935a01419ac2d83ddcfebc5717385295fcfcf0c57311d90fe49926d0abbd7a9dbefdd8861e6129939177f7e67ebc645b21 + version: 4.12.2 + resolution: "bn.js@npm:4.12.2" + checksum: 10c0/09a249faa416a9a1ce68b5f5ec8bbca87fe54e5dd4ef8b1cc8a4969147b80035592bddcb1e9cc814c3ba79e573503d5c5178664b722b509fb36d93620dba9b57 languageName: node linkType: hard "bn.js@npm:^5.2.0": - version: 5.2.1 - resolution: "bn.js@npm:5.2.1" - checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa + version: 5.2.2 + resolution: "bn.js@npm:5.2.2" + checksum: 10c0/cb97827d476aab1a0194df33cd84624952480d92da46e6b4a19c32964aa01553a4a613502396712704da2ec8f831cf98d02e74ca03398404bd78a037ba93f2ab languageName: node linkType: hard @@ -2145,6 +2184,16 @@ __metadata: languageName: node linkType: hard +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + languageName: node + linkType: hard + "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -2159,12 +2208,12 @@ __metadata: languageName: node linkType: hard -"cbor@npm:^9.0.2": - version: 9.0.2 - resolution: "cbor@npm:9.0.2" +"cbor@npm:^10.0.3": + version: 10.0.3 + resolution: "cbor@npm:10.0.3" dependencies: - nofilter: "npm:^3.1.0" - checksum: 10c0/709d4378067e663107b3d63a02d123a7b33e28946b4c5cc40c102f2f0ba13b072a79adc4369bb87a4e743399fce45deec30463fc84d363ab7cb39192d0fe5f30 + nofilter: "npm:^3.0.2" + checksum: 10c0/d1657a24799ab35cb262aef91205431100def90c0200917e42eec4580726880c090d5a0a77620b665248447a36db8cc5ea6b7fd6eac8e083a64098c7179ea2d1 languageName: node linkType: hard @@ -2178,10 +2227,10 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.3.0": - version: 5.3.0 - resolution: "chalk@npm:5.3.0" - checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 +"chalk@npm:^5.4.1": + version: 5.4.1 + resolution: "chalk@npm:5.4.1" + checksum: 10c0/b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef languageName: node linkType: hard @@ -2192,13 +2241,6 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -2213,10 +2255,10 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^4.0.0": - version: 4.0.0 - resolution: "ci-info@npm:4.0.0" - checksum: 10c0/ecc003e5b60580bd081d83dd61d398ddb8607537f916313e40af4667f9c92a1243bd8e8a591a5aa78e418afec245dbe8e90a0e26e39ca0825129a99b978dd3f9 +"ci-info@npm:^4.2.0": + version: 4.2.0 + resolution: "ci-info@npm:4.2.0" + checksum: 10c0/37a2f4b6a213a5cf835890eb0241f0d5b022f6cfefde58a69e9af8e3a0e71e06d6ad7754b0d4efb9cd2613e58a7a33996d71b56b0d04242722e86666f3f3d058 languageName: node linkType: hard @@ -2273,15 +2315,6 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.2": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 10c0/8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 - languageName: node - linkType: hard - "combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" @@ -2328,10 +2361,10 @@ __metadata: languageName: node linkType: hard -"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 10c0/7ab51d30b52d461412cd467721bb82afe695da78fff8f29fe6f6b9cbaac9a2328e27a22a966014df9532100f6dd85370460be8130b9c677891ba36d96a343f50 +"consola@npm:^3.2.3": + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a languageName: node linkType: hard @@ -2350,15 +2383,15 @@ __metadata: linkType: hard "cross-fetch@npm:^3.1.5": - version: 3.1.8 - resolution: "cross-fetch@npm:3.1.8" + version: 3.2.0 + resolution: "cross-fetch@npm:3.2.0" dependencies: - node-fetch: "npm:^2.6.12" - checksum: 10c0/4c5e022ffe6abdf380faa6e2373c0c4ed7ef75e105c95c972b6f627c3f083170b6886f19fb488a7fa93971f4f69dcc890f122b0d97f0bf5f41ca1d9a8f58c8af + node-fetch: "npm:^2.7.0" + checksum: 10c0/d8596adf0269130098a676f6739a0922f3cc7b71cc89729925411ebe851a87026171c82ea89154c4811c9867c01c44793205a52e618ce2684650218c7fbeeb9f languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -2387,15 +2420,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7": - version: 4.3.7 - resolution: "debug@npm:4.3.7" +"debug@npm:4, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0": + version: 4.4.1 + resolution: "debug@npm:4.4.1" dependencies: ms: "npm:^2.1.3" peerDependenciesMeta: supports-color: optional: true - checksum: 10c0/1471db19c3b06d485a622d62f65947a19a23fbd0dd73f7fd3eafb697eec5360cde447fb075919987899b1a2096e85d35d4eb5a4de09a57600ac9cf7e6c8e768b + checksum: 10c0/d2b44bc1afd912b49bb7ebb0d50a860dc93a4dd7d946e8de94abc957bb63726b7dd5aa48c18c2386c379ec024c46692e15ed3ed97d481729f929201e671fcd55 languageName: node linkType: hard @@ -2458,17 +2491,21 @@ __metadata: languageName: node linkType: hard -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: 10c0/ba05874b91148e1db4bf254750c042bf2215febd23a6d3cda2e64896aef79745fbd4b9996488bd3cafb39ce19dbce0fd6e3b6665275638befffe1c9b312b91b5 +"detect-libc@npm:^2.0.0": + version: 2.0.4 + resolution: "detect-libc@npm:2.0.4" + checksum: 10c0/c15541f836eba4b1f521e4eecc28eefefdbc10a94d3b8cb4c507689f332cc111babb95deda66f2de050b22122113189986d5190be97d51b5a2b23b938415e67c languageName: node linkType: hard -"detect-libc@npm:^2.0.0": - version: 2.0.3 - resolution: "detect-libc@npm:2.0.3" - checksum: 10c0/88095bda8f90220c95f162bf92cad70bd0e424913e655c20578600e35b91edc261af27531cf160a331e185c0ced93944bc7e09939143225f56312d7fd800fdb7 +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 languageName: node linkType: hard @@ -2479,7 +2516,7 @@ __metadata: languageName: node linkType: hard -"elliptic@npm:^6.5.4": +"elliptic@npm:^6.5.4, elliptic@npm:^6.6.1": version: 6.6.1 resolution: "elliptic@npm:6.6.1" dependencies: @@ -2494,17 +2531,17 @@ __metadata: languageName: node linkType: hard -"emittery@npm:^1.0.3": - version: 1.0.3 - resolution: "emittery@npm:1.0.3" - checksum: 10c0/91605d044f3891dd1f8ab731aeb94b520488b21e707f7064dcbcf5303bac3b4e7133dfa23c343ede1fc970340bd78a9b1aed522b805bc15104606bba630dd71e +"emittery@npm:^1.1.0": + version: 1.1.0 + resolution: "emittery@npm:1.1.0" + checksum: 10c0/645d4d7307b52c81bb2d2f9f320aa6a3c0225f53a4bfef2d337be8086df975746f7dd619f1dd7b2ffd4f2288103f28019e7b8567718677600e47507496d3af5f languageName: node linkType: hard "emoji-regex@npm:^10.3.0": - version: 10.3.0 - resolution: "emoji-regex@npm:10.3.0" - checksum: 10c0/b4838e8dcdceb44cf47f59abe352c25ff4fe7857acaf5fb51097c427f6f75b44d052eb907a7a3b86f86bc4eae3a93f5c2b7460abe79c407307e6212d65c91163 + version: 10.4.0 + resolution: "emoji-regex@npm:10.4.0" + checksum: 10c0/a3fcedfc58bfcce21a05a5f36a529d81e88d602100145fcca3dc6f795e3c8acc4fc18fe773fbf9b6d6e9371205edb3afa2668ec3473fa2aa7fd47d2a9d46482d languageName: node linkType: hard @@ -2554,12 +2591,10 @@ __metadata: languageName: node linkType: hard -"es-define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "es-define-property@npm:1.0.0" - dependencies: - get-intrinsic: "npm:^1.2.4" - checksum: 10c0/6bf3191feb7ea2ebda48b577f69bdfac7a2b3c9bcf97307f55fd6ef1bbca0b49f0c219a935aca506c993d8c5d8bddd937766cb760cd5e5a1071351f2df9f9aa4 +"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c languageName: node linkType: hard @@ -2570,10 +2605,31 @@ __metadata: languageName: node linkType: hard +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.6" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.2" + checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af + languageName: node + linkType: hard + "escalade@npm:^3.1.1": - version: 3.1.2 - resolution: "escalade@npm:3.1.2" - checksum: 10c0/6b4adafecd0682f3aa1cd1106b8fff30e492c7015b178bc81b2d2f75106dabea6c6d6e8508fc491bd58e597c74abb0e8e2368f943ecb9393d4162e3c2f3cf287 + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 languageName: node linkType: hard @@ -2599,13 +2655,13 @@ __metadata: linkType: hard "eslint-config-prettier@npm:^10.1.1": - version: 10.1.1 - resolution: "eslint-config-prettier@npm:10.1.1" + version: 10.1.5 + resolution: "eslint-config-prettier@npm:10.1.5" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 10c0/3dbfdf6495dd62e2e1644ea9e8e978100dabcd8740fd264df1222d130001a1e8de05d6ed6c67d3a60727386a07507f067d1ca79af6d546910414beab19e7966e + checksum: 10c0/5486255428e4577e8064b40f27db299faf7312b8e43d7b4bc913a6426e6c0f5950cd519cad81ae24e9aecb4002c502bc665c02e3b52efde57af2debcf27dd6e0 languageName: node linkType: hard @@ -2619,7 +2675,7 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0": +"eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 @@ -2634,17 +2690,17 @@ __metadata: linkType: hard "eslint@npm:^9.22.0": - version: 9.22.0 - resolution: "eslint@npm:9.22.0" + version: 9.27.0 + resolution: "eslint@npm:9.27.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.19.2" - "@eslint/config-helpers": "npm:^0.1.0" - "@eslint/core": "npm:^0.12.0" - "@eslint/eslintrc": "npm:^3.3.0" - "@eslint/js": "npm:9.22.0" - "@eslint/plugin-kit": "npm:^0.2.7" + "@eslint/config-array": "npm:^0.20.0" + "@eslint/config-helpers": "npm:^0.2.1" + "@eslint/core": "npm:^0.14.0" + "@eslint/eslintrc": "npm:^3.3.1" + "@eslint/js": "npm:9.27.0" + "@eslint/plugin-kit": "npm:^0.3.1" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" @@ -2679,7 +2735,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10c0/7b5ab6f2365971c16efe97349565f75d8343347562fb23f12734c6ab2cd5e35301373a0d51e194789ddcfdfca21db7b62ff481b03d524b8169896c305b65ff48 + checksum: 10c0/135d301e37cd961000a9c1d3f0e1863bed29a61435dfddedba3db295973193024382190fd8790a8de83777d10f450082a29eaee8bc9ce0fb1bc1f2b0bb882280 languageName: node linkType: hard @@ -2734,8 +2790,8 @@ __metadata: linkType: hard "ethers@npm:^6.13.4": - version: 6.13.4 - resolution: "ethers@npm:6.13.4" + version: 6.14.1 + resolution: "ethers@npm:6.14.1" dependencies: "@adraffy/ens-normalize": "npm:1.10.1" "@noble/curves": "npm:1.2.0" @@ -2744,13 +2800,13 @@ __metadata: aes-js: "npm:4.0.0-beta.5" tslib: "npm:2.7.0" ws: "npm:8.17.1" - checksum: 10c0/efcf9f39f841e38af68ec23cdbd745432c239c256aac4929842d1af04e55d7be0ff65e462f1cf3e93586f43f7bdcc0098fd56f2f7234f36d73e466521a5766ce + checksum: 10c0/492bba4512b87475c9c4523d577eafa8bfe1b6d86afb78b4a0410acbf4966c1c121c2763478e9b1558460a725df5ba4f08d76ee74cb53e43cf5d8391f37079d0 languageName: node linkType: hard "execa@npm:^9.5.2": - version: 9.5.2 - resolution: "execa@npm:9.5.2" + version: 9.5.3 + resolution: "execa@npm:9.5.3" dependencies: "@sindresorhus/merge-streams": "npm:^4.0.0" cross-spawn: "npm:^7.0.3" @@ -2764,7 +2820,7 @@ __metadata: signal-exit: "npm:^4.1.0" strip-final-newline: "npm:^4.0.0" yoctocolors: "npm:^2.0.0" - checksum: 10c0/94782a6282e03253224406c29068d18f9095cc251a45d1f19ac3d8f2a9db2cbe32fb8ceb039db1451d8fce3531135a6c0c559f76d634f85416268fc4a6995365 + checksum: 10c0/f39b38b960cfd68a69e73f19f74e6b5a15b43f913130c89e96d4c9377c6baa18243033bc5087003e25e6f67916dc5f37fc7cd3b940dfe699c30be5d17ba5fa1e languageName: node linkType: hard @@ -2776,9 +2832,9 @@ __metadata: linkType: hard "exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 + version: 3.1.2 + resolution: "exponential-backoff@npm:3.1.2" + checksum: 10c0/d9d3e1eafa21b78464297df91f1776f7fbaa3d5e3f7f0995648ca5b89c069d17055033817348d9f4a43d1c20b0eab84f75af6991751e839df53e4dfd6f22e844 languageName: node linkType: hard @@ -2796,16 +2852,16 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.3.2": - version: 3.3.2 - resolution: "fast-glob@npm:3.3.2" +"fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3": + version: 3.3.3 + resolution: "fast-glob@npm:3.3.3" dependencies: "@nodelib/fs.stat": "npm:^2.0.2" "@nodelib/fs.walk": "npm:^1.2.3" glob-parent: "npm:^5.1.2" merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.4" - checksum: 10c0/42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845 + micromatch: "npm:^4.0.8" + checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe languageName: node linkType: hard @@ -2824,11 +2880,23 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.17.1 - resolution: "fastq@npm:1.17.1" + version: 1.19.1 + resolution: "fastq@npm:1.19.1" dependencies: reusify: "npm:^1.0.4" - checksum: 10c0/1095f16cea45fb3beff558bb3afa74ca7a9250f5a670b65db7ed585f92b4b48381445cd328b3d87323da81e43232b5d5978a8201bde84e0cd514310f1ea6da34 + checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630 + languageName: node + linkType: hard + +"fdir@npm:^6.4.4": + version: 6.4.4 + resolution: "fdir@npm:6.4.4" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/6ccc33be16945ee7bc841e1b4178c0b4cf18d3804894cb482aa514651c962a162f96da7ffc6ebfaf0df311689fb70091b04dd6caffe28d56b9ebdc0e7ccadfdd languageName: node linkType: hard @@ -2874,9 +2942,9 @@ __metadata: linkType: hard "find-up-simple@npm:^1.0.0": - version: 1.0.0 - resolution: "find-up-simple@npm:1.0.0" - checksum: 10c0/de1ad5e55c8c162f5600fe3297bb55a3da5cd9cb8c6755e463ec1d52c4c15a84e312a68397fb5962d13263b3dbd4ea294668c465ccacc41291d7cc97588769f9 + version: 1.0.1 + resolution: "find-up-simple@npm:1.0.1" + checksum: 10c0/ad34de157b7db925d50ff78302fefb28e309f3bc947c93ffca0f9b0bccf9cf1a2dc57d805d5c94ec9fc60f4838f5dbdfd2a48ecd77c23015fa44c6dd5f60bc40 languageName: node linkType: hard @@ -2901,40 +2969,41 @@ __metadata: linkType: hard "flatted@npm:^3.2.9": - version: 3.3.1 - resolution: "flatted@npm:3.3.1" - checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf + version: 3.3.3 + resolution: "flatted@npm:3.3.3" + checksum: 10c0/e957a1c6b0254aa15b8cce8533e24165abd98fadc98575db082b786b5da1b7d72062b81bfdcd1da2f4d46b6ed93bec2434e62333e9b4261d79ef2e75a10dd538 languageName: node linkType: hard "follow-redirects@npm:^1.15.4": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" + version: 1.15.9 + resolution: "follow-redirects@npm:1.15.9" peerDependenciesMeta: debug: optional: true - checksum: 10c0/9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071 + checksum: 10c0/5829165bd112c3c0e82be6c15b1a58fa9dcfaede3b3c54697a82fe4a62dd5ae5e8222956b448d2f98e331525f05d00404aba7d696de9e761ef6e42fdc780244f languageName: node linkType: hard "foreground-child@npm:^3.1.0": - version: 3.3.0 - resolution: "foreground-child@npm:3.3.0" + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" dependencies: - cross-spawn: "npm:^7.0.0" + cross-spawn: "npm:^7.0.6" signal-exit: "npm:^4.0.1" - checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2 + checksum: 10c0/8986e4af2430896e65bc2788d6679067294d6aee9545daefc84923a0a4b399ad9c7a3ea7bd8c0b2b80fdf4a92de4c69df3f628233ff3224260e9c1541a9e9ed3 languageName: node linkType: hard "form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" + version: 4.0.2 + resolution: "form-data@npm:4.0.2" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" mime-types: "npm:^2.1.12" - checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + checksum: 10c0/e534b0cf025c831a0929bf4b9bbe1a9a6b03e273a8161f9947286b9b13bf8fb279c6944aae0070c4c311100c6d6dbb815cd955dc217728caf73fad8dc5b8ee9c languageName: node linkType: hard @@ -2946,22 +3015,13 @@ __metadata: linkType: hard "fs-extra@npm:^11.2.0": - version: 11.2.0 - resolution: "fs-extra@npm:11.2.0" + version: 11.3.0 + resolution: "fs-extra@npm:11.3.0" dependencies: graceful-fs: "npm:^4.2.0" jsonfile: "npm:^6.0.1" universalify: "npm:^2.0.0" - checksum: 10c0/d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 + checksum: 10c0/5f95e996186ff45463059feb115a22fb048bdaf7e487ecee8a8646c78ed8fdca63630e3077d4c16ce677051f5e60d3355a06f3cd61f3ca43f48cc58822a44d0a languageName: node linkType: hard @@ -2974,13 +3034,6 @@ __metadata: languageName: node linkType: hard -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 - languageName: node - linkType: hard - "function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" @@ -2988,23 +3041,6 @@ __metadata: languageName: node linkType: hard -"gauge@npm:^3.0.0": - version: 3.0.2 - resolution: "gauge@npm:3.0.2" - dependencies: - aproba: "npm:^1.0.3 || ^2.0.0" - color-support: "npm:^1.1.2" - console-control-strings: "npm:^1.0.0" - has-unicode: "npm:^2.0.1" - object-assign: "npm:^4.1.1" - signal-exit: "npm:^3.0.0" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - wide-align: "npm:^1.1.2" - checksum: 10c0/75230ccaf216471e31025c7d5fcea1629596ca20792de50c596eb18ffb14d8404f927cd55535aab2eeecd18d1e11bd6f23ec3c2e9878d2dda1dc74bccc34b913 - languageName: node - linkType: hard - "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -3013,22 +3049,37 @@ __metadata: linkType: hard "get-east-asian-width@npm:^1.0.0": - version: 1.2.0 - resolution: "get-east-asian-width@npm:1.2.0" - checksum: 10c0/914b1e217cf38436c24b4c60b4c45289e39a45bf9e65ef9fd343c2815a1a02b8a0215aeec8bf9c07c516089004b6e3826332481f40a09529fcadbf6e579f286b + version: 1.3.0 + resolution: "get-east-asian-width@npm:1.3.0" + checksum: 10c0/1a049ba697e0f9a4d5514c4623781c5246982bdb61082da6b5ae6c33d838e52ce6726407df285cdbb27ec1908b333cf2820989bd3e986e37bb20979437fdf34b languageName: node linkType: hard -"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.4": - version: 1.2.4 - resolution: "get-intrinsic@npm:1.2.4" +"get-intrinsic@npm:^1.2.6": + version: 1.3.0 + resolution: "get-intrinsic@npm:1.3.0" dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" function-bind: "npm:^1.1.2" - has-proto: "npm:^1.0.1" - has-symbols: "npm:^1.0.3" - hasown: "npm:^2.0.0" - checksum: 10c0/0a9b82c16696ed6da5e39b1267104475c47e3a9bdbe8b509dfe1710946e38a87be70d759f4bb3cda042d76a41ef47fe769660f3b7c0d1f68750299344ffb15b7 + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a + languageName: node + linkType: hard + +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c languageName: node linkType: hard @@ -3067,7 +3118,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.4.5": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -3083,20 +3134,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe - languageName: node - linkType: hard - "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" @@ -3121,26 +3158,24 @@ __metadata: languageName: node linkType: hard -"globby@npm:^14.0.2": - version: 14.0.2 - resolution: "globby@npm:14.0.2" +"globby@npm:^14.1.0": + version: 14.1.0 + resolution: "globby@npm:14.1.0" dependencies: "@sindresorhus/merge-streams": "npm:^2.1.0" - fast-glob: "npm:^3.3.2" - ignore: "npm:^5.2.4" - path-type: "npm:^5.0.0" + fast-glob: "npm:^3.3.3" + ignore: "npm:^7.0.3" + path-type: "npm:^6.0.0" slash: "npm:^5.1.0" - unicorn-magic: "npm:^0.1.0" - checksum: 10c0/3f771cd683b8794db1e7ebc8b6b888d43496d93a82aad4e9d974620f578581210b6c5a6e75ea29573ed16a1345222fab6e9b877a8d1ed56eeb147e09f69c6f78 + unicorn-magic: "npm:^0.3.0" + checksum: 10c0/527a1063c5958255969620c6fa4444a2b2e9278caddd571d46dfbfa307cb15977afb746e84d682ba5b6c94fc081e8997f80ff05dd235441ba1cb16f86153e58e languageName: node linkType: hard -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.1.3" - checksum: 10c0/505c05487f7944c552cee72087bf1567debb470d4355b1335f2c262d218ebbff805cd3715448fe29b4b380bae6912561d0467233e4165830efd28da241418c63 +"gopd@npm:^1.0.1, gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead languageName: node linkType: hard @@ -3174,24 +3209,19 @@ __metadata: languageName: node linkType: hard -"has-proto@npm:^1.0.1": - version: 1.0.3 - resolution: "has-proto@npm:1.0.3" - checksum: 10c0/35a6989f81e9f8022c2f4027f8b48a552de714938765d019dbea6bb547bd49ce5010a3c7c32ec6ddac6e48fc546166a3583b128f5a7add8b058a6d8b4afec205 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: 10c0/e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e languageName: node linkType: hard -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 10c0/ebdb2f4895c26bb08a8a100b62d362e49b2190bcfd84b76bc4be1a3bd4d254ec52d0dd9f2fbcc093fc5eb878b20c52146f9dfd33e2686ed28982187be593b47c +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c languageName: node linkType: hard @@ -3205,7 +3235,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0": +"hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -3226,9 +3256,9 @@ __metadata: linkType: hard "http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 languageName: node linkType: hard @@ -3242,17 +3272,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: "npm:6" - debug: "npm:4" - checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" dependencies: @@ -3263,9 +3283,9 @@ __metadata: linkType: hard "human-signals@npm:^8.0.0": - version: 8.0.0 - resolution: "human-signals@npm:8.0.0" - checksum: 10c0/e4dac4f7d3eb791ed04129fc6a85bd454a9102d3e3b76c911d0db7057ebd60b2956b435b5b5712aec18960488ede3c21ef7c56e42cdd70760c0d84d3c05cd92e + version: 8.0.1 + resolution: "human-signals@npm:8.0.1" + checksum: 10c0/195ac607108c56253757717242e17cd2e21b29f06c5d2dad362e86c672bf2d096e8a3bbb2601841c376c2301c4ae7cff129e87f740aa4ebff1390c163114c7c4 languageName: node linkType: hard @@ -3292,20 +3312,27 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1": +"ignore@npm:^5.2.0": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 languageName: node linkType: hard +"ignore@npm:^7.0.0, ignore@npm:^7.0.3": + version: 7.0.4 + resolution: "ignore@npm:7.0.4" + checksum: 10c0/90e1f69ce352b9555caecd9cbfd07abe7626d312a6f90efbbb52c7edca6ea8df065d66303863b30154ab1502afb2da8bc59d5b04e1719a52ef75bbf675c488eb + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1": - version: 3.3.0 - resolution: "import-fresh@npm:3.3.0" + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" dependencies: parent-module: "npm:^1.0.0" resolve-from: "npm:^4.0.0" - checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec languageName: node linkType: hard @@ -3330,17 +3357,7 @@ __metadata: languageName: node linkType: hard -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4": +"inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 @@ -3437,9 +3454,9 @@ __metadata: linkType: hard "is-unicode-supported@npm:^2.0.0": - version: 2.0.0 - resolution: "is-unicode-supported@npm:2.0.0" - checksum: 10c0/3013dfb8265fe9f9a0d1e9433fc4e766595631a8d85d60876c457b4bedc066768dab1477c553d02e2f626d88a4e019162706e04263c94d74994ef636a33b5f94 + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10c0/a0f53e9a7c1fdbcf2d2ef6e40d4736fdffff1c9f8944c75e15425118ff3610172c87bf7bc6c34d3903b04be59790bb2212ddbe21ee65b5a97030fc50370545a5 languageName: node linkType: hard @@ -3593,19 +3610,19 @@ __metadata: languageName: node linkType: hard -"libsodium-sumo@npm:^0.7.13": - version: 0.7.13 - resolution: "libsodium-sumo@npm:0.7.13" - checksum: 10c0/8159205cc36cc4bdf46ee097e5f998d5cac7d11612be7406a8396ca3ee31560871ac17daa69e47ff0e8407eeae9f49313912ea95dbc8715875301b004c28ef5b +"libsodium-sumo@npm:^0.7.15": + version: 0.7.15 + resolution: "libsodium-sumo@npm:0.7.15" + checksum: 10c0/5a1437ccff03c72669e7b49da702034e171df9ff6a4e65698297ab63ad0bf8f889d3dd51494e29418c643143526d8d7f08cbba3929d220334cddbe3e74a1560e languageName: node linkType: hard "libsodium-wrappers-sumo@npm:^0.7.11": - version: 0.7.13 - resolution: "libsodium-wrappers-sumo@npm:0.7.13" + version: 0.7.15 + resolution: "libsodium-wrappers-sumo@npm:0.7.15" dependencies: - libsodium-sumo: "npm:^0.7.13" - checksum: 10c0/51a151d0f73418632dcf9cf0184b14d8eb6e16b9a3f01a652c7401c6d1bf8ead4f5ce40a4f00bd4754c5719a7a5fb71d6125691896aeb7a9c1abcfe4b73afc02 + libsodium-sumo: "npm:^0.7.15" + checksum: 10c0/6da919a13395346d54f2ce4841adda8feb3fbb8a8c378ec5c93b7e6dc6353b379289349e659f3e017a9f1995ef396bf43f89c7ab4aab4e3b5ed85df62407d810 languageName: node linkType: hard @@ -3646,15 +3663,6 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.1.0": - version: 3.1.0 - resolution: "make-dir@npm:3.1.0" - dependencies: - semver: "npm:^6.0.0" - checksum: 10c0/56aaafefc49c2dfef02c5c95f9b196c4eb6988040cf2c712185c7fe5c99b4091591a7fc4d4eafaaefa70ff763a26f6ab8c3ff60b9e75ea19876f49b18667ecaa - languageName: node - linkType: hard - "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" @@ -3683,6 +3691,13 @@ __metadata: languageName: node linkType: hard +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f + languageName: node + linkType: hard + "md5-hex@npm:^3.0.1": version: 3.0.1 resolution: "md5-hex@npm:3.0.1" @@ -3692,12 +3707,12 @@ __metadata: languageName: node linkType: hard -"memoize@npm:^10.0.0": - version: 10.0.0 - resolution: "memoize@npm:10.0.0" +"memoize@npm:^10.1.0": + version: 10.1.0 + resolution: "memoize@npm:10.1.0" dependencies: - mimic-function: "npm:^5.0.0" - checksum: 10c0/1584351834564be66b21d47b7afe495851f622669ad49e2f4fa4f35d5633471b93176cf602130a95f71fa0aee65a20179817ffac2dd11fa354aa19a8109a14e8 + mimic-function: "npm:^5.0.1" + checksum: 10c0/6cf71f673b89778b05cd1131f573ba858627daa8fec60f2197328386acf7ab184a89e52527abbd5a605b5ccf5ee12dc0cb96efb651d9a30dcfcc89e9baacc84d languageName: node linkType: hard @@ -3708,7 +3723,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": +"micromatch@npm:^4.0.8": version: 4.0.8 resolution: "micromatch@npm:4.0.8" dependencies: @@ -3745,7 +3760,7 @@ __metadata: languageName: node linkType: hard -"mimic-function@npm:^5.0.0": +"mimic-function@npm:^5.0.1": version: 5.0.1 resolution: "mimic-function@npm:5.0.1" checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d @@ -3773,7 +3788,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -3808,8 +3823,8 @@ __metadata: linkType: hard "minipass-fetch@npm:^4.0.0": - version: 4.0.0 - resolution: "minipass-fetch@npm:4.0.0" + version: 4.0.1 + resolution: "minipass-fetch@npm:4.0.1" dependencies: encoding: "npm:^0.1.13" minipass: "npm:^7.0.3" @@ -3818,7 +3833,7 @@ __metadata: dependenciesMeta: encoding: optional: true - checksum: 10c0/7fa30ce7c373fb6f94c086b374fff1589fd7e78451855d2d06c2e2d9df936d131e73e952163063016592ed3081444bd8d1ea608533313b0149156ce23311da4b + checksum: 10c0/a3147b2efe8e078c9bf9d024a0059339c5a09c5b1dded6900a219c218cc8b1b78510b62dae556b507304af226b18c3f1aeb1d48660283602d5b6586c399eed5c languageName: node linkType: hard @@ -3858,13 +3873,6 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 - languageName: node - linkType: hard - "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" @@ -3872,23 +3880,12 @@ __metadata: languageName: node linkType: hard -"minizlib@npm:^2.1.1": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: "npm:^3.0.0" - yallist: "npm:^4.0.0" - checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 - languageName: node - linkType: hard - "minizlib@npm:^3.0.1": - version: 3.0.1 - resolution: "minizlib@npm:3.0.1" + version: 3.0.2 + resolution: "minizlib@npm:3.0.2" dependencies: - minipass: "npm:^7.0.4" - rimraf: "npm:^5.0.5" - checksum: 10c0/82f8bf70da8af656909a8ee299d7ed3b3372636749d29e105f97f20e88971be31f5ed7642f2e898f00283b68b701cc01307401cdc209b0efc5dd3818220e5093 + minipass: "npm:^7.1.2" + checksum: 10c0/9f3bd35e41d40d02469cb30470c55ccc21cae0db40e08d1d0b1dff01cc8cc89a6f78e9c5d2b7c844e485ec0a8abc2238111213fdc5b2038e6d1012eacf316f78 languageName: node linkType: hard @@ -3899,15 +3896,6 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf - languageName: node - linkType: hard - "mkdirp@npm:^3.0.1": version: 3.0.1 resolution: "mkdirp@npm:3.0.1" @@ -3924,10 +3912,10 @@ __metadata: languageName: node linkType: hard -"napi-build-utils@npm:^1.0.1": - version: 1.0.2 - resolution: "napi-build-utils@npm:1.0.2" - checksum: 10c0/37fd2cd0ff2ad20073ce78d83fd718a740d568b225924e753ae51cb69d68f330c80544d487e5e5bd18e28702ed2ca469c2424ad948becd1862c1b0209542b2e9 +"napi-build-utils@npm:^2.0.0": + version: 2.0.0 + resolution: "napi-build-utils@npm:2.0.0" + checksum: 10c0/5833aaeb5cc5c173da47a102efa4680a95842c13e0d9cc70428bd3ee8d96bb2172f8860d2811799b5daa5cbeda779933601492a2028a6a5351c6d0fcf6de83db languageName: node linkType: hard @@ -3946,11 +3934,11 @@ __metadata: linkType: hard "node-abi@npm:^3.3.0": - version: 3.71.0 - resolution: "node-abi@npm:3.71.0" + version: 3.75.0 + resolution: "node-abi@npm:3.75.0" dependencies: semver: "npm:^7.3.5" - checksum: 10c0/dbd0792ea729329cd9d099f28a5681ff9e8a6db48cf64e1437bf6a7fd669009d1e758a784619a1c4cc8bfd1ed17162f042c787654edf19a1f64b5018457c9c1f + checksum: 10c0/c43a2409407df3737848fd96202b0a49e15039994aecce963969e9ef7342a8fc544aba94e0bfd8155fb9de5f5fe9a4b6ccad8bf509e7c46caf096fc4491d63f2 languageName: node linkType: hard @@ -4003,51 +3991,40 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 11.0.0 - resolution: "node-gyp@npm:11.0.0" + version: 11.2.0 + resolution: "node-gyp@npm:11.2.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" graceful-fs: "npm:^4.2.6" make-fetch-happen: "npm:^14.0.3" nopt: "npm:^8.0.0" proc-log: "npm:^5.0.0" semver: "npm:^7.3.5" tar: "npm:^7.4.3" + tinyglobby: "npm:^0.2.12" which: "npm:^5.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10c0/a3b885bbee2d271f1def32ba2e30ffcf4562a3db33af06b8b365e053153e2dd2051b9945783c3c8e852d26a0f20f65b251c7e83361623383a99635c0280ee573 + checksum: 10c0/bd8d8c76b06be761239b0c8680f655f6a6e90b48e44d43415b11c16f7e8c15be346fba0cbf71588c7cdfb52c419d928a7d3db353afc1d952d19756237d8f10b9 languageName: node linkType: hard -"nofilter@npm:^3.1.0": +"nofilter@npm:^3.0.2": version: 3.1.0 resolution: "nofilter@npm:3.1.0" checksum: 10c0/92459f3864a067b347032263f0b536223cbfc98153913b5dce350cb39c8470bc1813366e41993f22c33cc6400c0f392aa324a4b51e24c22040635c1cdb046499 languageName: node linkType: hard -"nopt@npm:^5.0.0": - version: 5.0.0 - resolution: "nopt@npm:5.0.0" - dependencies: - abbrev: "npm:1" - bin: - nopt: bin/nopt.js - checksum: 10c0/fc5c4f07155cb455bf5fc3dd149fac421c1a40fd83c6bfe83aa82b52f02c17c5e88301321318adaa27611c8a6811423d51d29deaceab5fa158b585a61a551061 - languageName: node - linkType: hard - "nopt@npm:^8.0.0": - version: 8.0.0 - resolution: "nopt@npm:8.0.0" + version: 8.1.0 + resolution: "nopt@npm:8.1.0" dependencies: - abbrev: "npm:^2.0.0" + abbrev: "npm:^3.0.0" bin: nopt: bin/nopt.js - checksum: 10c0/19cb986f79abaca2d0f0b560021da7b32ee6fcc3de48f3eaeb0c324d36755c17754f886a754c091f01f740c17caf7d6aea8237b7fbaf39f476ae5e30a249f18f + checksum: 10c0/62e9ea70c7a3eb91d162d2c706b6606c041e4e7b547cbbb48f8b3695af457dd6479904d7ace600856bf923dd8d1ed0696f06195c8c20f02ac87c1da0e1d315ef languageName: node linkType: hard @@ -4061,25 +4038,6 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^5.0.1": - version: 5.0.1 - resolution: "npmlog@npm:5.0.1" - dependencies: - are-we-there-yet: "npm:^2.0.0" - console-control-strings: "npm:^1.1.0" - gauge: "npm:^3.0.0" - set-blocking: "npm:^2.0.0" - checksum: 10c0/489ba519031013001135c463406f55491a17fc7da295c18a04937fe3a4d523fd65e88dd418a28b967ab743d913fdeba1e29838ce0ad8c75557057c481f7d49fa - languageName: node - linkType: hard - -"object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -4087,7 +4045,7 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": +"once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -4110,6 +4068,19 @@ __metadata: languageName: node linkType: hard +"osmojs@npm:^16.15.0": + version: 16.15.0 + resolution: "osmojs@npm:16.15.0" + dependencies: + "@cosmjs/amino": "npm:0.32.3" + "@cosmjs/proto-signing": "npm:0.32.3" + "@cosmjs/stargate": "npm:0.32.3" + "@cosmjs/tendermint-rpc": "npm:0.32.3" + "@cosmology/lcd": "npm:^0.13.3" + checksum: 10c0/e427dfa7f54c967c009e7642289a13e7d51feed5472f12f6b228e8c49f3d6493612333171f8580e84e666b6ac0bd149bc131222febf8c06660394a909d019a1b + languageName: node + linkType: hard + "p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" @@ -4128,10 +4099,10 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^7.0.2": - version: 7.0.2 - resolution: "p-map@npm:7.0.2" - checksum: 10c0/e10548036648d1c043153f9997112fe5a7de54a319210238628f8ea22ee36587fd6ee740811f88b60bbf29d932e23ae35df7fced40df477116c84c18e797047e +"p-map@npm:^7.0.2, p-map@npm:^7.0.3": + version: 7.0.3 + resolution: "p-map@npm:7.0.3" + checksum: 10c0/46091610da2b38ce47bcd1d8b4835a6fa4e832848a6682cf1652bc93915770f4617afc844c10a77d1b3e56d2472bb2d5622353fa3ead01a7f42b04fc8e744a5c languageName: node linkType: hard @@ -4152,6 +4123,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^2.0.2": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 10c0/8e8646581410654b50eb22a5dfd71159cae98145bd5086c9a7a816ec0370b5f72b4648d08674624b3870a521e6a3daffd6c2f7bc00fdefc7063c9d8232ff5116 + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -4175,13 +4153,6 @@ __metadata: languageName: node linkType: hard -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 - languageName: node - linkType: hard - "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -4206,14 +4177,14 @@ __metadata: languageName: node linkType: hard -"path-type@npm:^5.0.0": - version: 5.0.0 - resolution: "path-type@npm:5.0.0" - checksum: 10c0/e8f4b15111bf483900c75609e5e74e3fcb79f2ddb73e41470028fcd3e4b5162ec65da9907be077ee5012c18801ff7fffb35f9f37a077f3f81d85a0b7d6578efd +"path-type@npm:^6.0.0": + version: 6.0.0 + resolution: "path-type@npm:6.0.0" + checksum: 10c0/55baa8b1187d6dc683d5a9cfcc866168d6adff58e5db91126795376d818eee46391e00b2a4d53e44d844c7524a7d96aa68cc68f4f3e500d3d069a39e6535481c languageName: node linkType: hard -"picocolors@npm:^1.0.0": +"picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 @@ -4244,15 +4215,15 @@ __metadata: linkType: hard "prebuild-install@npm:^7.1.1": - version: 7.1.2 - resolution: "prebuild-install@npm:7.1.2" + version: 7.1.3 + resolution: "prebuild-install@npm:7.1.3" dependencies: detect-libc: "npm:^2.0.0" expand-template: "npm:^2.0.3" github-from-package: "npm:0.0.0" minimist: "npm:^1.2.3" mkdirp-classic: "npm:^0.5.3" - napi-build-utils: "npm:^1.0.1" + napi-build-utils: "npm:^2.0.0" node-abi: "npm:^3.3.0" pump: "npm:^3.0.0" rc: "npm:^1.2.7" @@ -4261,7 +4232,7 @@ __metadata: tunnel-agent: "npm:^0.6.0" bin: prebuild-install: bin.js - checksum: 10c0/e64868ba9ef2068fd7264f5b03e5298a901e02a450acdb1f56258d88c09dea601eefdb3d1dfdff8513fdd230a92961712be0676192626a3b4d01ba154d48bdd3 + checksum: 10c0/25919a42b52734606a4036ab492d37cfe8b601273d8dfb1fa3c84e141a0a475e7bad3ab848c741d2f810cef892fcf6059b8c7fe5b29f98d30e0c29ad009bedff languageName: node linkType: hard @@ -4272,7 +4243,7 @@ __metadata: languageName: node linkType: hard -"pretty-ms@npm:^9.0.0, pretty-ms@npm:^9.1.0": +"pretty-ms@npm:^9.0.0, pretty-ms@npm:^9.2.0": version: 9.2.0 resolution: "pretty-ms@npm:9.2.0" dependencies: @@ -4323,13 +4294,13 @@ __metadata: linkType: hard "query-string@npm:^9.1.1": - version: 9.1.1 - resolution: "query-string@npm:9.1.1" + version: 9.2.0 + resolution: "query-string@npm:9.2.0" dependencies: decode-uri-component: "npm:^0.4.1" filter-obj: "npm:^5.1.0" split-on-first: "npm:^3.0.0" - checksum: 10c0/16481f17754f660aec3cae7abb838a70e383dfcf152414d184e0d0f81fae426acf112b4d51bf754f9c256eaf83ba4241241ba907c8d58b6ed9704425e1712e8c + checksum: 10c0/111cdc184c35d75f08c2dcb260c3cb038e7112d888a872dcbafd015d0ee790e57fd5ad8ebcad9c7a964f130c3711fef21ed2c28eb2dbf9c163bc56c144cac926 languageName: node linkType: hard @@ -4354,7 +4325,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -4372,13 +4343,6 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.14.0": - version: 0.14.1 - resolution: "regenerator-runtime@npm:0.14.1" - checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 - languageName: node - linkType: hard - "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -4417,31 +4381,9 @@ __metadata: linkType: hard "reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107 - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10c0/9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 - languageName: node - linkType: hard - -"rimraf@npm:^5.0.5": - version: 5.0.10 - resolution: "rimraf@npm:5.0.10" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10c0/7da4fd0e15118ee05b918359462cfa1e7fe4b1228c7765195a45b55576e8c15b95db513b8466ec89129666f4af45ad978a3057a02139afba1a63512a2d9644cc + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa languageName: node linkType: hard @@ -4452,6 +4394,7 @@ __metadata: "@agoric/cosmic-proto": "npm:dev" "@agoric/fast-usdc": "npm:dev" "@cosmjs/amino": "npm:^0.32.4" + "@cosmjs/cosmwasm-stargate": "npm:^0.33.1" "@cosmjs/crypto": "npm:^0.33.0" "@cosmjs/proto-signing": "npm:^0.33.0" "@cosmjs/stargate": "npm:^0.33.0" @@ -4469,6 +4412,7 @@ __metadata: eslint-config-prettier: "npm:^10.1.1" execa: "npm:^9.5.2" fs-extra: "npm:^11.2.0" + osmojs: "npm:^16.15.0" starshipjs: "npm:2.4.1" ts-blank-space: "npm:^0.4.4" typescript: "npm:~5.8.2" @@ -4498,7 +4442,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.3.0": +"semver@npm:^6.3.0": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -4507,12 +4451,12 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.6.0": - version: 7.6.3 - resolution: "semver@npm:7.6.3" +"semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.6.0": + version: 7.7.2 + resolution: "semver@npm:7.7.2" bin: semver: bin/semver.js - checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea languageName: node linkType: hard @@ -4534,13 +4478,6 @@ __metadata: languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 - languageName: node - linkType: hard - "sha.js@npm:^2.4.11": version: 2.4.11 resolution: "sha.js@npm:2.4.11" @@ -4569,13 +4506,6 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.0": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 - languageName: node - linkType: hard - "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -4637,12 +4567,12 @@ __metadata: linkType: hard "socks@npm:^2.8.3": - version: 2.8.3 - resolution: "socks@npm:2.8.3" + version: 2.8.4 + resolution: "socks@npm:2.8.4" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 + checksum: 10c0/00c3271e233ccf1fb83a3dd2060b94cc37817e0f797a93c560b9a7a86c4a0ec2961fb31263bdd24a3c28945e24868b5f063cd98744171d9e942c513454b50ae5 languageName: node linkType: hard @@ -4690,7 +4620,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -4713,13 +4643,13 @@ __metadata: linkType: hard "string-width@npm:^7.0.0": - version: 7.1.0 - resolution: "string-width@npm:7.1.0" + version: 7.2.0 + resolution: "string-width@npm:7.2.0" dependencies: emoji-regex: "npm:^10.3.0" get-east-asian-width: "npm:^1.0.0" strip-ansi: "npm:^7.1.0" - checksum: 10c0/68a99fbc3bd3d8eb42886ff38dce819767dee55f606f74dfa4687a07dfd21262745d9683df0aa53bf81a5dd47c13da921a501925b974bec66a7ddd634fef0634 + checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9 languageName: node linkType: hard @@ -4800,14 +4730,14 @@ __metadata: linkType: hard "tar-fs@npm:^2.0.0": - version: 2.1.1 - resolution: "tar-fs@npm:2.1.1" + version: 2.1.2 + resolution: "tar-fs@npm:2.1.2" dependencies: chownr: "npm:^1.1.1" mkdirp-classic: "npm:^0.5.2" pump: "npm:^3.0.0" tar-stream: "npm:^2.1.4" - checksum: 10c0/871d26a934bfb7beeae4c4d8a09689f530b565f79bd0cf489823ff0efa3705da01278160da10bb006d1a793fa0425cf316cec029b32a9159eacbeaff4965fb6d + checksum: 10c0/9c704bd4a53be7565caf34ed001d1428532457fe3546d8fc1233f0f0882c3d2403f8602e8046e0b0adeb31fe95336572a69fb28851a391523126b697537670fc languageName: node linkType: hard @@ -4824,21 +4754,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.1.11": - version: 6.2.1 - resolution: "tar@npm:6.2.1" - dependencies: - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.0.0" - minipass: "npm:^5.0.0" - minizlib: "npm:^2.1.1" - mkdirp: "npm:^1.0.3" - yallist: "npm:^4.0.0" - checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 - languageName: node - linkType: hard - -"tar@npm:^7.4.3": +"tar@npm:^7.4.0, tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" dependencies: @@ -4866,6 +4782,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.12": + version: 0.2.13 + resolution: "tinyglobby@npm:0.2.13" + dependencies: + fdir: "npm:^6.4.4" + picomatch: "npm:^4.0.2" + checksum: 10c0/ef07dfaa7b26936601d3f6d999f7928a4d1c6234c5eb36896bb88681947c0d459b7ebe797022400e555fe4b894db06e922b95d0ce60cb05fd827a0a66326b18c + languageName: node + linkType: hard + "tmp@npm:^0.2.1": version: 0.2.3 resolution: "tmp@npm:0.2.3" @@ -4889,12 +4815,12 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^2.0.1": - version: 2.0.1 - resolution: "ts-api-utils@npm:2.0.1" +"ts-api-utils@npm:^2.1.0": + version: 2.1.0 + resolution: "ts-api-utils@npm:2.1.0" peerDependencies: typescript: ">=4.8.4" - checksum: 10c0/23fd56a958b332cac00150a652e4c84730df30571bd2faa1ba6d7b511356d1a61656621492bb6c7f15dd6e18847a1408357a0e406671d358115369a17f5bfedd + checksum: 10c0/9806a38adea2db0f6aa217ccc6bc9c391ddba338a9fe3080676d0d50ed806d305bb90e8cef0276e793d28c8a929f400abb184ddd7ff83a416959c0f4d2ce754f languageName: node linkType: hard @@ -4940,42 +4866,42 @@ __metadata: linkType: hard "typescript@npm:5.1.6 - 5.7.x": - version: 5.7.2 - resolution: "typescript@npm:5.7.2" + version: 5.7.3 + resolution: "typescript@npm:5.7.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622 + checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa languageName: node linkType: hard "typescript@npm:^5.4.5, typescript@npm:~5.8.2": - version: 5.8.2 - resolution: "typescript@npm:5.8.2" + version: 5.8.3 + resolution: "typescript@npm:5.8.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/5c4f6fbf1c6389b6928fe7b8fcd5dc73bb2d58cd4e3883f1d774ed5bd83b151cbac6b7ecf11723de56d4676daeba8713894b1e9af56174f2f9780ae7848ec3c6 + checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48 languageName: node linkType: hard "typescript@patch:typescript@npm%3A5.1.6 - 5.7.x#optional!builtin": - version: 5.7.2 - resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5786d5" + version: 5.7.3 + resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5786d5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/f3b8082c9d1d1629a215245c9087df56cb784f9fb6f27b5d55577a20e68afe2a889c040aacff6d27e35be165ecf9dca66e694c42eb9a50b3b2c451b36b5675cb + checksum: 10c0/6fd7e0ed3bf23a81246878c613423730c40e8bdbfec4c6e4d7bf1b847cbb39076e56ad5f50aa9d7ebd89877999abaee216002d3f2818885e41c907caaa192cc4 languageName: node linkType: hard "typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A~5.8.2#optional!builtin": - version: 5.8.2 - resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=5786d5" + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/5448a08e595cc558ab321e49d4cac64fb43d1fa106584f6ff9a8d8e592111b373a995a1d5c7f3046211c8a37201eb6d0f1566f15cdb7a62a5e3be01d087848e2 + checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb languageName: node linkType: hard @@ -4986,10 +4912,10 @@ __metadata: languageName: node linkType: hard -"unicorn-magic@npm:^0.1.0": - version: 0.1.0 - resolution: "unicorn-magic@npm:0.1.0" - checksum: 10c0/e4ed0de05b0a05e735c7d8a2930881e5efcfc3ec897204d5d33e7e6247f4c31eac92e383a15d9a6bccb7319b4271ee4bea946e211bf14951fec6ff2cbbb66a92 +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 languageName: node linkType: hard @@ -5087,15 +5013,6 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.2": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: 10c0/1d9c2a3e36dfb09832f38e2e699c367ef190f96b82c71f809bc0822c306f5379df87bab47bed27ea99106d86447e50eb972d3c516c2f95782807a9d082fbea95 - languageName: node - linkType: hard - "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -5158,8 +5075,8 @@ __metadata: linkType: hard "ws@npm:^7": - version: 7.5.9 - resolution: "ws@npm:7.5.9" + version: 7.5.10 + resolution: "ws@npm:7.5.10" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -5168,7 +5085,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10c0/aec4ef4eb65821a7dde7b44790f8699cfafb7978c9b080f6d7a98a7f8fc0ce674c027073a78574c94786ba7112cc90fa2cc94fc224ceba4d4b1030cff9662494 + checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d languageName: node linkType: hard @@ -5233,8 +5150,8 @@ __metadata: linkType: hard "yoctocolors@npm:^2.0.0": - version: 2.0.2 - resolution: "yoctocolors@npm:2.0.2" - checksum: 10c0/27ec9659c49084ea6da7bef50b2927128d874dc944fe4a72c2b62910b0b6e15b24747bb1c5da54a94d03b96c3c1a429c288cb9be0f8c834e9a2639e1b9ced732 + version: 2.1.1 + resolution: "yoctocolors@npm:2.1.1" + checksum: 10c0/85903f7fa96f1c70badee94789fade709f9d83dab2ec92753d612d84fcea6d34c772337a9f8914c6bed2f5fc03a428ac5d893e76fab636da5f1236ab725486d0 languageName: node linkType: hard From ea3ab00ace1cdaa221d3267b3080c25c18feb8ac Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Thu, 22 May 2025 14:10:52 +0300 Subject: [PATCH 13/24] chore(orchestration): enable non-native pools chore: WIP enable non-native pool creation chore: multichain tests for non-native pool creation chore: refine helpers api with new generic pool creation feature fix: rebase fixes --- multichain-testing/.gitignore | 8 +- .../test/xcs-swap-anything/helpers.ts | 200 ++++++++++-------- .../xcs-swap-anything/swap-anything.test.ts | 75 +++++-- 3 files changed, 172 insertions(+), 111 deletions(-) diff --git a/multichain-testing/.gitignore b/multichain-testing/.gitignore index 5689a053e09..5a94f87e4ee 100644 --- a/multichain-testing/.gitignore +++ b/multichain-testing/.gitignore @@ -8,7 +8,7 @@ start* eval-* # ci logs for archive upload logs/ -# osmosis contracts info -/test/xcs-swap-anything/xcs-contracts-info.json -# osmosis contracts artifacts -/test/xcs-swap-anything/wasm-artifacts/* +# osmosis xcs configuration +*-pool-config.json +wasm-artifacts/ +xcs-contracts-info.json diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index 7d3a1001343..055cf66ea1d 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -22,8 +22,6 @@ import { import starshipChainInfo from '../../starship-chain-info.js'; import { makeQueryClient } from '../../tools/query.js'; import type { SetupContextWithWallets } from '../support.js'; -import { makeBlockTool } from '../../tools/e2e-tools.js'; -import { makeHttpClient } from '../../tools/makeHttpClient.js'; export type SetupOsmosisContext = Awaited>; export type SetupOsmosisContextWithCommon = SetupOsmosisContext & @@ -39,10 +37,8 @@ export type Channel = { counterParty: string; }; -export type OsmosisPool = { - issuingChain: string; - issuingDenom: string; -}; +export type SwapParty = { chain: string; denom: string; amount?: string }; +export type Pair = { tokenA: SwapParty; tokenB: SwapParty }; type ContractInfoBase = { codeId: number | null; @@ -70,11 +66,6 @@ type Contracts = { export const osmosisSwapTools = async t => { const { useChain, retryUntilCondition } = t.context; - const { waitForBlock } = makeBlockTool({ - rpc: makeHttpClient('http://localhost:26657', fetch), - delay: ms => new Promise(resolve => setTimeout(resolve, ms)), - }); - const osmosisBranch = 'main'; const scriptLocalPath = './test/xcs-swap-anything/download-wasm-artifacts.sh'; const xcsArtifactsPath = './test/xcs-swap-anything/wasm-artifacts'; @@ -254,10 +245,9 @@ export const osmosisSwapTools = async t => { encodeObjects, fee, ); - console.log("invokeOsmosisContract DeliverTxResponse: ", response); - + console.log('invokeOsmosisContract DeliverTxResponse: ', response); - const { msgResponses, code } = response + const { msgResponses, code } = response; if (code !== 0) { throw Error(`Failed to execute osmosis contract with message ${message}`); @@ -335,11 +325,11 @@ export const osmosisSwapTools = async t => { const storeEncodeObjects: Array< import('@cosmjs/proto-signing').EncodeObject > = [ - { - typeUrl: MsgStoreCode.typeUrl, - value: storeMessage, - }, - ]; + { + typeUrl: MsgStoreCode.typeUrl, + value: storeMessage, + }, + ]; const storeResult = await osmosisClient.signAndBroadcast( osmosisAddress, @@ -366,11 +356,11 @@ export const osmosisSwapTools = async t => { const instantiateEncodeObjects: Array< import('@cosmjs/proto-signing').EncodeObject > = [ - { - typeUrl: MsgInstantiateContract.typeUrl, - value: instantiateMessage, - }, - ]; + { + typeUrl: MsgInstantiateContract.typeUrl, + value: instantiateMessage, + }, + ]; const instantiateResult = await osmosisClient.signAndBroadcast( osmosisAddress, @@ -503,11 +493,7 @@ export const osmosisSwapTools = async t => { } }; - const createPoolAgainstOsmo = async ( - issuingChain: string, - issuingDenom: string, - tokensAmount: string = '1000000', - ) => { + const createPool = async (chainA: SwapParty, chainB: SwapParty) => { const clientRegistry = osmosisClient.registry; osmosis.gamm.poolmodels.balancer.v1beta1.load(clientRegistry); @@ -521,17 +507,18 @@ export const osmosisSwapTools = async t => { gas: '1000000', }; - const hash = await getDenomHash('osmosis', issuingChain, issuingDenom); + const inDenom = await getFinalDenom('osmosis', chainA); + const outDenom = await getFinalDenom('osmosis', chainB); const message = MsgCreateBalancerPool.fromPartial({ sender: osmosisAddress, poolParams: { swapFee: '0.01', exitFee: '0.00' }, poolAssets: [ - { token: { denom: 'uosmo', amount: tokensAmount }, weight: '1' }, + { token: { denom: inDenom, amount: chainA.amount || '' }, weight: '1' }, { token: { - denom: `ibc/${hash}`, - amount: tokensAmount, + denom: outDenom, + amount: chainB.amount || '', }, weight: '1', }, @@ -547,26 +534,16 @@ export const osmosisSwapTools = async t => { }, ]; - const response = await osmosisClient.signAndBroadcast( + const result = await osmosisClient.signAndBroadcast( osmosisAddress, encodeObjects, fee, ); - console.log("createPoolAgainstOsmo DeliverTxResponse: ", response); - - - const { msgResponses, code } = response - - if (msgResponses[0] && code !== 0) { - throw Error(`Failed to create pool with uosmo and ${issuingDenom}`); - } - const poolId = MsgCreateBalancerPoolResponse.decode( - msgResponses[0].value, + result.msgResponses[0].value, ).poolId; - - return { poolId, hash }; + return { poolId, inDenom, outDenom }; }; const setPoolRoute = async ( @@ -595,16 +572,6 @@ export const osmosisSwapTools = async t => { await invokeOsmosisContract(swaprouterAddress, txMsg); }; - const isRouteSet = async (pool: OsmosisPool) => { - try { - await getPoolRoute(pool); - return true; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (error) { - return false; - } - }; - const queryContractsInfo = async () => { const osmosisCLI = 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; @@ -646,13 +613,38 @@ export const osmosisSwapTools = async t => { return hash; }; + const getFinalDenom = async ( + currentChain: string, + issuerChain: SwapParty, + ) => { + if (currentChain === issuerChain.chain) return issuerChain.denom; + const hash = await getDenomHash( + currentChain, + issuerChain.chain, + issuerChain.denom, + ); + + return `ibc/${hash}`; + }; + const getPools = async () => { const { createRPCQueryClient } = osmosis.ClientFactory; const client = await createRPCQueryClient({ rpcEndpoint: osmosisRpcEndpoint, }); - const { pools } = await client.osmosis.gamm.v1beta1.pools(); - return pools; + const response = await client.osmosis.gamm.v1beta1.numPools(); + return response; + }; + + const getPool = async (poolId: bigint) => { + const { createRPCQueryClient } = osmosis.ClientFactory; + const client = await createRPCQueryClient({ + rpcEndpoint: osmosisRpcEndpoint, + }); + const response = await client.osmosis.gamm.v1beta1.pool( + osmosis.gamm.v1beta1.QueryPoolRequest.fromPartial({ poolId }), + ); + return response; }; const getXcsState = async (channel: Channel) => { @@ -682,19 +674,16 @@ export const osmosisSwapTools = async t => { return { channelId, prefix }; }; - const getPoolRoute = async (pool: OsmosisPool) => { - const swaprouterAddress = xcsContracts.swaprouter.address; - if (!swaprouterAddress) { - throw new Error('swaprouter contract address not found'); - } - - const { issuingChain, issuingDenom } = pool; - - const hash = await getDenomHash('osmosis', issuingChain, issuingDenom); + const getPoolRoute = async (chainA: SwapParty, chainB: SwapParty) => { + const swaprouterAddress = xcsContracts.swaprouter.address as string; + const [inDenom, outDenom] = await Promise.all([ + getFinalDenom('osmosis', chainA), + getFinalDenom('osmosis', chainB), + ]); const queryMsg = { get_route: { - input_denom: `ibc/${hash}`, - output_denom: 'uosmo', + input_denom: inDenom, + output_denom: outDenom, }, }; @@ -702,6 +691,7 @@ export const osmosisSwapTools = async t => { swaprouterAddress, queryMsg, ); + console.log('LOG: ', pool_route); return pool_route; }; @@ -767,41 +757,61 @@ export const osmosisSwapTools = async t => { ); await setupXcsChannelLink(primary, counterParty); } + } else { + console.log('XCS contracts alrady set'); } - - console.log('XCS state updated!'); }; - const setupOsmosisPools = async (osmosisPoolList: OsmosisPool[]) => { - for (const pool of osmosisPoolList) { - const { issuingChain, issuingDenom } = pool; - console.log(`Setting Osmosis pool for uosmo, ${issuingDenom} ...`); - - if (!(await isRouteSet(pool))) { - console.log(`Funding osmosis wallet with ${issuingDenom} ...`); - await fundRemote(issuingChain, issuingDenom); + const fundRemoteIfNecessary = async ({ chain, denom }: SwapParty) => { + if (chain === 'osmosis') return; + await fundRemote(chain, denom); + }; - console.log(`Creating new pool ...`); - const { poolId, hash } = await createPoolAgainstOsmo( - issuingChain, - issuingDenom, - ); + const isRouteSet = async (chainA: SwapParty, chainB: SwapParty) => { + try { + await getPoolRoute(chainA, chainB); + return true; + } catch (error) { + console.error( + `Pool Route is not set for ${chainA.chain}.${chainA.denom} <> ${chainB.chain}.${chainB.denom}`, + error, + ); + return false; + } + }; - console.log(`Setting pool routes ...`); - const denomHash = `ibc/${hash}`; - await setPoolRoute('uosmo', denomHash, poolId.toString()); - await waitForBlock(5); - await setPoolRoute(denomHash, 'uosmo', poolId.toString()); - } + const setupNewPool = async ( + chainA: SwapParty = { chain: 'agoric', denom: 'ubld', amount: '1000000' }, + chainB: SwapParty = { chain: 'osmosis', denom: 'uosmo', amount: '1000000' }, + ) => { + if (!(await isRouteSet(chainA, chainB))) { + console.log( + `Pool being created with assets ${chainA.denom} and ${chainB.denom}`, + ); + await Promise.all([ + fundRemoteIfNecessary(chainA), + fundRemoteIfNecessary(chainB), + ]); + const { poolId, inDenom, outDenom } = await createPool(chainA, chainB); + // Don't Promise.all here to avoid sequence number mismatch + await setPoolRoute(inDenom, outDenom, poolId.toString()); + await setPoolRoute(outDenom, inDenom, poolId.toString()); + } else { + console.log( + `Pool with assets ${chainA.denom} and ${chainB.denom} already exists`, + ); + } + }; - console.log(`Osmosis pool for uosmo, ${issuingDenom} available!`); + const setupPoolsInBatch = async (pools: Pair[]) => { + for await (const { tokenA, tokenB } of pools) { + await setupNewPool(tokenA, tokenB); } }; return { setupXcsContracts, setupXcsState, - setupOsmosisPools, fundRemote, getDenomHash, getContractsInfo, @@ -809,5 +819,9 @@ export const osmosisSwapTools = async t => { getPools, getXcsState, getPoolRoute, + getPool, + setupNewPool, + setPoolRoute, + setupPoolsInBatch, }; -}; \ No newline at end of file +}; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index c49909df956..8a9071d6897 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -1,8 +1,7 @@ import anyTest from '@endo/ses-ava/prepare-endo.js'; import type { TestFn } from 'ava'; import { AmountMath } from '@agoric/ertp'; -import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; -import { makeBlockTool, makeDoOffer } from '../../tools/e2e-tools.js'; +import { makeDoOffer } from '../../tools/e2e-tools.js'; import { commonSetup } from '../support.js'; import { makeQueryClient } from '../../tools/query.js'; import starshipChainInfo from '../../starship-chain-info.js'; @@ -16,8 +15,10 @@ import { type Prefix, type Channel, type SetupOsmosisContextWithCommon, - type OsmosisPool, + type Pair, } from './helpers.js'; +import type { Pool } from 'osmojs/osmosis/gamm/v1beta1/balancerPool.js'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; const test = anyTest as TestFn; @@ -39,9 +40,19 @@ const channelList: Channel[] = [ { primary: 'cosmoshub', counterParty: 'osmosis' }, ]; -const osmosisPoolList: OsmosisPool[] = [ - { issuingChain: 'agoric', issuingDenom: 'ubld' }, - { issuingChain: 'cosmoshub', issuingDenom: 'uatom' }, +const osmosisPoolList: Pair[] = [ + { + tokenA: { chain: 'agoric', denom: 'ubld', amount: '10000000' }, + tokenB: { chain: 'osmosis', denom: 'uosmo', amount: '10000000' }, + }, + { + tokenA: { chain: 'cosmoshub', denom: 'uatom', amount: '10000000' }, + tokenB: { chain: 'osmosis', denom: 'uosmo', amount: '10000000' }, + }, + { + tokenA: { chain: 'cosmoshub', denom: 'uatom', amount: '10000000' }, + tokenB: { chain: 'agoric', denom: 'ubld', amount: '10000000' }, + }, ]; test.before(async t => { @@ -57,18 +68,25 @@ test.before(async t => { t.context = { ...common, wallets }; const swapTools = await osmosisSwapTools(t); - const { setupXcsContracts, setupXcsState, setupOsmosisPools } = swapTools; + const { setupXcsContracts, setupXcsState, setupPoolsInBatch } = swapTools; await setupXcsContracts(); await setupXcsState(prefixList, channelList); - await setupOsmosisPools(osmosisPoolList); + await setupPoolsInBatch(osmosisPoolList); t.context = { ...t.context, ...swapTools }; }); test.serial('test osmosis xcs state', async t => { - const { useChain, getContractsInfo, getXcsState, getPoolRoute, getPools } = - t.context; + const { + useChain, + getContractsInfo, + getXcsState, + getPoolRoute, + getPools, + getPool, + getDenomHash, + } = t.context; // verify if Osmosis XCS contracts were instantiated const { swaprouter, crosschain_registry, crosschain_swaps } = @@ -93,12 +111,40 @@ test.serial('test osmosis xcs state', async t => { t.is(channelId, transferChannel.channelId); // Verify if Pool was succefuly created - const pool_route = await getPoolRoute(osmosisPoolList[0]); + const pool_route = await getPoolRoute( + { chain: 'agoric', denom: 'ubld' }, + { chain: 'osmosis', denom: 'uosmo' }, + ); t.is(pool_route[0].token_out_denom, 'uosmo'); - // TODO: fix this assertion - const pools = await getPools(); - t.assert(pools, 'No Osmosis Pool found'); + const { numPools } = await getPools(); + t.assert(numPools > 0n, 'No Osmosis Pool found'); + + // Check non-native pool + const { tokenA, tokenB } = osmosisPoolList[2]; + const nonNativeRoute = await getPoolRoute(tokenA, tokenB); + console.log('ME', nonNativeRoute); + t.log(nonNativeRoute); + const [pool, chainADenomHash, chainBDenomHash] = await Promise.all([ + getPool(BigInt(nonNativeRoute[0].pool_id)), + getDenomHash('osmosis', tokenA.chain, tokenA.denom), + getDenomHash('osmosis', tokenB.chain, tokenB.denom), + ]); + t.log(pool); + + t.is(nonNativeRoute[0].token_out_denom, `ibc/${chainBDenomHash}`); + + const myPool = pool.pool as Pool; + t.truthy( + myPool.poolAssets.find( + ({ token }) => token.denom === `ibc/${chainADenomHash}`, + ), + ); + t.truthy( + myPool.poolAssets.find( + ({ token }) => token.denom === `ibc/${chainBDenomHash}`, + ), + ); }); test.serial('BLD for OSMO, receiver on Agoric', async t => { @@ -189,6 +235,7 @@ test.serial('BLD for OSMO, receiver on Agoric', async t => { ); }); +// FLAKE: fails when run in isolation (.only) test.serial('OSMO for BLD, receiver on Agoric', async t => { const { wallets, From ad270566056a496aba60cdebea2e78cdf7c8b492 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Tue, 20 May 2025 15:02:08 +0300 Subject: [PATCH 14/24] chore(orchestration): handle pfm of transfer with memo chore: handle pfm of transfer with memo chore: recover pfm test --- .../xcs-swap-anything/swap-anything.test.ts | 80 +++++++++++++++++++ .../src/exos/local-orchestration-account.js | 9 ++- .../local-orchestration-account-kit.test.ts | 22 +++++ 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 8a9071d6897..9420ab42935 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -666,6 +666,86 @@ test.serial('bad swapOut receiver, via addressHooks', async t => { ); }); +test.serial('native ATOM for Osmo using PFM, receiver on Agoric', async t => { + const { wallets, vstorageClient, retryUntilCondition, useChain, getContractsInfo, getDenomHash } = t.context; + + const { client: cosmosHubClient, address: cosmosHubAddr } = await createFundedWalletAndClient( + t.log, + 'cosmoshub', + useChain, + ); + + const cosmosBalanceResult = await retryUntilCondition( + () => cosmosHubClient.getAllBalances(cosmosHubAddr), + coins => !!coins?.length, + `Faucet balances found for ${cosmosHubAddr}`, + ); + t.log(cosmosHubAddr, cosmosBalanceResult); + t.pass() + + const apiUrl = await useChain('agoric').getRestEndpoint(); + const queryClient = makeQueryClient(apiUrl); + + const { balances: balancesBefore } = await queryClient.queryBalances( + wallets.agoricReceiver, + ); + + const { + sharedLocalAccount: { value: baseAddress }, + } = await vstorageClient.queryData('published.swap-anything'); + t.log(baseAddress); + + const { crosschain_swaps } = getContractsInfo(); + + const orcContractReceiverAddress = encodeAddressHook(baseAddress, { + destAddr: crosschain_swaps.address, + receiverAddr: wallets.agoricReceiver, + outDenom: 'uosmo', + }); + + const transferArgs = makeIBCTransferMsg( + { denom: `uatom`, value: 125n }, + { address: orcContractReceiverAddress, chainName: 'agoric' }, + { address: cosmosHubAddr, chainName: 'cosmoshub' }, + Date.now(), + useChain, + ); + console.log('Transfer Args:', transferArgs); + // TODO #9200 `sendIbcTokens` does not support `memo` + // @ts-expect-error spread argument for concise code + const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + if (txRes && txRes.code !== 0) { + console.error(txRes); + throw Error(`failed to ibc transfer funds to ${orcContractReceiverAddress}`); + } + const { events: _events, ...txRest } = txRes; + console.log(txRest); + t.is(txRes.code, 0, `Transaction succeeded`); + t.log(`Funds transferred to ${orcContractReceiverAddress}`); + + const { balances: agoricReceiverBalances } = await retryUntilCondition( + () => queryClient.queryBalances(wallets.agoricReceiver), + ({ balances }) => { + const balancesBeforeAmount = BigInt(balancesBefore[0]?.amount || 0); + const currentBalanceAmount = BigInt(balances[0]?.amount || 0); + return currentBalanceAmount > balancesBeforeAmount; + }, + 'Osmosis swap output reflected on Agoric receiver balance', + ); + t.log(agoricReceiverBalances); + + const osmoOnAgoricHash = await getDenomHash('agoric', 'osmosis', 'uosmo'); + + t.log('Expected denom hash:', osmoOnAgoricHash); + + t.regex(agoricReceiverBalances[0]?.denom, /^ibc/); + t.is( + agoricReceiverBalances[0]?.denom.split('ibc/')[1], + osmoOnAgoricHash, + 'got expected ibc denom hash', + ); +}); + test.after(async t => { const { deleteTestKeys } = t.context; deleteTestKeys(accounts); diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js index f8e555f7d03..d7797945e0d 100644 --- a/packages/orchestration/src/exos/local-orchestration-account.js +++ b/packages/orchestration/src/exos/local-orchestration-account.js @@ -379,8 +379,13 @@ export const prepareLocalOrchestrationAccountKit = ( memo = opts.memo; } if (forwardInfo) { - // forward memo takes precedence - memo = JSON.stringify(forwardInfo); + // pass opts.memo as forward.next, if present + memo = JSON.stringify({ + forward: { + ...forwardInfo.forward, + next: memo, + }, + }); } const transferMsg = typedJson( '/ibc.applications.transfer.v1.MsgTransfer', diff --git a/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts b/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts index 95e7db01564..d8de72e730c 100644 --- a/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts +++ b/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts @@ -306,6 +306,28 @@ test('transfer', async t => { await t.throwsAsync(pfmTimeoutTransferP, { message: `ICS20-1 transfer error "${ackErrorMsg}"`, }); + + t.log('Transfer handles multi-hop transfers with memo for the destination'); + await t.notThrowsAsync( + doTransfer(aDenomAmount, dydxDest, { + memo: JSON.stringify({ + wasm: { contract: 'osmosis4829219', msg: { osmosis_swap: 'XCS' } }, + }), + }), + ); + t.is(latestTxMsg().receiver, PFM_RECEIVER, 'defaults to "pfm" receiver'); + t.deepEqual(JSON.parse(latestTxMsg().memo), { + forward: { + receiver: 'dydx1test', + port: 'transfer', + channel: 'channel-33', + retries: 3, + timeout: '10m', + next: JSON.stringify({ + wasm: { contract: 'osmosis4829219', msg: { osmosis_swap: 'XCS' } }, + }), + }, + }); }); test('monitor transfers', async t => { From 8191a9431fde776201c0e901a1b4b051c4ebc2d4 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 26 May 2025 11:11:22 +0100 Subject: [PATCH 15/24] fix: resolve conflicts with dependencies chore: typing and linting minor changes --- multichain-testing/package.json | 4 +- .../test/xcs-swap-anything/helpers.ts | 3 +- .../xcs-swap-anything/swap-anything.test.ts | 22 ++++--- multichain-testing/yarn.lock | 64 +++++++++---------- 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/multichain-testing/package.json b/multichain-testing/package.json index 22b2b2b9242..1732164c717 100644 --- a/multichain-testing/package.json +++ b/multichain-testing/package.json @@ -97,8 +97,8 @@ "@agoric/xsnap-lockdown": "portal:../packages/xsnap-lockdown", "@agoric/zoe": "portal:../packages/zoe", "@agoric/zone": "portal:../packages/zone", - "@cosmjs/proto-signing@npm:0.32.3": "npm:@cosmjs/proto-signing@0.33.0", - "@cosmjs/stargate@npm:0.32.3": "npm:@cosmjs/stargate@0.33.0" + "@cosmjs/proto-signing": "0.33.1", + "@cosmjs/stargate": "0.33.1" }, "license": "Apache-2.0" } diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index 055cf66ea1d..8a5824bbe7b 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -267,7 +267,7 @@ export const osmosisSwapTools = async t => { }; const downloadXcsContracts = async ( - xcsContracts, + xcsContracts: Contracts, branch: string = osmosisBranch, scriptPath: string = scriptLocalPath, artifactsPath: string = xcsArtifactsPath, @@ -691,7 +691,6 @@ export const osmosisSwapTools = async t => { swaprouterAddress, queryMsg, ); - console.log('LOG: ', pool_route); return pool_route; }; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 9420ab42935..ca921a387f9 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -667,13 +667,17 @@ test.serial('bad swapOut receiver, via addressHooks', async t => { }); test.serial('native ATOM for Osmo using PFM, receiver on Agoric', async t => { - const { wallets, vstorageClient, retryUntilCondition, useChain, getContractsInfo, getDenomHash } = t.context; - - const { client: cosmosHubClient, address: cosmosHubAddr } = await createFundedWalletAndClient( - t.log, - 'cosmoshub', + const { + wallets, + vstorageClient, + retryUntilCondition, useChain, - ); + getContractsInfo, + getDenomHash, + } = t.context; + + const { client: cosmosHubClient, address: cosmosHubAddr } = + await createFundedWalletAndClient(t.log, 'cosmoshub', useChain); const cosmosBalanceResult = await retryUntilCondition( () => cosmosHubClient.getAllBalances(cosmosHubAddr), @@ -681,7 +685,7 @@ test.serial('native ATOM for Osmo using PFM, receiver on Agoric', async t => { `Faucet balances found for ${cosmosHubAddr}`, ); t.log(cosmosHubAddr, cosmosBalanceResult); - t.pass() + t.pass(); const apiUrl = await useChain('agoric').getRestEndpoint(); const queryClient = makeQueryClient(apiUrl); @@ -716,7 +720,9 @@ test.serial('native ATOM for Osmo using PFM, receiver on Agoric', async t => { const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); - throw Error(`failed to ibc transfer funds to ${orcContractReceiverAddress}`); + throw Error( + `failed to ibc transfer funds to ${orcContractReceiverAddress}`, + ); } const { events: _events, ...txRest } = txRes; console.log(txRest); diff --git a/multichain-testing/yarn.lock b/multichain-testing/yarn.lock index 52f7f45c24d..834debe4054 100644 --- a/multichain-testing/yarn.lock +++ b/multichain-testing/yarn.lock @@ -642,21 +642,21 @@ __metadata: languageName: node linkType: hard -"@chain-registry/types@npm:^0.50.136": - version: 0.50.136 - resolution: "@chain-registry/types@npm:0.50.136" - checksum: 10c0/bd5406cdba8b057c6055a538ba50bdd95c8291fef8abbfaf75673f826718064e22e8d2a74c462070bd162dfc5c80a9c7ff94a0f555bddee61cee3cdf9d27e135 +"@chain-registry/types@npm:^0.50.138": + version: 0.50.138 + resolution: "@chain-registry/types@npm:0.50.138" + checksum: 10c0/c17ffcc9fb8d464192fe9906312af3b39f08a11e826e56896e443da839afe438d3e983f26143dc2035ee40560ce13319f9b502cf1b09f02bbf294606777b3e15 languageName: node linkType: hard "@chain-registry/utils@npm:^1.17.0": - version: 1.51.136 - resolution: "@chain-registry/utils@npm:1.51.136" + version: 1.51.138 + resolution: "@chain-registry/utils@npm:1.51.138" dependencies: - "@chain-registry/types": "npm:^0.50.136" + "@chain-registry/types": "npm:^0.50.138" bignumber.js: "npm:9.1.2" sha.js: "npm:^2.4.11" - checksum: 10c0/c28e5ab6ce893108600cab5d7a758c40cf9cbfe68359d6eb93f3ebf201336c5eca13746df8700952021e44547f88679964e98ea664ee6330939c14eb78dafd85 + checksum: 10c0/e0d89ba0fbf6e86e394674dd77e60b10363bc3b4f0ba75a855c50c999416d7dfeb3dc1a072b67ad7cbb31e9323ab7f059b4a1047add7aaf61be187ae6893705b languageName: node linkType: hard @@ -684,7 +684,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/amino@npm:^0.33.0, @cosmjs/amino@npm:^0.33.1": +"@cosmjs/amino@npm:^0.33.1": version: 0.33.1 resolution: "@cosmjs/amino@npm:0.33.1" dependencies: @@ -815,7 +815,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/math@npm:^0.33.0, @cosmjs/math@npm:^0.33.1": +"@cosmjs/math@npm:^0.33.1": version: 0.33.1 resolution: "@cosmjs/math@npm:0.33.1" dependencies: @@ -824,17 +824,17 @@ __metadata: languageName: node linkType: hard -"@cosmjs/proto-signing@npm:0.33.0": - version: 0.33.0 - resolution: "@cosmjs/proto-signing@npm:0.33.0" +"@cosmjs/proto-signing@npm:0.33.1": + version: 0.33.1 + resolution: "@cosmjs/proto-signing@npm:0.33.1" dependencies: - "@cosmjs/amino": "npm:^0.33.0" - "@cosmjs/crypto": "npm:^0.33.0" - "@cosmjs/encoding": "npm:^0.33.0" - "@cosmjs/math": "npm:^0.33.0" - "@cosmjs/utils": "npm:^0.33.0" + "@cosmjs/amino": "npm:^0.33.1" + "@cosmjs/crypto": "npm:^0.33.1" + "@cosmjs/encoding": "npm:^0.33.1" + "@cosmjs/math": "npm:^0.33.1" + "@cosmjs/utils": "npm:^0.33.1" cosmjs-types: "npm:^0.9.0" - checksum: 10c0/7f9ebc676249db180191bd3ffc84481341482c7c6d03c82a6cbd0350bdd17862e2058882044ec68e8d01aa11c600c79c9c11ef5dbdc0bc6382c708cf1d1a12b8 + checksum: 10c0/d8516fccad54264e9893623fdf7d4a04927fce1ac5a0c799eab422a7be000e7f055e5ded44172a7cb97ad991bffba4f9fefa786074070bc4151ee1faacd7070d languageName: node linkType: hard @@ -862,7 +862,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/stargate@npm:^0.33.0": +"@cosmjs/stargate@npm:0.33.1": version: 0.33.1 resolution: "@cosmjs/stargate@npm:0.33.1" dependencies: @@ -939,7 +939,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/utils@npm:^0.33.0, @cosmjs/utils@npm:^0.33.1": +"@cosmjs/utils@npm:^0.33.1": version: 0.33.1 resolution: "@cosmjs/utils@npm:0.33.1" checksum: 10c0/fe675de1caa1028ece747ea6a96a8a4f5475084982adf5f200abfdf0c2bb5173668ea6437c03cd03bf5639c8540363ac934cf4868686f6577f2640c9d468b8d1 @@ -1481,9 +1481,9 @@ __metadata: linkType: hard "@noble/hashes@npm:^1, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.5.0": - version: 1.6.1 - resolution: "@noble/hashes@npm:1.6.1" - checksum: 10c0/27643cd8b551bc933b57cc29aa8c8763d586552fc4c3e06ecf7897f55be3463c0c9dff7f6ebacd88e5ce6d0cdb5415ca4874d0cf4359b5ea4a85be21ada03aab + version: 1.8.0 + resolution: "@noble/hashes@npm:1.8.0" + checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77 languageName: node linkType: hard @@ -1624,8 +1624,8 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:^22.0.0": - version: 22.7.8 - resolution: "@types/node@npm:22.7.8" + version: 22.15.21 + resolution: "@types/node@npm:22.15.21" dependencies: undici-types: "npm:~6.21.0" checksum: 10c0/f092bbccda2131c2b2c8f720338080aa0ef1d928f5f1062c03954a4f7dafa7ee3ed29bc3e51bd4e2584473b3d943c637a2b39ad7174898970818270187cf10c1 @@ -4730,14 +4730,14 @@ __metadata: linkType: hard "tar-fs@npm:^2.0.0": - version: 2.1.2 - resolution: "tar-fs@npm:2.1.2" + version: 2.1.3 + resolution: "tar-fs@npm:2.1.3" dependencies: chownr: "npm:^1.1.1" mkdirp-classic: "npm:^0.5.2" pump: "npm:^3.0.0" tar-stream: "npm:^2.1.4" - checksum: 10c0/9c704bd4a53be7565caf34ed001d1428532457fe3546d8fc1233f0f0882c3d2403f8602e8046e0b0adeb31fe95336572a69fb28851a391523126b697537670fc + checksum: 10c0/472ee0c3c862605165163113ab6924f411c07506a1fb24c51a1a80085f0d4d381d86d2fd6b189236c8d932d1cd97b69cce35016767ceb658a35f7584fe77f305 languageName: node linkType: hard @@ -4783,12 +4783,12 @@ __metadata: linkType: hard "tinyglobby@npm:^0.2.12": - version: 0.2.13 - resolution: "tinyglobby@npm:0.2.13" + version: 0.2.14 + resolution: "tinyglobby@npm:0.2.14" dependencies: fdir: "npm:^6.4.4" picomatch: "npm:^4.0.2" - checksum: 10c0/ef07dfaa7b26936601d3f6d999f7928a4d1c6234c5eb36896bb88681947c0d459b7ebe797022400e555fe4b894db06e922b95d0ce60cb05fd827a0a66326b18c + checksum: 10c0/f789ed6c924287a9b7d3612056ed0cda67306cd2c80c249fd280cf1504742b12583a2089b61f4abbd24605f390809017240e250241f09938054c9b363e51c0a6 languageName: node linkType: hard From 54e569accec3581f1141555b7f736856e53fc727 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Tue, 27 May 2025 12:26:32 +0300 Subject: [PATCH 16/24] fix: increase staking tests timeout and move xcs setup to its own test fix(orchestration): resolve timeout issue chore: experiment with timeouts chore: timeout experiment chore: clear unnecessary comments --- multichain-testing/ava.staking.config.js | 1 + .../test/xcs-swap-anything/swap-anything.test.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/multichain-testing/ava.staking.config.js b/multichain-testing/ava.staking.config.js index 8fa1f1dc1aa..98e13eca9f6 100644 --- a/multichain-testing/ava.staking.config.js +++ b/multichain-testing/ava.staking.config.js @@ -3,4 +3,5 @@ import mainConfig from './ava.config.js'; export default { ...mainConfig, files: ['test/staking/**/*.test.ts'], + timeout: '300s', }; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index ca921a387f9..844eb669eee 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -68,13 +68,18 @@ test.before(async t => { t.context = { ...common, wallets }; const swapTools = await osmosisSwapTools(t); - const { setupXcsContracts, setupXcsState, setupPoolsInBatch } = swapTools; + + t.context = { ...t.context, ...swapTools }; +}); + +test.serial('setup XCS', async t => { + const { setupXcsContracts, setupXcsState, setupPoolsInBatch } = t.context; await setupXcsContracts(); await setupXcsState(prefixList, channelList); await setupPoolsInBatch(osmosisPoolList); - t.context = { ...t.context, ...swapTools }; + t.pass(); }); test.serial('test osmosis xcs state', async t => { From 75782a5bc3ac120213aac91fef345ab41f67064f Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 27 May 2025 15:47:10 +0100 Subject: [PATCH 17/24] chore: removed outdated instructions and update shell script --- multichain-testing/Makefile | 10 ------- multichain-testing/README.md | 7 ----- .../test/xcs-swap-anything/README.md | 2 +- .../download-wasm-artifacts.sh | 27 ++++++++++--------- 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/multichain-testing/Makefile b/multichain-testing/Makefile index c19d2e66941..8c2e3b866d1 100644 --- a/multichain-testing/Makefile +++ b/multichain-testing/Makefile @@ -93,16 +93,6 @@ provision-smart-wallet: tail-slog: kubectl exec -i agoriclocal-genesis-0 -c validator -- tail -f slog.slog - -############################################################################### -### Osmosis Setup ### -############################################################################### -osmosis-xcs-setup: - $(CURDIR)/scripts/setup-xcs.sh - -create-osmosis-pool: - $(CURDIR)/scripts/create-osmosis-pool.sh - ############################################################################### ### Start All ### ############################################################################### diff --git a/multichain-testing/README.md b/multichain-testing/README.md index 0cda4a349ca..572865afe9c 100644 --- a/multichain-testing/README.md +++ b/multichain-testing/README.md @@ -136,13 +136,6 @@ make provision-smart-wallet ADDR=$ADDR kubectl exec -i noblelocal-genesis-0 -c validator -- nobled query interchain-accounts host params | jq ``` -## Optional Features - -```sh -# create and fund a liquidity pool on Osmosis -make create-osmosis-pool -``` - ## Chain Registry These only work if you've done `make port-forward`. diff --git a/multichain-testing/test/xcs-swap-anything/README.md b/multichain-testing/test/xcs-swap-anything/README.md index 3af79181147..0bd26febfa6 100644 --- a/multichain-testing/test/xcs-swap-anything/README.md +++ b/multichain-testing/test/xcs-swap-anything/README.md @@ -6,7 +6,7 @@ make osmosis-xcs-setup make create-osmosis-pool ## Configure the osmosis registries -cd cd agoric-sdk/multichain-testing/test/xcs-swap-anything +cd agoric-sdk/multichain-testing/test/xcs-swap-anything make tx-chain-channel-links make tx-bec32-prefixes ``` diff --git a/multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh b/multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh index f6c45e83c64..0b26fcb2d67 100755 --- a/multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh +++ b/multichain-testing/test/xcs-swap-anything/download-wasm-artifacts.sh @@ -1,26 +1,27 @@ #!/bin/bash - # Usage: ./download_specific_files.sh ... -OWNER="$1" -REPO="$2" -BRANCH="$3" -FOLDER="$4" -DEST="$5" +set -euo pipefail + +owner="$1" +repo="$2" +branch="$3" +folder="$4" +dest="$5" shift 5 -FILES_TO_DOWNLOAD=("$@") +files_to_download=("$@") -API_URL="https://api.github.com/repos/$OWNER/$REPO/contents/$FOLDER?ref=$BRANCH" -mkdir -p "$DEST" +api_url="https://api.github.com/repos/$owner/$repo/contents/$folder?ref=$branch" +mkdir -p "$dest" -curl -s "$API_URL" | jq -r '.[] | select(.type=="file") | .name + " " + .download_url' \ +curl -s "$api_url" | jq -r '.[] | select(.type=="file") | .name + " " + .download_url' \ | while read -r filename url; do - for wanted in "${FILES_TO_DOWNLOAD[@]}"; do + for wanted in "${files_to_download[@]}"; do if [[ "$filename" == "$wanted" ]]; then echo "Downloading $filename..." - curl -sL "$url" -o "$DEST/$filename" + curl -sL "$url" -o "$dest/$filename" fi done done -echo "✅ Selected files downloaded to $DEST" +echo "✅ Selected files downloaded to $dest" From 103c6aaed798f4c4935f837e7f37c0e4009d6f90 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 27 May 2025 14:39:37 -0500 Subject: [PATCH 18/24] chore: avoid deprecated .sendIbcTokens(...) method - use Parameters<...> to avoid spread type error --- .../test/xcs-swap-anything/helpers.ts | 4 +--- .../xcs-swap-anything/swap-anything.test.ts | 12 +++------- multichain-testing/tools/ibc-transfer.ts | 24 +++++++------------ 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index 8a5824bbe7b..240582acdbf 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -175,9 +175,7 @@ export const osmosisSwapTools = async t => { useChain, ); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await issuingClient.sendIbcTokens(...transferArgs); + const txRes = await issuingClient.signAndBroadcast(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); throw Error(`failed to ibc transfer funds to ${destinationAddress}`); diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 844eb669eee..1c87ba61e62 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -539,9 +539,7 @@ test.serial('address hook - BLD for OSMO, receiver on Agoric', async t => { useChain, ); console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + const txRes = await cosmosHubClient.signAndBroadcast(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); throw Error(`failed to ibc transfer funds to ibc/${bldDenomOnHub}`); @@ -625,9 +623,7 @@ test.serial('bad swapOut receiver, via addressHooks', async t => { useChain, ); console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + const txRes = await cosmosHubClient.signAndBroadcast(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); throw Error(`failed to ibc transfer funds to ibc/${bldDenomOnHub}`); @@ -720,9 +716,7 @@ test.serial('native ATOM for Osmo using PFM, receiver on Agoric', async t => { useChain, ); console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await cosmosHubClient.sendIbcTokens(...transferArgs); + const txRes = await cosmosHubClient.signAndBroadcast(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); throw Error( diff --git a/multichain-testing/tools/ibc-transfer.ts b/multichain-testing/tools/ibc-transfer.ts index 85df9137be4..f90da7f4c5e 100644 --- a/multichain-testing/tools/ibc-transfer.ts +++ b/multichain-testing/tools/ibc-transfer.ts @@ -1,6 +1,6 @@ import type { ExecutionContext } from 'ava'; import type { StdFee } from '@cosmjs/amino'; -import { coins } from '@cosmjs/proto-signing'; +import { coins, type EncodeObject } from '@cosmjs/proto-signing'; import { SigningStargateClient } from '@cosmjs/stargate'; import type { CosmosChainInfo, @@ -64,7 +64,7 @@ export const makeIBCTransferMsg = ( currentTime: number, useChain: MultichainRegistry['useChain'], opts: IBCMsgTransferOptions = {}, -) => { +): Parameters => { const { timeoutHeight, timeoutTimestamp, memo = '' } = opts; const destChainInfo = (chainInfo as Record)[ @@ -110,17 +110,11 @@ export const makeIBCTransferMsg = ( gasPrice: high_gas_price, }); - return [ - msgTransfer.sender, - msgTransfer.receiver, - msgTransfer.token, - msgTransfer.sourcePort, - msgTransfer.sourceChannel, - msgTransfer.timeoutHeight, - Number(msgTransfer.timeoutTimestamp), - fee, - msgTransfer.memo, - ]; + const message0 = { + typeUrl: MsgTransfer.typeUrl, + value: msgTransfer, + } as EncodeObject; + return [sender.address, [message0], fee]; }; export const createFundedWalletAndClient = async ( @@ -180,9 +174,7 @@ export const makeFundAndTransfer = ( useChain, ); console.log('Transfer Args:', transferArgs); - // TODO #9200 `sendIbcTokens` does not support `memo` - // @ts-expect-error spread argument for concise code - const txRes = await client.sendIbcTokens(...transferArgs); + const txRes = await client.signAndBroadcast(...transferArgs); if (txRes && txRes.code !== 0) { console.error(txRes); throw Error(`failed to ibc transfer funds to ${chainName}`); From e487bb1d7487aa1964323a6bf95cb83e8641e847 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 15:58:55 +0100 Subject: [PATCH 19/24] chore: replace execa and add inline encodeObjects --- .../test/xcs-swap-anything/helpers.ts | 84 +++++-------------- 1 file changed, 23 insertions(+), 61 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index 8a5824bbe7b..f860cc32d01 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -11,7 +11,7 @@ import type { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin.js'; import type { SigningStargateClient } from '@cosmjs/stargate'; import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'; import { toUtf8 } from '@cosmjs/encoding'; -import { execa } from 'execa'; +import { $ } from 'execa'; import { writeFileSync } from 'fs'; import fs from 'fs/promises'; import path from 'path'; @@ -233,16 +233,9 @@ export const osmosisSwapTools = async t => { funds: [], }); - const encodeObjects: Array = [ - { - typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', - value: message, - }, - ]; - const response = await osmosisClient.signAndBroadcast( osmosisAddress, - encodeObjects, + [{ typeUrl: MsgExecuteContract.typeUrl, value: message }], fee, ); console.log('invokeOsmosisContract DeliverTxResponse: ', response); @@ -281,15 +274,7 @@ export const osmosisSwapTools = async t => { } try { - await execa('bash', [ - scriptPath, - 'osmosis-labs', - 'osmosis', - branch, - 'tests/ibc-hooks/bytecode', - artifactsPath, - ...wasmFiles, - ]); + await $`${scriptPath} osmosis-labs osmosis ${branch} tests/ibc-hooks/bytecode ${artifactsPath} ${wasmFiles}`; } catch (error) { throw Error(`Failed to download XCS artifacts: ${error}`); } @@ -322,18 +307,14 @@ export const osmosisSwapTools = async t => { wasmByteCode, }); - const storeEncodeObjects: Array< - import('@cosmjs/proto-signing').EncodeObject - > = [ - { - typeUrl: MsgStoreCode.typeUrl, - value: storeMessage, - }, - ]; - const storeResult = await osmosisClient.signAndBroadcast( osmosisAddress, - storeEncodeObjects, + [ + { + typeUrl: MsgStoreCode.typeUrl, + value: storeMessage, + }, + ], fee, ); @@ -353,18 +334,14 @@ export const osmosisSwapTools = async t => { msg: toUtf8(JSON.stringify(instantiateArgs)), }); - const instantiateEncodeObjects: Array< - import('@cosmjs/proto-signing').EncodeObject - > = [ - { - typeUrl: MsgInstantiateContract.typeUrl, - value: instantiateMessage, - }, - ]; - const instantiateResult = await osmosisClient.signAndBroadcast( osmosisAddress, - instantiateEncodeObjects, + [ + { + typeUrl: MsgInstantiateContract.typeUrl, + value: instantiateMessage, + }, + ], fee, ); @@ -391,11 +368,7 @@ export const osmosisSwapTools = async t => { JSON.stringify(sanitizedContracts), ); - await execa('kubectl', [ - 'cp', - './test/xcs-swap-anything/xcs-contracts-info.json', - 'osmosislocal-genesis-0:/', - ]); + await $`kubectl cp ./test/xcs-swap-anything/xcs-contracts-info.json osmosislocal-genesis-0:/`; } catch (error) { throw Error(`Failed to store XCS info: ${error}`); } @@ -525,18 +498,15 @@ export const osmosisSwapTools = async t => { ], futurePoolGovernor: '', }); - /** @type {Array} */ - const encodeObjects = [ - { - typeUrl: - '/osmosis.gamm.poolmodels.balancer.v1beta1.MsgCreateBalancerPool', - value: message, - }, - ]; const result = await osmosisClient.signAndBroadcast( osmosisAddress, - encodeObjects, + [ + { + typeUrl: MsgCreateBalancerPool.typeUrl, + value: message, + }, + ], fee, ); @@ -573,15 +543,7 @@ export const osmosisSwapTools = async t => { }; const queryContractsInfo = async () => { - const osmosisCLI = - 'kubectl exec -i osmosislocal-genesis-0 -c validator -- /bin/bash -c'; - - const info = `${osmosisCLI} "jq . /xcs-contracts-info.json"`; - - const { stdout } = await execa(info, { - shell: true, - }); - + const { stdout } = await $`kubectl exec -i osmosislocal-genesis-0 -c validator -- cat /xcs-contracts-info.json`; return JSON.parse(stdout); }; From 9bdf4e3ca6d289d459fa0b7d514776e6dfe20231 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 16:03:28 +0100 Subject: [PATCH 20/24] chore: improve error handling and bigint serialization --- .../test/xcs-swap-anything/helpers.ts | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index f860cc32d01..cd3aea7b48f 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -118,6 +118,8 @@ export const osmosisSwapTools = async t => { }, }; + const bigintReplacer = (_, v) => (typeof v === 'bigint' ? Number(v) : v); + const fundRemote = async ( issuingChain: string, issuingDenom: string = 'ubld', @@ -276,7 +278,7 @@ export const osmosisSwapTools = async t => { try { await $`${scriptPath} osmosis-labs osmosis ${branch} tests/ibc-hooks/bytecode ${artifactsPath} ${wasmFiles}`; } catch (error) { - throw Error(`Failed to download XCS artifacts: ${error}`); + throw Error(`Failed to download XCS artifacts`, { cause: error }); } }; @@ -322,9 +324,9 @@ export const osmosisSwapTools = async t => { throw Error(`Failed to store ${contractLabel} contract`); } - const codeId = MsgStoreCodeResponse.decode( + const { codeId } = MsgStoreCodeResponse.decode( storeResult.msgResponses[0].value, - ).codeId; + ); const instantiateMessage = MsgInstantiateContract.fromPartial({ sender: osmosisAddress, @@ -349,9 +351,9 @@ export const osmosisSwapTools = async t => { throw Error(`Failed to instantiate ${contractLabel} contract`); } - const address = MsgInstantiateContractResponse.decode( + const { address } = MsgInstantiateContractResponse.decode( instantiateResult.msgResponses[0].value, - ).address; + ); return { codeId, address }; }; @@ -359,9 +361,7 @@ export const osmosisSwapTools = async t => { const persistXcsInfo = async () => { try { const sanitizedContracts = JSON.parse( - JSON.stringify(xcsContracts, (_, v) => - typeof v === 'bigint' ? Number(v) : v, - ), + JSON.stringify(xcsContracts, bigintReplacer), ); writeFileSync( './test/xcs-swap-anything/xcs-contracts-info.json', @@ -370,7 +370,7 @@ export const osmosisSwapTools = async t => { await $`kubectl cp ./test/xcs-swap-anything/xcs-contracts-info.json osmosislocal-genesis-0:/`; } catch (error) { - throw Error(`Failed to store XCS info: ${error}`); + throw Error(`Failed to store XCS info`, { cause: error }); } }; @@ -378,27 +378,26 @@ export const osmosisSwapTools = async t => { let contractInfo; try { contractInfo = await queryContractsInfo(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (error) { + + } catch { return false; } const sanitizedContracts = JSON.parse( - JSON.stringify(xcsContracts, (_, v) => - typeof v === 'bigint' ? Number(v) : v, - ), + JSON.stringify(xcsContracts, bigintReplacer), ); - if (JSON.stringify(contractInfo) != JSON.stringify(sanitizedContracts)) { + if (JSON.stringify(contractInfo) !== JSON.stringify(sanitizedContracts)) { xcsContracts = contractInfo; } - return true; }; const setupXcsChannelLink = async ( primaryChain: string, counterPartyChain: string, ) => { - const chainId = useChain(counterPartyChain).chain.chain_id; + const { + chain: { chain_id }, + } = useChain(counterPartyChain); const registryAddress = xcsContracts.crosschain_registry.address; if (!registryAddress) { throw new Error('crosschain_registry contract address not found'); @@ -406,7 +405,7 @@ export const osmosisSwapTools = async t => { const { transferChannel: { channelId, counterPartyChannelId }, - } = starshipChainInfo[primaryChain].connections[chainId]; + } = starshipChainInfo[primaryChain].connections[chain_id]; const txMsg = { modify_chain_channel_links: { @@ -460,8 +459,7 @@ export const osmosisSwapTools = async t => { ); } return true; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (error) { + } catch { return false; } }; @@ -510,9 +508,9 @@ export const osmosisSwapTools = async t => { fee, ); - const poolId = MsgCreateBalancerPoolResponse.decode( + const { poolId } = MsgCreateBalancerPoolResponse.decode( result.msgResponses[0].value, - ).poolId; + ); return { poolId, inDenom, outDenom }; }; @@ -558,11 +556,13 @@ export const osmosisSwapTools = async t => { issuingChain: string, issuingDenom: string, ) => { - const chainId = useChain(issuingChain).chain.chain_id; + const { + chain: { chain_id }, + } = useChain(issuingChain); const { transferChannel: { channelId }, - } = starshipChainInfo[currentChain].connections[chainId]; + } = starshipChainInfo[currentChain].connections[chain_id]; const apiUrl = await useChain(currentChain).getRestEndpoint(); const queryClient = makeQueryClient(apiUrl); @@ -572,6 +572,10 @@ export const osmosisSwapTools = async t => { issuingDenom, ); + if (!hash) { + throw Error(`Hash not found for ${issuingDenom} on ${currentChain}`); + } + return hash; }; From cf37ab29da835de9d57537314def04088878ab92 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 16:08:49 +0100 Subject: [PATCH 21/24] chore: improve robustness of setupXcsContracts --- .../test/xcs-swap-anything/helpers.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index cd3aea7b48f..bce94206863 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -268,11 +268,8 @@ export const osmosisSwapTools = async t => { artifactsPath: string = xcsArtifactsPath, ) => { const wasmFiles: string[] = []; - for (const contract in xcsContracts) { - if (Object.prototype.hasOwnProperty.call(xcsContracts, contract)) { - const { label } = xcsContracts[contract]; - wasmFiles.push(`${label}.wasm`); - } + for (const [label, _contractInfo] of Object.entries(xcsContracts)) { + wasmFiles.push(`${label}.wasm`); } try { @@ -375,13 +372,16 @@ export const osmosisSwapTools = async t => { }; const areContractsInstantiated = async () => { - let contractInfo; try { - contractInfo = await queryContractsInfo(); - + await queryContractsInfo(); + return true; } catch { return false; } + }; + + const updateLocalXcsContracts = async () => { + const contractInfo = await queryContractsInfo(); const sanitizedContracts = JSON.parse( JSON.stringify(xcsContracts, bigintReplacer), @@ -699,6 +699,8 @@ export const osmosisSwapTools = async t => { await persistXcsInfo(); } + await updateLocalXcsContracts(); + console.log('XCS contracts instantiation completed!'); return xcsContracts; From 71749c1f918c2a9fba4c5b2cce1c9b81dfe15ea8 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 16:17:11 +0100 Subject: [PATCH 22/24] chore: rename osmosisSwapTools and fix log typos --- .../test/xcs-swap-anything/helpers.ts | 19 +++++++++++-------- .../xcs-swap-anything/swap-anything.test.ts | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/multichain-testing/test/xcs-swap-anything/helpers.ts b/multichain-testing/test/xcs-swap-anything/helpers.ts index bce94206863..eb2c69cb433 100644 --- a/multichain-testing/test/xcs-swap-anything/helpers.ts +++ b/multichain-testing/test/xcs-swap-anything/helpers.ts @@ -23,7 +23,9 @@ import starshipChainInfo from '../../starship-chain-info.js'; import { makeQueryClient } from '../../tools/query.js'; import type { SetupContextWithWallets } from '../support.js'; -export type SetupOsmosisContext = Awaited>; +export type SetupOsmosisContext = Awaited< + ReturnType +>; export type SetupOsmosisContextWithCommon = SetupOsmosisContext & SetupContextWithWallets; @@ -63,7 +65,7 @@ type Contracts = { crosschain_swaps: ContractInfoBase; }; -export const osmosisSwapTools = async t => { +export const makeOsmosisSwapTools = async t => { const { useChain, retryUntilCondition } = t.context; const osmosisBranch = 'main'; @@ -541,7 +543,8 @@ export const osmosisSwapTools = async t => { }; const queryContractsInfo = async () => { - const { stdout } = await $`kubectl exec -i osmosislocal-genesis-0 -c validator -- cat /xcs-contracts-info.json`; + const { stdout } = + await $`kubectl exec -i osmosislocal-genesis-0 -c validator -- cat /xcs-contracts-info.json`; return JSON.parse(stdout); }; @@ -672,7 +675,7 @@ export const osmosisSwapTools = async t => { }; const setupXcsContracts = async (forceInstall = false) => { - console.log('Seeting XCS contracts ...'); + console.log('Setting XCS contracts ...'); if (!(await areContractsInstantiated()) || forceInstall) { console.log(`XCS contracts being downloaded ...`); await downloadXcsContracts(xcsContracts); @@ -710,22 +713,22 @@ export const osmosisSwapTools = async t => { prefixList: Prefix[], channelList: Channel[], ) => { - console.log('Seeting XCS state ...'); + console.log('Setting XCS state ...'); if (!(await isXcsStateSet(channelList))) { for (const { chain, prefix } of prefixList) { - console.log(`Seeting Prefix for ${chain} ...`); + console.log(`Setting Prefix for ${chain} ...`); await setupXcsPrefix(chain, prefix); } for (const { primary, counterParty } of channelList) { console.log( - `Seeting Channel Link for ${primary} and ${counterParty} ...`, + `Setting Channel Link for ${primary} and ${counterParty} ...`, ); await setupXcsChannelLink(primary, counterParty); } } else { - console.log('XCS contracts alrady set'); + console.log('XCS contracts already set'); } }; diff --git a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts index 844eb669eee..4f237c17201 100644 --- a/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts +++ b/multichain-testing/test/xcs-swap-anything/swap-anything.test.ts @@ -11,7 +11,7 @@ import { } from '../../tools/ibc-transfer.js'; import type { OfferStatus } from '@agoric/smart-wallet/src/offers.js'; import { - osmosisSwapTools, + makeOsmosisSwapTools, type Prefix, type Channel, type SetupOsmosisContextWithCommon, @@ -67,7 +67,7 @@ test.before(async t => { //@ts-expect-error missing swap tools t.context = { ...common, wallets }; - const swapTools = await osmosisSwapTools(t); + const swapTools = await makeOsmosisSwapTools(t); t.context = { ...t.context, ...swapTools }; }); From f385e2e59adae4e5c93696a9625650725973ddcf Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 16:22:17 +0100 Subject: [PATCH 23/24] chore: update starship configuration and README instructions --- .../config.xcs-swap-anything.yaml | 2 +- .../scripts/update-config-logs.sh | 5 ++++ .../test/xcs-swap-anything/README.md | 27 ++++++++++--------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/multichain-testing/config.xcs-swap-anything.yaml b/multichain-testing/config.xcs-swap-anything.yaml index 82b1095762b..137c84081d2 100644 --- a/multichain-testing/config.xcs-swap-anything.yaml +++ b/multichain-testing/config.xcs-swap-anything.yaml @@ -16,7 +16,7 @@ chains: unbonding_time: '2m' swingset: params: - bootstrap_vat_config: '@agoric/vm-config/decentral-itest-orchestration-chains-config.json' + bootstrap_vat_config: '@agoric/vm-config/decentral-itest-orchestration-config.json' scripts: updateConfig: file: scripts/update-config.sh diff --git a/multichain-testing/scripts/update-config-logs.sh b/multichain-testing/scripts/update-config-logs.sh index 93598a1d982..5b555226678 100644 --- a/multichain-testing/scripts/update-config-logs.sh +++ b/multichain-testing/scripts/update-config-logs.sh @@ -1,4 +1,9 @@ #!/bin/bash +# This script customizes chain configuration files for local testing, based on the default settings from: +# https://github.com/hyperweb-io/starship/blob/main/starship/charts/devnet/scripts/default/update-config.sh +# +# In addition to the standard configuration, it sets the log_level in config.toml to "debug" (instead of "info"). +# This enables detailed logging of contract calls and IBC transfer messages, aiding in debugging and observability. CHAIN_ID="${CHAIN_ID:=osmosis}" CHAIN_DIR="${CHAIN_DIR:=$HOME/.osmosisd}" diff --git a/multichain-testing/test/xcs-swap-anything/README.md b/multichain-testing/test/xcs-swap-anything/README.md index 0bd26febfa6..08853638d47 100644 --- a/multichain-testing/test/xcs-swap-anything/README.md +++ b/multichain-testing/test/xcs-swap-anything/README.md @@ -1,18 +1,21 @@ -## Spin up Environment +## Start Chains + +Runs agoric, cosmoshub, and osmosis with hermes relayers. + ```sh -cd agoric-sdk/multichain-testing +# start starship with xcs-swap-anything configuration +make clean setup make start FILE=config.xcs-swap-anything.yaml -make osmosis-xcs-setup -make create-osmosis-pool +``` + +## Run Tests -## Configure the osmosis registries -cd agoric-sdk/multichain-testing/test/xcs-swap-anything -make tx-chain-channel-links -make tx-bec32-prefixes +```sh +yarn test:xcs ``` -## Run tests +## Stop Chains + ```sh -cd agoric-sdk/multichain-testing -yarn ava test/xcs-swap-anything/swap-anything.test.ts -``` \ No newline at end of file +make stop +``` From c6074939734e867a68ad49b748f7b9b01b14510b Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 28 May 2025 18:43:57 +0100 Subject: [PATCH 24/24] fix: revert bootstrap_vat_config to add write-chain-info --- multichain-testing/config.xcs-swap-anything.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multichain-testing/config.xcs-swap-anything.yaml b/multichain-testing/config.xcs-swap-anything.yaml index 137c84081d2..82b1095762b 100644 --- a/multichain-testing/config.xcs-swap-anything.yaml +++ b/multichain-testing/config.xcs-swap-anything.yaml @@ -16,7 +16,7 @@ chains: unbonding_time: '2m' swingset: params: - bootstrap_vat_config: '@agoric/vm-config/decentral-itest-orchestration-config.json' + bootstrap_vat_config: '@agoric/vm-config/decentral-itest-orchestration-chains-config.json' scripts: updateConfig: file: scripts/update-config.sh