Skip to content

Commit

Permalink
Install exchange rate canister (#397)
Browse files Browse the repository at this point in the history
# Motivation

The NNS dapp displays the USD value of the total amount of ICP locked in
neurons.
It gets this information from the TVL canister but we want to move this
functionality to the nns-dapp canister and remove the TVL canister.

To test the TVL, we need to be able to get an exchange rate from the
exchange rate canister. To make this possible while testing, we install
a mock exchange rate canister.

# Changes

1. Refactor `bin/dfx-software-mock-bitcoin-install` to extract
`bin/dfx-mock-canister-install` for installing a generic mock canister.
2. Add `bin/dfx-mock-exchange-rate-canister-install` using
`bin/dfx-mock-canister-install`.
3. Add `bin/dfx-mock-exchange-rate-set` to populate the exchange rate.
4. Install the exchange rate canister and set an exchange rate for
ICP/USD in `bin/dfx-stock-deploy`.

# Tests

1. Added `bin/dfx-mock-exchange-rate-canister-install.test` analogous to
`bin/dfx-software-mock-bitcoin-install.test` and added it to
`.github/workflows/checks.yml`.
2. Created a snapshot and used it with a version of the nns-dapp that
has TVL implemented.

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
dskloetd and github-actions[bot] authored Sep 10, 2024
1 parent 72b6530 commit dc0dbe8
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 25 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,22 @@ jobs:
git clean -dfx
bin/dfx-canister-url.test --verbose
git clean -dfx
other-tests:
name: Other tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Install apt-dependencies
# Needed for sponge
run: sudo apt-get update && sudo apt-get install moreutils -yy
- name: Install idl2json
run: bin/dfx-software-idl2json-install
- name: Install dfx
uses: dfinity/setup-dfx@main
- name: Install mock exchange rate canister works
run: |
set -euxo pipefail
echo "This modifies files, so make sure the state is clean before and after"
git clean -dfx
bin/dfx-mock-exchange-rate-canister-install.test
git clean -dfx
67 changes: 67 additions & 0 deletions bin/dfx-mock-canister-install
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
PATH="$SOURCE_DIR:$PATH"

print_help() {
cat <<-EOF
Fetches and installs a given mock canister:
* Downloads the wasm.
* Adds the canister to dfx.json, if not already present.
* Deploys the downloaded wasm to the specified network.
EOF
}

# Source the clap.bash file ---------------------------------------------------
source "$SOURCE_DIR/clap.bash"
# Define options
clap.define short=n long=network desc="The dfx network to use" variable=DFX_NETWORK default="local"
clap.define long=wasm_url desc="The URL to download the wasm from" variable=WASM_URL default=""
clap.define long=canister_name desc="The name of the non-mock version of the canister" variable=CANISTER_NAME default=""
clap.define long=specified_canister_id desc="Use a specific canister ID instead of letting dfx pick one" variable=SPECIFIED_CANISTER_ID default=""
clap.define long=canister_arg desc="Candid argument to pass to dfx install" variable=CANISTER_ARG default="(record{})"
# Source the output file ----------------------------------------------------------
source "$(clap.build)"

if [[ -z "${WASM_URL:-}" ]]; then
echo "The --wasm_url option is required." >&2
exit 1
fi

if [[ -z "${CANISTER_NAME:-}" ]]; then
echo "The --canister_name option is required." >&2
exit 1
fi

WASM_DIR="wasms"
WASM_FILE="$CANISTER_NAME-mock.wasm.gz"
WASM_PATH="${WASM_DIR}/${WASM_FILE}"

mkdir -p "${WASM_DIR}"

echo "Downloading mock ${CANISTER_NAME} wasm from ${WASM_URL}"
curl --retry 5 --fail --silent --show-error --location \
"${WASM_URL}" >"${WASM_PATH}"

echo "Add an entry for '${CANISTER_NAME}' in dfx.json if there isn't one already."
if ! jq -e ".canisters.${CANISTER_NAME}" dfx.json >/dev/null; then
echo "Adding ${CANISTER_NAME} to dfx.json..."
jq -s '.[0] * .[1]' <(echo "{\"canisters\": { \"$CANISTER_NAME\": { \"type\": \"custom\", \"candid\": \"candid/${CANISTER_NAME}_mock.did\", \"wasm\": \"${WASM_PATH}\", \"build\": \"true\" }}}") dfx.json | sponge dfx.json
fi

DFX_CANISTER_CREATE_ARGS=()
if [[ -n "${SPECIFIED_CANISTER_ID:-}" ]]; then
DFX_CANISTER_CREATE_ARGS=("--specified-id" "$SPECIFIED_CANISTER_ID")
fi

if ! dfx canister create "$CANISTER_NAME" --network "${DFX_NETWORK}" "${DFX_CANISTER_CREATE_ARGS[@]}"; then
echo "Failed to create $CANISTER_NAME canister." >&2
exit 1
fi

dfx canister install "$CANISTER_NAME" --wasm "$WASM_PATH" --upgrade-unchanged --mode reinstall --yes --network "${DFX_NETWORK}" --argument "$CANISTER_ARG"

dfx-canister-check-wasm-hash --canister "$CANISTER_NAME" --network "$DFX_NETWORK" --wasm "${WASM_PATH}"

echo "Installed mock $CANISTER_NAME canister."
42 changes: 42 additions & 0 deletions bin/dfx-mock-exchange-rate-canister-install
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
PATH="$SOURCE_DIR:$PATH"

print_help() {
cat <<-EOF
Fetches and installs the mock exchange rate canister:
* Downloads the wasm.
* Adds the xrc canister to dfx.json, if not already present.
* Deploys the downloaded wasm to the specified network.
EOF
}

# Source the clap.bash file ---------------------------------------------------
source "$SOURCE_DIR/clap.bash"
# Define options
clap.define short=n long=network desc="The dfx network to use" variable=DFX_NETWORK default="local"
clap.define short=r long=release desc="The release to download the wasm from" variable=RELEASE default="pinned"
# Source the output file ----------------------------------------------------------
source "$(clap.build)"

# https://github.com/dfinity/ic/blob/ce350b79f34e5a8b57429cf6892c127195464984/rs/nns/constants/src/lib.rs#L114-L116
HARD_CODED_CANISTER_ID="uf6dk-hyaaa-aaaaq-qaaaq-cai"

if [[ "${RELEASE}" ]]; then
. "$SOURCE_DIR/versions.bash"
RELEASE="${EXCHANGE_RATE_CANISTER_RELEASE}"
fi

WASM_FILE="xrc_mock.wasm.gz"
WASM_URL="https://github.com/dfinity/exchange-rate-canister/releases/download/${RELEASE}/${WASM_FILE}"
CANISTER_NAME="xrc"
CANISTER_ARG="(record{response=variant{Error=variant{CryptoBaseAssetNotFound=null}}})"

dfx-mock-canister-install \
--network "${DFX_NETWORK}" \
--wasm_url "${WASM_URL}" \
--canister_name "${CANISTER_NAME}" \
--specified_canister_id "${HARD_CODED_CANISTER_ID}" \
--canister_arg "${CANISTER_ARG}"
44 changes: 44 additions & 0 deletions bin/dfx-mock-exchange-rate-canister-install.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
PATH="$SOURCE_DIR:$PATH"

# https://github.com/dfinity/ic/blob/ce350b79f34e5a8b57429cf6892c127195464984/rs/nns/constants/src/lib.rs#L114-L116
HARD_CODED_EXCHANGE_RATE_CANISTER_ID="uf6dk-hyaaa-aaaaq-qaaaq-cai"

git checkout dfx.json
dfx-network-stop
dfx start --clean --background

trap 'dfx-network-stop' EXIT

if dfx canister metadata "$HARD_CODED_EXCHANGE_RATE_CANISTER_ID" --network local candid:service; then
echo "ERROR: exchange rate canister should not exist before installing."
exit 1
fi

dfx-mock-exchange-rate-canister-install --network local

# dfx-mock-exchange-rate-canister-install is a known method on the exchange rate canister.
if ! dfx canister metadata "$HARD_CODED_EXCHANGE_RATE_CANISTER_ID" --network local candid:service | grep get_exchange_rate; then
echo "ERROR: mock exchange rate canister should have been installed."
exit 1
fi

EXPECTED_EXCHANGE_RATE=345000000

bin/dfx-mock-exchange-rate-set --network local --base_asset ICP --quote_asset USD --rate_e8s "$EXPECTED_EXCHANGE_RATE"

ACTUAL_EXCHANGE_RATE="$(dfx canister call xrc get_exchange_rate '(
record {
quote_asset = record { class = variant { FiatCurrency }; symbol = "USD" };
base_asset = record { class = variant { Cryptocurrency }; symbol = "ICP" };
}
)' | idl2json | jq -r '.Ok.rate')"

if [[ "$ACTUAL_EXCHANGE_RATE" != "$EXPECTED_EXCHANGE_RATE" ]]; then
echo "ERROR: exchange rate should have been set to $EXPECTED_EXCHANGE_RATE, but was $ACTUAL_EXCHANGE_RATE."
exit 1
fi

echo "PASSED: dfx-mock-exchange-rate-canister-install.test"
28 changes: 28 additions & 0 deletions bin/dfx-mock-exchange-rate-set
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
SOURCE_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
PATH="$SOURCE_DIR:$PATH"

print_help() {
cat <<-EOF
Sets the exchange rate for the given currency pair on the mock exchange rate canister.
EOF
}

# Source the clap.bash file ---------------------------------------------------
source "$SOURCE_DIR/clap.bash"
# Define options
clap.define short=n long=network desc="The dfx network to use" variable=DFX_NETWORK default="local"
clap.define short=q long=base_asset desc="The base asset to use. In ICP/USD this is ICP" variable=BASE_ASSET default="ICP"
clap.define short=q long=quote_asset desc="The quote asset to use. In ICP/USD this is USD" variable=QUOTE_ASSET default="USD"
clap.define short=r long=rate_e8s desc="The price of the base asset expressed in e8s of the quote asset. For 9.00 USD per ICP this is 900_000_000" variable=RATE_E8S default=""
# Source the output file ----------------------------------------------------------
source "$(clap.build)"

if [[ -z "${RATE_E8S}" ]]; then
echo "ERROR: --rate_e8s is required"
exit 1
fi

dfx canister call xrc set_exchange_rate "(record{base_asset=\"$BASE_ASSET\"; quote_asset=\"$QUOTE_ASSET\"; rate=$RATE_E8S:nat64})"
34 changes: 9 additions & 25 deletions bin/dfx-software-mock-bitcoin-install
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,14 @@ if [[ "${DFX_IC_COMMIT}" == "pinned" ]]; then
DFX_IC_COMMIT="$(dfx-software-ic-current)"
fi

WASM_DIR="wasms"
WASM_FILE="bitcoin-mock-canister.wasm.gz"
WASM_PATH="${WASM_DIR}/${WASM_FILE}"
WASM_URL="https://download.dfinity.systems/ic/${DFX_IC_COMMIT}/canisters/${WASM_FILE}"

mkdir -p "${WASM_DIR}"

echo "Downloading mock bitcoin wasm from ${WASM_URL}"
curl --retry 5 --fail --silent --show-error --location \
"${WASM_URL}" >"${WASM_PATH}"

echo "Add an entry for 'bitcoin' in dfx.json if there isn't one already."
if ! jq -e '.canisters.bitcoin' dfx.json >/dev/null; then
echo "Adding bitcoin to dfx.json..."
jq -s '.[0] * .[1]' <(echo '{"canisters": { "bitcoin": { "type": "custom", "candid": "candid/bitcoin_mock.did", "wasm": "'"${WASM_PATH}"'", "build": "true" }}}') dfx.json | sponge dfx.json
fi

if ! dfx canister create bitcoin --network "${DFX_NETWORK}" --specified-id "$HARD_CODED_BITCOIN_CANISTER_ID"; then
echo "Failed to create bitcoin canister." >&2
exit 1
fi

dfx canister install bitcoin --wasm "$WASM_PATH" --upgrade-unchanged --mode reinstall --yes --network "${DFX_NETWORK}" --argument '(variant { mainnet })'

dfx-canister-check-wasm-hash --canister bitcoin --network "$DFX_NETWORK" --wasm "${WASM_PATH}"

echo "Installed mock bitcoin canister."
CANISTER_NAME="bitcoin"
CANISTER_ARG="(variant { mainnet })"

dfx-mock-canister-install \
--network "${DFX_NETWORK}" \
--wasm_url "${WASM_URL}" \
--canister_name "${CANISTER_NAME}" \
--specified_canister_id "${HARD_CODED_BITCOIN_CANISTER_ID}" \
--canister_arg "${CANISTER_ARG}"
3 changes: 3 additions & 0 deletions bin/dfx-stock-deploy
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ fi
: Set up SNS state and create one finalized SNS
dfx-sns-demo --network "$DFX_NETWORK" --ic_commit "$DFX_IC_COMMIT" --ic_dir "$IC_REPO_DIR" --nd_dir "$ND_REPO_DIR" --unique_logo "$UNIQUE_LOGO"

dfx-mock-exchange-rate-canister-install --network "$DFX_NETWORK" --release pinned
dfx-mock-exchange-rate-set --network "$DFX_NETWORK" --base_asset ICP --quote_asset USD --rate_e8s 900_000_000

dfx-software-mock-bitcoin-install --network "$DFX_NETWORK" --ic_commit "$DFX_IC_COMMIT"

: Add 1 open SNS project.
Expand Down
1 change: 1 addition & 0 deletions bin/versions.bash
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ BINSTALL_VERSION=1.3.0
IC_WASM_VERSION=0.6.0
DFX_NNS_EXTENSION_VERSION=0.4.3
DFX_SNS_EXTENSION_VERSION=0.4.3
EXCHANGE_RATE_CANISTER_RELEASE=2024.09.05

0 comments on commit dc0dbe8

Please sign in to comment.