diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..44df0ff --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/strict-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + 'prettier', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: [], + rules: {}, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, + settings: {}, +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..211f811 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +node_modules +temp +build diff --git a/.prettierrc b/.prettierrc index 24a6660..e8c1b75 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,8 @@ { "printWidth": 120, "tabWidth": 4, + "semi": false, "singleQuote": true, "bracketSpacing": true, - "semi": true + "trailingComma": "all" } diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..959fa93 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.PHONY: build_graphviz graphs clean + +UID=$(shell id -u) +GID=$(shell id -g) + +GRAPHVIZ_DOCKER_IMG=contract/graphviz:latest + +build_graphviz: + @docker build -t $(GRAPHVIZ_DOCKER_IMG) -f docker/graphviz.Dockerfile . + +graphs: + @docker run --rm --user $(UID):$(GID) -v $(PWD)/graphs:/data $(GRAPHVIZ_DOCKER_IMG) + +clean: + @rm -r graphs/img diff --git a/README.md b/README.md index 2dde478..95d2a67 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,18 @@ There are 3 roles in the governance of the protocol: - Deploy: `yarn blueprint run` - Test: `yarn test` +### Graphs + +Requirements: + +1. [Docker](https://docs.docker.com/get-docker/) +2. make + +How to generate: + +1. `make build_graphviz` +2. `make graphs` + ## License -MIT +[MIT](./LICENSE) diff --git a/contracts/imports/stdlib.fc b/contracts/imports/stdlib.fc index 5a30dee..25b790c 100644 --- a/contracts/imports/stdlib.fc +++ b/contracts/imports/stdlib.fc @@ -290,7 +290,7 @@ slice begin_parse(cell c) asm "CTOS"; ;;; Preloads the first reference from the slice. cell preload_ref(slice s) asm "PLDREF"; - {- Functions below are commented because are implemented on compilator level for optimisation -} +{- Functions below are commented because are implemented on compilator level for optimisation -} ;;; Loads a signed [len]-bit integer from a slice [s]. ;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; diff --git a/contracts/imports/utils.fc b/contracts/imports/utils.fc index 424f33b..5adc588 100644 --- a/contracts/imports/utils.fc +++ b/contracts/imports/utils.fc @@ -229,7 +229,7 @@ int max_recommended_punishment_for_validator_misbehaviour(int stake) inline_ref , cs~load_uint(16), cs~load_uint(16) , cs~load_uint(16) , cs~load_uint(16), cs~load_uint(16), cs~load_uint(16) - ); + ); ;; https://github.com/ton-blockchain/ton/blob/master/lite-client/lite-client.cpp#L3721 int fine = default_flat_fine; diff --git a/contracts/treasury.fc b/contracts/treasury.fc index cfc3ff0..3357f04 100644 --- a/contracts/treasury.fc +++ b/contracts/treasury.fc @@ -1370,14 +1370,24 @@ builder pack_participation } () upgrade_data(slice src, int query_id, slice s) impure method_id { + ;; Add code for upgrading date here. + ;; This is just a template, and will only run after upgrade_code. ;; If data is upgraded, remember to reset this code, ;; so that the next upgrade won't change data by mistake. + ;; Do not change the following code. + load_data(); + unpack_extension(); + + throw_unless(err::access_denied, equal_slice_bits(src, governor)); + builder excess = begin_cell() .store_uint(op::gas_excess, 32) .store_uint(query_id, 64); send_msg(false, src.to_builder(), null(), excess, 0, send::remaining_value + send::ignore_errors); + + throw(0); } () upgrade_code(slice src, slice s) impure inline { @@ -1392,7 +1402,6 @@ builder pack_participation set_code(new_code); set_c3(new_code.begin_parse().bless()); upgrade_data(src, query_id, s); - throw(0); } () withdraw_surplus(int msg_ton, slice src, slice s) impure inline { diff --git a/custom-matchers.d.ts b/custom-matchers.d.ts new file mode 100644 index 0000000..eedf47b --- /dev/null +++ b/custom-matchers.d.ts @@ -0,0 +1,14 @@ +export {} + +declare global { + namespace jest { + interface AsymmetricMatchers { + toBeBetween(a: bigint | string, b: bigint | string): void + toBeTonValue(v: bigint | string): void + } + interface Matchers { + toBeBetween(a: bigint | string, b: bigint | string): R + toBeTonValue(v: bigint | string): R + } + } +} diff --git a/docker/graphviz.Dockerfile b/docker/graphviz.Dockerfile new file mode 100644 index 0000000..b8b24fd --- /dev/null +++ b/docker/graphviz.Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:3.18 + +RUN apk add --no-cache graphviz ttf-dejavu && \ + chmod -R a+rw /var/cache/fontconfig + +COPY docker/graphviz.sh /dot/graphviz.sh + +WORKDIR /data + +ENTRYPOINT ["/dot/graphviz.sh"] diff --git a/docker/graphviz.sh b/docker/graphviz.sh new file mode 100755 index 0000000..d716809 --- /dev/null +++ b/docker/graphviz.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +if [ ! -d "img" ]; then + mkdir img +fi + +for file in *.dot +do + echo "Generating image from $file" + dot -Tsvg $file -o img/${file%.*}.svg +done diff --git a/graphs/img/00-legend.svg b/graphs/img/00-legend.svg new file mode 100644 index 0000000..46097ae --- /dev/null +++ b/graphs/img/00-legend.svg @@ -0,0 +1,91 @@ + + + + + + + +        The black point denotes an external message starting the flow. +         Each node is a smart contract. +         Arrows denote a message sent from one smart contract to another. +         The number on each arrow shows the order of messages. +         Each arrow has an operation identifying the message type being sent. +         Blue nodes are simple TON wallets controlled by its owning user. +         Green nodes are hTON wallets. +         Dotted lines show the owner of each hTON wallet. +          + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +treasury + +treasury + + + +staker->treasury + + +2 + op::deposit_coins + 10.10 TON + + + +driver + +driver + + + +wallet->driver + + +4 + op::gas_excess + 0.08 TON + + + +treasury->wallet + + +3 + op::save_coins + 0.09 TON + coins: 10 + + + diff --git a/graphs/img/01-deposit-coins.svg b/graphs/img/01-deposit-coins.svg new file mode 100644 index 0000000..c044541 --- /dev/null +++ b/graphs/img/01-deposit-coins.svg @@ -0,0 +1,83 @@ + + + + + + + +staker deposits 10 TON to receive near 10 hTON later + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +treasury + +treasury + + + +staker->treasury + + +2 + op::deposit_coins + 10.10 TON + + + +driver + +driver + + + +wallet->driver + + +4 + op::gas_excess + 0.08 TON + + + +treasury->wallet + + +3 + op::save_coins + 0.09 TON + coins: 10 + + + diff --git a/graphs/img/02.1-stake-coins-too-soon.svg b/graphs/img/02.1-stake-coins-too-soon.svg new file mode 100644 index 0000000..516258e --- /dev/null +++ b/graphs/img/02.1-stake-coins-too-soon.svg @@ -0,0 +1,87 @@ + + + + + + + +user cannot convert coins to tokens before round's rewards are distributed + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +staker->wallet + + +2 + op::stake_coins + 0.07 TON + + + +wallet->staker + + +5 + op::gas_excess + 0.04 TON + + + +treasury + +treasury + + + +wallet->treasury + + +3 + op::mint_tokens + 0.06 TON + coins: 10 + + + +treasury->wallet + + +4 + op::save_coins + 0.05 TON + coins: 10 + + + diff --git a/graphs/img/02.2-stake-coins.svg b/graphs/img/02.2-stake-coins.svg new file mode 100644 index 0000000..4596e90 --- /dev/null +++ b/graphs/img/02.2-stake-coins.svg @@ -0,0 +1,103 @@ + + + + + + + +staker's deposit of 10 TON is converted to near 10 hTON considering the current price + + +external + + + + +driver + +driver + + + +external->driver + + +1 + + + +staker + +staker + + + +wallet + +wallet + + + +staker->wallet + + + + + +driver->wallet + + +2 + op::stake_coins + 0.07 TON + + + +wallet->staker + + +5 + op::transfer_notification + 0.01 TON + tokens: 10 + + + +wallet->driver + + +6 + op::gas_excess + 0.03 TON + + + +treasury + +treasury + + + +wallet->treasury + + +3 + op::mint_tokens + 0.06 TON + coins: 10 + + + +treasury->wallet + + +4 + op::receive_tokens + 0.05 TON + tokens: 10 + + + diff --git a/graphs/img/03-send-tokens.svg b/graphs/img/03-send-tokens.svg new file mode 100644 index 0000000..82f9eea --- /dev/null +++ b/graphs/img/03-send-tokens.svg @@ -0,0 +1,102 @@ + + + + + + + +staker1 sends 10 hTON to staker2 + + +external + + + + +staker1 + +staker1 + + + +external->staker1 + + +1 + + + +wallet1 + +wallet1 + + + +staker1->wallet1 + + + + + +staker1->wallet1 + + +2 + op::send_tokens + 1.10 TON + tokens: 10 + forward: 1 + + + +staker2 + +staker2 + + + +wallet2 + +wallet2 + + + +staker2->wallet2 + + + + + +wallet1->wallet2 + + +3 + op::receive_tokens + 1.09 TON + tokens: 10 + forward: 1 + + + +wallet2->staker1 + + +5 + op::gas_excess + 0.08 TON + + + +wallet2->staker2 + + +4 + op::transfer_notification + 1 TON + tokens: 10 + + + diff --git a/graphs/img/04-unstake-tokens.svg b/graphs/img/04-unstake-tokens.svg new file mode 100644 index 0000000..400bf8d --- /dev/null +++ b/graphs/img/04-unstake-tokens.svg @@ -0,0 +1,93 @@ + + + + + + + +staker unstakes 10 hTON which will be converted to near 10 TON considering the future price + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +staker->wallet + + +2 + op::unstake_tokens + 0.20 TON + tokens: 10 + + + +driver + +driver + + + +treasury + +treasury + + + +treasury->staker + + +5 + op::gas_excess + 0.10 TON + + + +treasury->driver + + +4 + op::gas_excess + 0.08 TON + + + +wallet->treasury + + +3 + op::reserve_tokens + 0.19 TON + tokens: 10 + + + diff --git a/graphs/img/05.1-withdraw-tokens-no-funds.svg b/graphs/img/05.1-withdraw-tokens-no-funds.svg new file mode 100644 index 0000000..d373708 --- /dev/null +++ b/graphs/img/05.1-withdraw-tokens-no-funds.svg @@ -0,0 +1,93 @@ + + + + + + + +withdrawing but there's not enough TON in treasury + + +external + + + + +driver + +driver + + + +external->driver + + +1 + + + +staker + +staker + + + +wallet + +wallet + + + +staker->wallet + + + + + +driver->wallet + + +2 + op::withdraw_tokens + 0.07 TON + + + +treasury + +treasury + + + +treasury->wallet + + +4 + op::burn_failed + 0.05 TON + tokens: 10 + + + +wallet->driver + + +5 + op::withdraw_failed + 0.04 TON + + + +wallet->treasury + + +3 + op::burn_tokens + 0.06 TON + tokens: 10 + + + diff --git a/graphs/img/05.2-withdraw-tokens.svg b/graphs/img/05.2-withdraw-tokens.svg new file mode 100644 index 0000000..9a8c011 --- /dev/null +++ b/graphs/img/05.2-withdraw-tokens.svg @@ -0,0 +1,92 @@ + + + + + + + +staker withdraws 10 TON + + +external + + + + +driver + +driver + + + +external->driver + + +1 + + + +staker + +staker + + + +wallet + +wallet + + + +staker->wallet + + + + + +driver->wallet + + +2 + op::withdraw_tokens + 0.07 TON + + + +treasury + +treasury + + + +treasury->staker + + +4 + op::withdrawal_notification + 10 TON + + + +treasury->driver + + +5 + op::gas_excess + 0.04 TON + + + +wallet->treasury + + +3 + op::burn_tokens + 0.06 TON + tokens: 10 + + + diff --git a/graphs/img/06-request-loan.svg b/graphs/img/06-request-loan.svg new file mode 100644 index 0000000..f9a8358 --- /dev/null +++ b/graphs/img/06-request-loan.svg @@ -0,0 +1,109 @@ + + + + + + + +validators request loans + + +external1 + + + + +validator1 + +validator1 + + + +external1->validator1 + + +1 + + + +external2 + + + + +validator2 + +validator2 + + + +external2->validator2 + + +1 + + + +externalN + + + + +validatorN + +validatorN + + + +externalN->validatorN + + +1 + + + +treasury + +treasury + + + +validator1->treasury + + +2 + op::request_loan + 100002 TON + loan: 200000 + min payment: 100 + share: 40% + + + +validator2->treasury + + +2 + op::request_loan + 202 TON + loan: 300000 + min payment: 100 + share: 40% + + + +validatorN->treasury + + +2 + op::request_loan + 302 TON + loan: 300000 + min payment: 200 + share: 100% + + + diff --git a/graphs/img/07-participate-in-election.svg b/graphs/img/07-participate-in-election.svg new file mode 100644 index 0000000..0c65a02 --- /dev/null +++ b/graphs/img/07-participate-in-election.svg @@ -0,0 +1,159 @@ + + + + + + + +anyone sends a message to start the process of participation in election + + +external + + + + +treasury + +treasury + + + +external->treasury + + +1 + op::participate_in_election + + + +treasury->treasury + + +2 + op::decide_loan_requests     + + + +treasury->treasury + + +3 + op::process_loan_requests + + + +loan2 + +loan2 + + + +treasury->loan2 + + +4 + op::send_new_stake + 300002 TON + + + +loan3 + +loan3 + + + +treasury->loan3 + + +7 + op::send_new_stake + 300002 TON + + + +validator1 + +validator1 + + + +treasury->validator1 + + +10 + op::request_rejected + 301 TON + + + +elector + +elector + + + +loan2->elector + + +5 + op::new_stake + 300001 TON + + + +loan3->elector + + +8 + op::new_stake + 300001 TON + + + +elector->loan2 + + +6 + op::new_stake_ok + 1 TON + + + +elector->loan3 + + +9 + op::new_stake_ok + 1 TON + + + +validator2 + +validator2 + + + +validator2->loan2 + + + + + +validator3 + +validator3 + + + +validator3->loan3 + + + + + diff --git a/graphs/img/08-vset-changed.svg b/graphs/img/08-vset-changed.svg new file mode 100644 index 0000000..1a4f8f2 --- /dev/null +++ b/graphs/img/08-vset-changed.svg @@ -0,0 +1,32 @@ + + + + + + + +anyone sends a message to update validators set + + +external + + + + +treasury + +treasury + + + +external->treasury + + +1 + op::vset_changed + + + diff --git a/graphs/img/09-finish-participation.svg b/graphs/img/09-finish-participation.svg new file mode 100644 index 0000000..b5ba4dd --- /dev/null +++ b/graphs/img/09-finish-participation.svg @@ -0,0 +1,184 @@ + + + + + + + +anyone sends a message to finish participation + + +external + + + + +treasury + +treasury + + + +external->treasury + + +1 + op::finish_participation + + + +treasury->treasury + + +2 + op::recover_stakes + + + +loan1 + +loan1 + + + +treasury->loan1 + + +3 + op::send_recover_stake + 1 TON + + + +loan2 + +loan2 + + + +treasury->loan2 + + +9 + op::send_recover_stake + 1 TON + + + +validator1 + +validator1 + + + +treasury->validator1 + + +7 + op::loan_result + 100050 TON + + + +validator2 + +validator2 + + + +treasury->validator2 + + +13 + op::loan_result + 250 TON + + + +governor + +governor + + + +treasury->governor + + +8 + op::take_profit + 50 TON + + + +treasury->governor + + +14 + op::take_profit + 50 TON + + + +loan1->treasury + + +6 + op::recover_stake_result + 300101 TON + + + +elector + +elector + + + +loan1->elector + + +4 + op::recover_stake + 1 TON + + + +loan2->treasury + + +12 + op::recover_stake_result + 300101 TON + + + +loan2->elector + + +10 + op::recover_stake + 1 TON + + + +elector->loan1 + + +5 + op::recover_stake_ok + 300101 TON + + + +elector->loan2 + + +11 + op::recover_stake_ok + 300101 TON + + + diff --git a/graphs/img/10-text-deposit-coins.svg b/graphs/img/10-text-deposit-coins.svg new file mode 100644 index 0000000..1985750 --- /dev/null +++ b/graphs/img/10-text-deposit-coins.svg @@ -0,0 +1,83 @@ + + + + + + + +staker sends a simple message with comment 'd' to deposit coins + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +treasury + +treasury + + + +staker->treasury + + +2 + comment: d + 10.10 TON + + + +driver + +driver + + + +wallet->driver + + +4 + op::gas_excess + 0.08 TON + + + +treasury->wallet + + +3 + op::save_coins + 0.09 TON + coins: 10 + + + diff --git a/graphs/img/11-text-stake-coins.svg b/graphs/img/11-text-stake-coins.svg new file mode 100644 index 0000000..ef5c83a --- /dev/null +++ b/graphs/img/11-text-stake-coins.svg @@ -0,0 +1,106 @@ + + + + + + + +staker sends a simple message with comment 's' to stake coins + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +treasury + +treasury + + + +staker->treasury + + +2 + comment: s + 0.07 TON + + + +wallet->staker + + +6 + op::transfer_notification + 0.01 TON + tokens: 9 + + + +wallet->staker + + +7 + op::gas_excess + 0.03 TON + + + +wallet->treasury + + +4 + op::mint_tokens + 0.06 TON + coins: 10 + + + +treasury->wallet + + +3 + op::stake_first_coins + 0.07 TON + + + +treasury->wallet + + +5 + op::receive_tokens + 0.05 TON + tokens: 10 + + + diff --git a/graphs/img/12-text-unstake-tokens.svg b/graphs/img/12-text-unstake-tokens.svg new file mode 100644 index 0000000..353df4d --- /dev/null +++ b/graphs/img/12-text-unstake-tokens.svg @@ -0,0 +1,101 @@ + + + + + + + +staker sends a simple message with comment 'w' to unstake all tokens + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +treasury + +treasury + + + +staker->treasury + + +2 + comment: w + 0.20 TON + + + +wallet + +wallet + + + +staker->wallet + + + + + +driver + +driver + + + +treasury->staker + + +6 + op::gas_excess + 0.10 TON + + + +treasury->driver + + +5 + op::gas_excess + 0.07 TON + + + +treasury->wallet + + +3 + op::unstake_all_tokens + 0.19 TON + + + +wallet->treasury + + +4 + op::reserve_tokens + 0.18 TON + tokens: 10 + + + diff --git a/graphs/img/13-text-withdraw-tokens.svg b/graphs/img/13-text-withdraw-tokens.svg new file mode 100644 index 0000000..dc72291 --- /dev/null +++ b/graphs/img/13-text-withdraw-tokens.svg @@ -0,0 +1,95 @@ + + + + + + + +staker sends a simple message with comment 'u' to withdraw tokens + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +treasury + +treasury + + + +staker->treasury + + +2 + comment: u + 0.07 TON + + + +wallet + +wallet + + + +staker->wallet + + + + + +treasury->staker + + +5 + op::withdrawal_notification + 10 TON + + + +treasury->staker + + +6 + op::gas_excess + 0.04 TON + + + +treasury->wallet + + +3 + op::withdraw_tokens + 0.07 TON + + + +wallet->treasury + + +4 + op::burn_tokens + 0.06 TON + tokens: 10 + + + diff --git a/graphs/img/14-propose-governor.svg b/graphs/img/14-propose-governor.svg new file mode 100644 index 0000000..ba93093 --- /dev/null +++ b/graphs/img/14-propose-governor.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor proposes another governor + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::propose_governor + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/15-accept-governance.svg b/graphs/img/15-accept-governance.svg new file mode 100644 index 0000000..72d366b --- /dev/null +++ b/graphs/img/15-accept-governance.svg @@ -0,0 +1,55 @@ + + + + + + + +the new governor accepts governance + + +external + + + + +proposed_governor + +proposed_governor + + + +external->proposed_governor + + +1 + + + +treasury + +treasury + + + +proposed_governor->treasury + + +2 + op::accept_governance + 0.10 TON + + + +treasury->proposed_governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/16-set-halter.svg b/graphs/img/16-set-halter.svg new file mode 100644 index 0000000..5699f37 --- /dev/null +++ b/graphs/img/16-set-halter.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor changes the halter + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::set_halter + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/17-set-stopped.svg b/graphs/img/17-set-stopped.svg new file mode 100644 index 0000000..e1fa63f --- /dev/null +++ b/graphs/img/17-set-stopped.svg @@ -0,0 +1,55 @@ + + + + + + + +the current halter sets the stopped flag + + +external + + + + +halter + +halter + + + +external->halter + + +1 + + + +treasury + +treasury + + + +halter->treasury + + +2 + op::set_stopped + 0.10 TON + + + +treasury->halter + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/18-set-driver.svg b/graphs/img/18-set-driver.svg new file mode 100644 index 0000000..8ab70cb --- /dev/null +++ b/graphs/img/18-set-driver.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor sets the driver + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::set_driver + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/19-set-content.svg b/graphs/img/19-set-content.svg new file mode 100644 index 0000000..7f8dbdd --- /dev/null +++ b/graphs/img/19-set-content.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor sets the content + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::set_content + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/20-set-governance-fee.svg b/graphs/img/20-set-governance-fee.svg new file mode 100644 index 0000000..b8c0115 --- /dev/null +++ b/graphs/img/20-set-governance-fee.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor sets the governance fee + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::set_governance_fee + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/21-set-balanced-rounds.svg b/graphs/img/21-set-balanced-rounds.svg new file mode 100644 index 0000000..75118fc --- /dev/null +++ b/graphs/img/21-set-balanced-rounds.svg @@ -0,0 +1,55 @@ + + + + + + + +the current halter sets the balanced-rounds flag + + +external + + + + +halter + +halter + + + +external->halter + + +1 + + + +treasury + +treasury + + + +halter->treasury + + +2 + op::set_balanced_rounds + 0.10 TON + + + +treasury->halter + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/graphs/img/22-wallet-withdraw-surplus.svg b/graphs/img/22-wallet-withdraw-surplus.svg new file mode 100644 index 0000000..2b7c457 --- /dev/null +++ b/graphs/img/22-wallet-withdraw-surplus.svg @@ -0,0 +1,61 @@ + + + + + + + +staker withdraws surplus of wallet + + +external + + + + +staker + +staker + + + +external->staker + + +1 + + + +wallet + +wallet + + + +staker->wallet + + + + + +staker->wallet + + +2 + op::withdraw_surplus + 0.10 TON + + + +wallet->staker + + +3 + op::gas_excess + 0.14 TON + + + diff --git a/graphs/img/23-treasury-withdraw-surplus.svg b/graphs/img/23-treasury-withdraw-surplus.svg new file mode 100644 index 0000000..2c677ae --- /dev/null +++ b/graphs/img/23-treasury-withdraw-surplus.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor withdraws surplus of treasury + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::withdraw_surplus + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 20.09 TON + + + diff --git a/graphs/img/24-halter-sends-message-to-loan.svg b/graphs/img/24-halter-sends-message-to-loan.svg new file mode 100644 index 0000000..10b2bbe --- /dev/null +++ b/graphs/img/24-halter-sends-message-to-loan.svg @@ -0,0 +1,60 @@ + + + + + + + +the current halter sends any message to a loan + + +external + + + + +halter + +halter + + + +external->halter + + +1 + + + +treasury + +treasury + + + +halter->treasury + + +2 + op::send_message_to_loan + 0.10 TON + + + +loan + +loan + + + +treasury->loan + + +3 + 0.9 TON + + + diff --git a/graphs/img/25-halter-sends-process-loan-requests.svg b/graphs/img/25-halter-sends-process-loan-requests.svg new file mode 100644 index 0000000..133ab2b --- /dev/null +++ b/graphs/img/25-halter-sends-process-loan-requests.svg @@ -0,0 +1,55 @@ + + + + + + + +the current halter sends process-loan-requests + + +external + + + + +halter + +halter + + + +external->halter + + +1 + + + +treasury + +treasury + + + +halter->treasury + + +2 + op::send_process_loan_requests + 0.10 TON + + + +treasury->treasury + + +3 + op::process_loan_requests + 0.9 TON + + + diff --git a/graphs/img/26-upgrade-code.svg b/graphs/img/26-upgrade-code.svg new file mode 100644 index 0000000..a9e9ff5 --- /dev/null +++ b/graphs/img/26-upgrade-code.svg @@ -0,0 +1,55 @@ + + + + + + + +the current governor upgrades the code of the treasury + + +external + + + + +governor + +governor + + + +external->governor + + +1 + + + +treasury + +treasury + + + +governor->treasury + + +2 + op::upgrade_code + 0.10 TON + + + +treasury->governor + + +3 + op::gas_excess + 0.09 TON + + + diff --git a/jest.config.ts b/jest.config.ts index e48e1a1..ce2bc0a 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,11 +1,12 @@ -import type { Config } from 'jest'; +import type { Config } from 'jest' const config: Config = { preset: 'ts-jest', testEnvironment: 'node', testPathIgnorePatterns: ['/node_modules/', '/dist/'], + setupFilesAfterEnv: ['/tests/setup-jest.ts'], slowTestThreshold: 20, workerThreads: true, -}; +} -export default config; +export default config diff --git a/package.json b/package.json index b44bceb..af0d5c7 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "license": "MIT", "private": true, "scripts": { + "lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0", "test": "jest" }, "devDependencies": { @@ -13,6 +14,10 @@ "@ton-community/test-utils": "^0.2.0", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.7.4", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.0.0", "jest": "^29.5.0", "prettier": "^2.8.8", "ton": "^13.5.0", diff --git a/scripts/deployTreasury.ts b/scripts/deployTreasury.ts index ed1657b..bad3970 100644 --- a/scripts/deployTreasury.ts +++ b/scripts/deployTreasury.ts @@ -4,7 +4,7 @@ import { compile, NetworkProvider } from '@ton-community/blueprint' import { sha256_sync } from 'ton-crypto' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() const governor = provider.sender().address if (governor == null) { @@ -12,39 +12,46 @@ export async function run(provider: NetworkProvider) { } const treasury = provider.open( - Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode: await compile('Wallet'), - loanCode: await compile('Loan'), - driver: governor, - halter: governor, - governor: governor, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content, - }, await compile('Treasury')) + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode: await compile('Wallet'), + loanCode: await compile('Loan'), + driver: governor, + halter: governor, + governor: governor, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content, + }, + await compile('Treasury'), + ), ) + const confirm = await ui.input('\n\nDeploy new contract? [yN]') + if (confirm.toLowerCase() !== 'y') { + return + } await treasury.sendDeploy(provider.sender(), { value: toNano('10.01') }) await provider.waitForDeploy(treasury.address) - ui.clearActionPrompt(); - ui.write('Done'); + ui.clearActionPrompt() + ui.write('Done') } const contentDict = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.Cell()) - .set(toSha256("decimals"), toTextCell("9")) - .set(toSha256("symbol"), toTextCell("hTON")) - .set(toSha256("name"), toTextCell("hTON")) - .set(toSha256("description"), toTextCell("Hipo liquid staking protocol")) - .set(toSha256("image"), toTextCell("https://hipo.finance/hton.png")) + .set(toSha256('decimals'), toTextCell('9')) + .set(toSha256('symbol'), toTextCell('hTON')) + .set(toSha256('name'), toTextCell('hTON')) + .set(toSha256('description'), toTextCell('Hipo liquid staking protocol')) + .set(toSha256('image'), toTextCell('https://hipo.finance/hton.png')) const content = beginCell().storeUint(0, 8).storeDict(contentDict).endCell() diff --git a/scripts/finishParticipation.ts b/scripts/finishParticipation.ts index 7bfa572..ce64be9 100644 --- a/scripts/finishParticipation.ts +++ b/scripts/finishParticipation.ts @@ -3,9 +3,9 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() - const addressString = await ui.input('treasury\'s friendly address') + const addressString = await ui.input("treasury's friendly address") const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) @@ -13,5 +13,5 @@ export async function run(provider: NetworkProvider) { await treasury.sendFinishParticipation({ roundSince }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/getLoanAddress.ts b/scripts/getLoanAddress.ts index 4e46221..1a2646d 100644 --- a/scripts/getLoanAddress.ts +++ b/scripts/getLoanAddress.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() const addressString = await ui.input('Enter the friendly address of the treasury') const treasuryAddress = Address.parse(addressString) @@ -16,7 +16,11 @@ export async function run(provider: NetworkProvider) { } const loanAddress = await treasury.getLoanAddress(validatorAddress, roundSince) - console.info('Loan Address:\n Raw: %s\n Friendly: %s\n', loanAddress.toRawString(), loanAddress.toString({ urlSafe: true, bounceable: true, testOnly: true })) + console.info( + 'Loan Address:\n Raw: %s\n Friendly: %s\n', + loanAddress.toRawString(), + loanAddress.toString({ urlSafe: true, bounceable: true, testOnly: true }) + ) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/participateInElection.ts b/scripts/participateInElection.ts index e9756bd..54e1750 100644 --- a/scripts/participateInElection.ts +++ b/scripts/participateInElection.ts @@ -3,9 +3,9 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() - const addressString = await ui.input('treasury\'s friendly address') + const addressString = await ui.input("treasury's friendly address") const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) @@ -13,5 +13,5 @@ export async function run(provider: NetworkProvider) { await treasury.sendParticipateInElection({ roundSince }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/requestLoan.ts b/scripts/requestLoan.ts index f5c6bae..602c1f5 100644 --- a/scripts/requestLoan.ts +++ b/scripts/requestLoan.ts @@ -3,21 +3,21 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() - const addressString = await ui.input('treasury\'s friendly address') + const addressString = await ui.input("treasury's friendly address") const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) const roundSince = BigInt(await ui.input('participation round')) const value = toNano(await ui.input('value')) const loanAmount = toNano(await ui.input('loan amount')) - const minPayment = toNano(await ui.input('min payment (default: 0)') || '0') - const validatorRewardShare = BigInt(await ui.input('validator reward share [0-255] (default: 102)') || '102') - const maxFactor = BigInt(await ui.input('max factor (default: 65536)') || '65536') - const adnlAddress = BigInt('0x' + await ui.input('adnl address')) - const validatorPubkey = BigInt('0x' + await ui.input('validator pubkey')) - const signature = BigInt('0x' + await ui.input('signature')) + const minPayment = toNano((await ui.input('min payment (default: 0)')) || '0') + const validatorRewardShare = BigInt((await ui.input('validator reward share [0-255] (default: 102)')) || '102') + const maxFactor = BigInt((await ui.input('max factor (default: 65536)')) || '65536') + const adnlAddress = BigInt('0x' + (await ui.input('adnl address'))) + const validatorPubkey = BigInt('0x' + (await ui.input('validator pubkey'))) + const signature = BigInt('0x' + (await ui.input('signature'))) await treasury.sendRequestLoan(provider.sender(), { value, @@ -31,8 +31,8 @@ export async function run(provider: NetworkProvider) { .storeUint(maxFactor, 32) .storeUint(adnlAddress, 256) .storeRef(beginCell().storeUint(signature, 512)) - .endCell() + .endCell(), }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/sendProcessLoanRequests.ts b/scripts/sendProcessLoanRequests.ts index 91c643d..079bfa0 100644 --- a/scripts/sendProcessLoanRequests.ts +++ b/scripts/sendProcessLoanRequests.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() console.info('Sending process-loan-requests') @@ -11,9 +11,9 @@ export async function run(provider: NetworkProvider) { const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) - const roundSince = BigInt((await ui.input("Enter round since"))) + const roundSince = BigInt(await ui.input('Enter round since')) await treasury.sendSendProcessLoanRequests(provider.sender(), { value: '0.1', roundSince }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/setBalancedRounds.ts b/scripts/setBalancedRounds.ts index 3b6cbb9..cb1ce5b 100644 --- a/scripts/setBalancedRounds.ts +++ b/scripts/setBalancedRounds.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() console.info('Setting balanced-rounds') @@ -11,9 +11,11 @@ export async function run(provider: NetworkProvider) { const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) - const balancedRounds = await ui.choose('Should this treasury use balanced rounds?', [false, true], f => f ? 'Yes' : 'No') + const balancedRounds = await ui.choose('Should this treasury use balanced rounds?', [false, true], (f) => + f ? 'Yes' : 'No' + ) await treasury.sendSetBalancedRounds(provider.sender(), { value: '0.1', newBalancedRounds: balancedRounds }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/setContent.ts b/scripts/setContent.ts index cce5b36..41e4f19 100644 --- a/scripts/setContent.ts +++ b/scripts/setContent.ts @@ -8,9 +8,14 @@ const description = 'Hipo liquid staking protocol' const image = 'https://hipo.finance/hton.png' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() - console.info('Setting metadata to:\n\tname: \t\t%s\n\tdescription: \t%s\n\timage: \t\t%s\n', name, description, image) + console.info( + 'Setting metadata to:\n\tname: \t\t%s\n\tdescription: \t%s\n\timage: \t\t%s\n', + name, + description, + image + ) const addressString = await ui.input('Enter the friendly address of the treasury') const treasuryAddress = Address.parse(addressString) @@ -18,7 +23,7 @@ export async function run(provider: NetworkProvider) { await treasury.sendSetContent(provider.sender(), { value: '0.1', newContent: content }) - ui.write('Done'); + ui.write('Done') } const contentDict = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.Cell()) diff --git a/scripts/setDriver.ts b/scripts/setDriver.ts index 1f5cfa3..7f52d84 100644 --- a/scripts/setDriver.ts +++ b/scripts/setDriver.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() console.info('Setting driver') @@ -16,5 +16,5 @@ export async function run(provider: NetworkProvider) { await treasury.sendSetDriver(provider.sender(), { value: '0.1', newDriver: driverAddress }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/setStopped.ts b/scripts/setStopped.ts index e40e6b5..4a017b6 100644 --- a/scripts/setStopped.ts +++ b/scripts/setStopped.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() console.info('Setting stopped') @@ -11,9 +11,9 @@ export async function run(provider: NetworkProvider) { const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) - const stopped = await ui.choose('Should this treasury be stopped?', [false, true], f => f ? 'Yes' : 'No') + const stopped = await ui.choose('Should this treasury be stopped?', [false, true], (f) => (f ? 'Yes' : 'No')) await treasury.sendSetStopped(provider.sender(), { value: '0.1', newStopped: stopped }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/upgradeCode.ts b/scripts/upgradeCode.ts index 1a55fce..3f5a7e8 100644 --- a/scripts/upgradeCode.ts +++ b/scripts/upgradeCode.ts @@ -3,18 +3,18 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider, compile } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() const newCode = await compile('Treasury') const additionalData = beginCell() console.info() console.info('UPGRADING CODE') - console.info("==============") - console.info("1. Check upgrade_code in treasury.fc before proceeding\n") - console.info("2. Check upgrade_data in treasury.fc before proceeding\n") - console.info("3. Check additional data to be sent alongside the upgrade in this script") - console.info("==============") + console.info('==============') + console.info('1. Check upgrade_code in treasury.fc before proceeding\n') + console.info('2. Check upgrade_data in treasury.fc before proceeding\n') + console.info('3. Check additional data to be sent alongside the upgrade in this script') + console.info('==============') console.info() const addressString = await ui.input('Enter the friendly address of the treasury') @@ -37,5 +37,7 @@ export async function run(provider: NetworkProvider) { await treasury.sendUpgradeCode(provider.sender(), { value: '0.1', newCode, rest: additionalData }) - ui.write('Done'); + ui.write('Done') + + ui.write('\n Remember to log the upgrade date and time: ' + new Date().toISOString()) } diff --git a/scripts/vsetChanged.ts b/scripts/vsetChanged.ts index 09f9eda..0767f10 100644 --- a/scripts/vsetChanged.ts +++ b/scripts/vsetChanged.ts @@ -3,9 +3,9 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() - const addressString = await ui.input('treasury\'s friendly address') + const addressString = await ui.input("treasury's friendly address") const treasuryAddress = Address.parse(addressString) const treasury = provider.open(Treasury.createFromAddress(treasuryAddress)) @@ -13,5 +13,5 @@ export async function run(provider: NetworkProvider) { await treasury.sendVsetChanged({ roundSince }) - ui.write('Done'); + ui.write('Done') } diff --git a/scripts/withdrawSurplus.ts b/scripts/withdrawSurplus.ts index 7d355a6..90f0e27 100644 --- a/scripts/withdrawSurplus.ts +++ b/scripts/withdrawSurplus.ts @@ -3,7 +3,7 @@ import { Treasury } from '../wrappers/Treasury' import { NetworkProvider } from '@ton-community/blueprint' export async function run(provider: NetworkProvider) { - const ui = provider.ui(); + const ui = provider.ui() console.info('Withdraw surplus of treasury') @@ -13,5 +13,5 @@ export async function run(provider: NetworkProvider) { await treasury.sendWithdrawSurplus(provider.sender(), { value: '0.1' }) - ui.write('Done'); + ui.write('Done') } diff --git a/tests/Getters.spec.ts b/tests/Getters.spec.ts new file mode 100644 index 0000000..e870e02 --- /dev/null +++ b/tests/Getters.spec.ts @@ -0,0 +1,171 @@ +import { compile } from '@ton-community/blueprint' +import { Blockchain, SandboxContract, TreasuryContract } from '@ton-community/sandbox' +import '@ton-community/test-utils' +import { beginCell, Cell, Dictionary, toNano } from 'ton-core' +import { bodyOp, logTotalFees } from './helper' +import { op } from '../wrappers/common' +import { Fees, Treasury, participationDictionaryValue, rewardDictionaryValue } from '../wrappers/Treasury' +import { Wallet } from '../wrappers/Wallet' + +describe('Getters', () => { + let treasuryCode: Cell + let walletCode: Cell + let loanCode: Cell + + afterAll(() => { + logTotalFees() + }) + + beforeAll(async () => { + treasuryCode = await compile('Treasury') + walletCode = await compile('Wallet') + loanCode = await compile('Loan') + }) + + let blockchain: Blockchain + let treasury: SandboxContract + let driver: SandboxContract + let halter: SandboxContract + let governor: SandboxContract + let fees: Fees + + beforeEach(async () => { + blockchain = await Blockchain.create() + driver = await blockchain.treasury('driver') + halter = await blockchain.treasury('halter') + governor = await blockchain.treasury('governor') + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) + + const deployer = await blockchain.treasury('deployer') + const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) + + expect(deployResult.transactions).toHaveTransaction({ + from: deployer.address, + to: treasury.address, + value: toNano('0.01'), + body: bodyOp(op.topUp), + deploy: true, + success: true, + outMessagesCount: 0, + }) + expect(deployResult.transactions).toHaveLength(2) + + fees = await treasury.getFees() + + await treasury.sendTopUp(deployer.getSender(), { value: fees.treasuryStorage }) + }) + + it('should deploy treasury', () => { + return + }) + + it('should return max punishment value', async () => { + const maxPunishmentMin = await treasury.getMaxPunishment(1n) + expect(maxPunishmentMin).toBeTonValue('101') + + const maxPunishmentMax = await treasury.getMaxPunishment(5000000000000000000n) + expect(maxPunishmentMax).toBeTonValue('101') + }) + + it('should return jetton data', async () => { + const staker = await blockchain.treasury('staker') + const walletAddress = await treasury.getWalletAddress(staker.address) + const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) + await treasury.sendDepositCoins(staker.getSender(), { value: '10' }) + await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) + const newContent = beginCell().storeUint(0, 9).endCell() + await treasury.sendSetContent(governor.getSender(), { value: '0.1', newContent: newContent }) + + const [totalTokens, mintable, adminAddress, content, code] = await treasury.getJettonData() + expect(totalTokens).toBeBetween('9', '10') + expect(mintable).toEqual(true) + expect(adminAddress.toString()).toEqual('EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c') + expect(content.toBoc().toString('base64')).toEqual(newContent.toBoc().toString('base64')) + expect(code.toBoc().toString('base64')).toEqual(walletCode.toBoc().toString('base64')) + }) + + it('should return wallet data', async () => { + const staker = await blockchain.treasury('staker') + const walletAddress = await treasury.getWalletAddress(staker.address) + const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) + await treasury.sendDepositCoins(staker.getSender(), { value: '10' }) + await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) + + const [tokens, ownerAddress, treasuryAddress, code] = await wallet.getWalletData() + expect(tokens).toBeBetween('9', '10') + expect(ownerAddress.toString()).toEqual(staker.address.toString()) + expect(treasuryAddress.toString()).toEqual(treasury.address.toString()) + expect(code.toBoc().toString('base64')).toEqual(walletCode.toBoc().toString('base64')) + }) + + it('should return treasury state', async () => { + const staker = await blockchain.treasury('staker') + const walletAddress = await treasury.getWalletAddress(staker.address) + const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) + await treasury.sendDepositCoins(staker.getSender(), { value: '10' }) + await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) + const newContent = beginCell().storeUint(0, 9).endCell() + await treasury.sendSetContent(governor.getSender(), { value: '0.1', newContent: newContent }) + + const treasuryState = await treasury.getTreasuryState() + expect(treasuryState.totalCoins).toBeBetween('9', '10') + expect(treasuryState.totalTokens).toBeBetween('9', '10') + expect(treasuryState.totalStaking).toBeTonValue('0') + expect(treasuryState.totalUnstaking).toBeTonValue('0') + expect(treasuryState.totalValidatorsStake).toBeTonValue('0') + expect(treasuryState.participations.keys()).toHaveLength(0) + expect(treasuryState.balancedRounds).toEqual(false) + expect(treasuryState.stopped).toEqual(false) + expect(treasuryState.walletCode.toBoc().toString('base64')).toEqual(walletCode.toBoc().toString('base64')) + expect(treasuryState.loanCode.toBoc().toString('base64')).toEqual(loanCode.toBoc().toString('base64')) + expect(treasuryState.driver.toString()).toEqual(driver.address.toString()) + expect(treasuryState.halter.toString()).toEqual(halter.address.toString()) + expect(treasuryState.governor.toString()).toEqual(governor.address.toString()) + expect(treasuryState.proposedGovernor).toEqual(null) + expect(treasuryState.governanceFee).toEqual(4096n) + expect(treasuryState.rewardsHistory.keys()).toHaveLength(0) + expect(treasuryState.content.toBoc().toString('base64')).toEqual(newContent.toBoc().toString('base64')) + }) + + it('should return wallet state', async () => { + const staker = await blockchain.treasury('staker') + const walletAddress = await treasury.getWalletAddress(staker.address) + const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) + await treasury.sendDepositCoins(staker.getSender(), { value: '10' }) + + const [tokens, staking, unstaking] = await wallet.getWalletState() + expect(tokens).toBeTonValue('0') + expect(staking.keys()).toHaveLength(1) + expect(staking.get(0n)).toBeBetween('9', '10') + expect(unstaking).toBeTonValue('0') + + await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) + const [tokensAfterStake, stakingAfterStake, unstakingAfterStake] = await wallet.getWalletState() + expect(tokensAfterStake).toBeBetween('9', '10') + expect(stakingAfterStake.keys()).toHaveLength(0) + expect(unstakingAfterStake).toBeTonValue('0') + }) +}) diff --git a/tests/Governance.spec.ts b/tests/Governance.spec.ts index 10bad83..437b3ff 100644 --- a/tests/Governance.spec.ts +++ b/tests/Governance.spec.ts @@ -1,20 +1,27 @@ import { compile } from '@ton-community/blueprint' import { Blockchain, SandboxContract, TreasuryContract, createShardAccount } from '@ton-community/sandbox' -import '@ton-community/test-utils' import { Cell, Dictionary, beginCell, toNano } from 'ton-core' import { between, bodyOp, createVset, emptyNewStakeMsg, logTotalFees, accumulateFees, setConfig } from './helper' import { config, op } from '../wrappers/common' -import { Fees, Participation, ParticipationState, Treasury, participationDictionaryValue, rewardDictionaryValue, treasuryConfigToCell } from '../wrappers/Treasury' +import { + Fees, + Participation, + ParticipationState, + Treasury, + participationDictionaryValue, + rewardDictionaryValue, + treasuryConfigToCell, +} from '../wrappers/Treasury' import { Wallet } from '../wrappers/Wallet' describe('Treasury', () => { let treasuryCode: Cell let walletCode: Cell let loanCode: Cell - let onlyUpgradeCode : Cell + let onlyUpgradeCode: Cell let resetDataCode: Cell - afterAll(async () => { + afterAll(() => { logTotalFees() }) @@ -38,25 +45,30 @@ describe('Treasury', () => { driver = await blockchain.treasury('driver') halter = await blockchain.treasury('halter') governor = await blockchain.treasury('governor') - treasury = blockchain.openContract(Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode, - loanCode, - driver: driver.address, - halter: halter.address, - governor: governor.address, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content: Cell.EMPTY, - }, treasuryCode)) + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) const deployer = await blockchain.treasury('deployer') const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) @@ -70,21 +82,22 @@ describe('Treasury', () => { success: true, outMessagesCount: 0, }) - expect(deployResult.transactions).toHaveLength(2); + expect(deployResult.transactions).toHaveLength(2) fees = await treasury.getFees() await treasury.sendTopUp(deployer.getSender(), { value: fees.treasuryStorage }) }) - it('should deploy treasury', async () => { + it('should deploy treasury', () => { + return }) it('should propose governor', async () => { const newGovernor = await blockchain.treasury('newGovernor') const result = await treasury.sendProposeGovernor(governor.getSender(), { value: '0.1', - newGovernor: newGovernor.address + newGovernor: newGovernor.address, }) expect(result.transactions).toHaveTransaction({ @@ -106,7 +119,7 @@ describe('Treasury', () => { expect(result.transactions).toHaveLength(3) const treasuryState = await treasury.getTreasuryState() - const proposedGovernor = (treasuryState.proposedGovernor || Cell.EMPTY).beginParse() + const proposedGovernor = (treasuryState.proposedGovernor ?? Cell.EMPTY).beginParse() const after = Math.floor(Date.now() / 1000) + 60 * 60 * 24 expect(Math.abs(proposedGovernor.loadUint(32) - after) <= 1).toBeTruthy() expect(proposedGovernor.loadAddress().equals(newGovernor.address)).toBeTruthy() @@ -120,18 +133,18 @@ describe('Treasury', () => { await treasury.sendProposeGovernor(governor.getSender(), { value: '0.1', newGovernor: newGovernor.address }) const before = Math.floor(Date.now() / 1000) - 60 * 60 * 24 const state = await treasury.getTreasuryState() - state.proposedGovernor = beginCell() - .storeUint(before, 32) - .storeAddress(newGovernor.address) - .endCell() + state.proposedGovernor = beginCell().storeUint(before, 32).storeAddress(newGovernor.address).endCell() const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10'), + }), + ) const result = await treasury.sendAcceptGovernance(newGovernor.getSender(), { value: '0.1' }) expect(result.transactions).toHaveTransaction({ @@ -163,7 +176,7 @@ describe('Treasury', () => { const newHalter = await blockchain.treasury('newHalter') const result = await treasury.sendSetHalter(governor.getSender(), { value: '0.1', - newHalter: newHalter.address + newHalter: newHalter.address, }) expect(result.transactions).toHaveTransaction({ @@ -395,7 +408,7 @@ describe('Treasury', () => { it('should set balanced-rounds', async () => { const result = await treasury.sendSetBalancedRounds(governor.getSender(), { value: '0.1', - newBalancedRounds: true + newBalancedRounds: true, }) expect(result.transactions).toHaveTransaction({ @@ -425,10 +438,7 @@ describe('Treasury', () => { it('should send message to loan', async () => { const validator = await blockchain.treasury('validator') const loanAddress = await treasury.getLoanAddress(validator.address, 0n) - const message = beginCell() - .storeUint(op.sendRecoverStake, 32) - .storeUint(1, 64) - .endCell() + const message = beginCell().storeUint(op.sendRecoverStake, 32).storeUint(1, 64).endCell() const result = await treasury.sendSendMessageToLoan(halter.getSender(), { value: '1', validator: validator.address, @@ -464,13 +474,16 @@ describe('Treasury', () => { } state.participations.set(0n, participation) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10'), + }), + ) const result = await treasury.sendSendProcessLoanRequests(halter.getSender(), { value: '1', @@ -496,13 +509,43 @@ describe('Treasury', () => { it('should upgrade code', async () => { const oldState = await treasury.getState() const someone = await blockchain.treasury('someone') - const result1 = await treasury.sendUpgradeCode(governor.getSender(), { + + // Reject upgrade since not sent by governor + const result1 = await treasury.sendUpgradeCode(someone.getSender(), { value: '0.1', newCode: onlyUpgradeCode, - rest: beginCell().storeAddress(someone.address) }) - expect(result1.transactions).toHaveTransaction({ + from: someone.address, + to: treasury.address, + value: toNano('0.1'), + body: bodyOp(op.upgradeCode), + success: false, + outMessagesCount: 1, + }) + + // Reject upgrade since governor is not the same after upgrade + const result2 = await treasury.sendUpgradeCode(governor.getSender(), { + value: '0.1', + newCode: onlyUpgradeCode, + rest: beginCell().storeAddress(someone.address), + }) + expect(result2.transactions).toHaveTransaction({ + from: governor.address, + to: treasury.address, + value: toNano('0.1'), + body: bodyOp(op.upgradeCode), + success: false, + outMessagesCount: 1, + }) + + const result3 = await treasury.sendUpgradeCode(governor.getSender(), { + value: '0.1', + newCode: onlyUpgradeCode, + rest: beginCell().storeAddress(governor.address), + }) + + expect(result3.transactions).toHaveTransaction({ from: governor.address, to: treasury.address, value: toNano('0.1'), @@ -510,7 +553,7 @@ describe('Treasury', () => { success: true, outMessagesCount: 1, }) - expect(result1.transactions).toHaveTransaction({ + expect(result3.transactions).toHaveTransaction({ from: treasury.address, to: governor.address, value: between('0', '0.1'), @@ -518,11 +561,11 @@ describe('Treasury', () => { success: true, outMessagesCount: 0, }) - expect(result1.transactions).toHaveLength(3) + expect(result3.transactions).toHaveLength(3) - const result2 = await treasury.sendDepositCoins(someone.getSender(), { value: '10' }) - expect(result2.transactions).toHaveTransaction({ - from: someone.address, + const result4 = await treasury.sendDepositCoins(governor.getSender(), { value: '10' }) + expect(result4.transactions).toHaveTransaction({ + from: governor.address, to: treasury.address, value: toNano('10'), body: bodyOp(op.depositCoins), @@ -530,32 +573,32 @@ describe('Treasury', () => { outMessagesCount: 1, }) - const result3 = await treasury.sendUpgradeCode(someone.getSender(), { + const result5 = await treasury.sendUpgradeCode(governor.getSender(), { value: '0.1', newCode: resetDataCode, }) - expect(result3.transactions).toHaveTransaction({ - from: someone.address, + expect(result5.transactions).toHaveTransaction({ + from: governor.address, to: treasury.address, value: toNano('0.1'), body: bodyOp(op.upgradeCode), success: true, outMessagesCount: 1, }) - expect(result3.transactions).toHaveTransaction({ + expect(result5.transactions).toHaveTransaction({ from: treasury.address, - to: someone.address, + to: governor.address, value: between('0', '0.1'), body: bodyOp(op.gasExcess), success: true, outMessagesCount: 0, }) - expect(result3.transactions).toHaveLength(3) + expect(result5.transactions).toHaveLength(3) - const result4 = await treasury.sendDepositCoins(someone.getSender(), { value: '10' }) - expect(result4.transactions).toHaveTransaction({ - from: someone.address, + const result6 = await treasury.sendDepositCoins(governor.getSender(), { value: '10' }) + expect(result6.transactions).toHaveTransaction({ + from: governor.address, to: treasury.address, value: toNano('10'), body: bodyOp(op.depositCoins), @@ -563,12 +606,12 @@ describe('Treasury', () => { outMessagesCount: 1, }) - const result5 = await treasury.sendUpgradeCode(governor.getSender(), { + const result7 = await treasury.sendUpgradeCode(governor.getSender(), { value: '0.1', newCode: treasuryCode, }) - expect(result5.transactions).toHaveTransaction({ + expect(result7.transactions).toHaveTransaction({ from: governor.address, to: treasury.address, value: toNano('0.1'), @@ -576,7 +619,7 @@ describe('Treasury', () => { success: true, outMessagesCount: 1, }) - expect(result5.transactions).toHaveTransaction({ + expect(result7.transactions).toHaveTransaction({ from: treasury.address, to: governor.address, value: between('0', '0.1'), @@ -584,20 +627,21 @@ describe('Treasury', () => { success: true, outMessagesCount: 0, }) - expect(result5.transactions).toHaveLength(3) + expect(result7.transactions).toHaveLength(3) const newState = await treasury.getState() expect(oldState.state.type === 'active').toBeTruthy() expect(oldState.state.type == newState.state.type).toBeTruthy() if (oldState.state.type === 'active' && newState.state.type === 'active') { - expect(oldState.state.data?.toString() === newState.state.data?.toString()).toBeTruthy() + expect(oldState.state.data?.toString('base64') === newState.state.data?.toString('base64')).toBeTruthy() } accumulateFees(result1.transactions) - accumulateFees(result2.transactions) accumulateFees(result3.transactions) accumulateFees(result4.transactions) accumulateFees(result5.transactions) + accumulateFees(result6.transactions) + accumulateFees(result7.transactions) }) it('should withdraw surplus', async () => { @@ -626,13 +670,16 @@ describe('Treasury', () => { state.totalUnstaking = toNano('200000') state.totalValidatorsStake = toNano('300000') const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10') + toNano('801000') + 16n * toNano('0.9') + toNano('20'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10') + toNano('801000') + 16n * toNano('0.9') + toNano('20'), + }), + ) const result = await treasury.sendWithdrawSurplus(governor.getSender(), { value: '0.1' }) expect(result.transactions).toHaveTransaction({ diff --git a/tests/Large.spec.ts b/tests/Large.spec.ts index 8725cfe..7875ef8 100644 --- a/tests/Large.spec.ts +++ b/tests/Large.spec.ts @@ -1,21 +1,26 @@ import { compile } from '@ton-community/blueprint' import { Blockchain, SandboxContract, TreasuryContract, createShardAccount } from '@ton-community/sandbox' -import '@ton-community/test-utils' -import { Address, Cell, Dictionary, beginCell, toNano } from 'ton-core' -import { bodyOp, createVset, emptyNewStakeMsg, getElector, logTotalFees, accumulateFees, setConfig, between, logComputeGas, createNewStakeMsg } from './helper' +import { Cell, Dictionary, beginCell, toNano } from 'ton-core' +import { bodyOp, createVset, emptyNewStakeMsg, logTotalFees, accumulateFees, setConfig } from './helper' import { config, op } from '../wrappers/common' -import { Fees, Participation, ParticipationState, Treasury, participationDictionaryValue, requestDictionaryValue, rewardDictionaryValue, sortedDictionaryValue, treasuryConfigToCell } from '../wrappers/Treasury' -import { Loan } from '../wrappers/Loan' -import { Wallet } from '../wrappers/Wallet' -import { createElectionConfig, electorConfigToCell } from '../wrappers/elector-test/Elector' +import { + Fees, + Participation, + ParticipationState, + Treasury, + participationDictionaryValue, + requestDictionaryValue, + rewardDictionaryValue, + sortedDictionaryValue, + treasuryConfigToCell, +} from '../wrappers/Treasury' describe('Large number of loan requests', () => { let treasuryCode: Cell let walletCode: Cell let loanCode: Cell - let electorCode: Cell - afterAll(async () => { + afterAll(() => { logTotalFees() }) @@ -23,7 +28,6 @@ describe('Large number of loan requests', () => { treasuryCode = await compile('Treasury') walletCode = await compile('Wallet') loanCode = await compile('Loan') - electorCode = await compile('elector-test/Elector') }) let blockchain: Blockchain @@ -32,32 +36,36 @@ describe('Large number of loan requests', () => { let halter: SandboxContract let governor: SandboxContract let fees: Fees - let electorAddress: Address beforeEach(async () => { blockchain = await Blockchain.create() driver = await blockchain.treasury('driver') halter = await blockchain.treasury('halter') governor = await blockchain.treasury('governor') - treasury = blockchain.openContract(Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode, - loanCode, - driver: driver.address, - halter: halter.address, - governor: governor.address, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content: Cell.EMPTY, - }, treasuryCode)) + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) const deployer = await blockchain.treasury('deployer') const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) @@ -71,16 +79,15 @@ describe('Large number of loan requests', () => { success: true, outMessagesCount: 0, }) - expect(deployResult.transactions).toHaveLength(2); + expect(deployResult.transactions).toHaveLength(2) fees = await treasury.getFees() await treasury.sendTopUp(deployer.getSender(), { value: fees.treasuryStorage }) - - electorAddress = getElector(blockchain) }) - it('should deploy treasury', async () => { + it('should deploy treasury', () => { + return }) it('should send a big batch of messages to recover stakes', async () => { @@ -113,13 +120,16 @@ describe('Large number of loan requests', () => { const state = await treasury.getTreasuryState() state.participations.set(until1, participation) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10') + toNano('1') * count, - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10') + toNano('1') * count, + }), + ) const result = await treasury.sendFinishParticipation({ roundSince: until1 }) @@ -135,11 +145,7 @@ describe('Large number of loan requests', () => { }) it('should handle large number of loan requests', async () => { - const maxValidators = beginCell() - .storeUint(65535, 16) - .storeUint(65535, 16) - .storeUint(65535, 16) - .endCell() + const maxValidators = beginCell().storeUint(65535, 16).storeUint(65535, 16).storeUint(65535, 16).endCell() setConfig(blockchain, config.validators, maxValidators) const times = await treasury.getTimes() @@ -190,13 +196,16 @@ describe('Large number of loan requests', () => { state.participations.set(until1, participation) state.totalValidatorsStake = toNano('1000') * (count1 + count2 + count3) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10') + toNano('1001.72') * (count1 + count2 + count3) + toNano('300000') * count3, - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10') + toNano('1001.72') * (count1 + count2 + count3) + toNano('300000') * count3, + }), + ) const since2 = BigInt(Math.floor(Date.now() / 1000)) - times.participateSince + times.currentRoundSince const until2 = since2 + electedFor @@ -206,8 +215,8 @@ describe('Large number of loan requests', () => { let sendNewStakeCount = 0n let requestRejectedCount = 0n - for (let i = 0; i < result.transactions.length; i += 1) { - const bodyOp = result.transactions[i].inMessage?.body.beginParse().loadUint(32) + for (const transaction of result.transactions) { + const bodyOp = transaction.inMessage?.body.beginParse().loadUint(32) if (bodyOp === op.sendNewStake) { sendNewStakeCount += 1n } else if (bodyOp === op.requestRejected) { diff --git a/tests/Loan.spec.ts b/tests/Loan.spec.ts index c33e9f5..0283236 100644 --- a/tests/Loan.spec.ts +++ b/tests/Loan.spec.ts @@ -1,11 +1,31 @@ import { compile } from '@ton-community/blueprint' import { Blockchain, SandboxContract, TreasuryContract, createShardAccount } from '@ton-community/sandbox' -import '@ton-community/test-utils' import { Address, Cell, Dictionary, beginCell, toNano } from 'ton-core' -import { between, bodyOp, createNewStakeMsg, createVset, emptyNewStakeMsg, getElector, logTotalFees, accumulateFees, setConfig, logComputeGas } from './helper' +import { + between, + bodyOp, + createNewStakeMsg, + createVset, + emptyNewStakeMsg, + getElector, + logTotalFees, + accumulateFees, + setConfig, + logComputeGas, +} from './helper' import { config, op } from '../wrappers/common' import { Loan } from '../wrappers/Loan' -import { Fees, Participation, ParticipationState, Treasury, participationDictionaryValue, requestDictionaryValue, rewardDictionaryValue, sortedDictionaryValue, treasuryConfigToCell } from '../wrappers/Treasury' +import { + Fees, + Participation, + ParticipationState, + Treasury, + participationDictionaryValue, + requestDictionaryValue, + rewardDictionaryValue, + sortedDictionaryValue, + treasuryConfigToCell, +} from '../wrappers/Treasury' import { Wallet } from '../wrappers/Wallet' import { createElectionConfig, electorConfigToCell } from '../wrappers/elector-test/Elector' @@ -15,7 +35,7 @@ describe('Loan', () => { let loanCode: Cell let electorCode: Cell - afterAll(async () => { + afterAll(() => { logTotalFees() }) @@ -39,25 +59,30 @@ describe('Loan', () => { driver = await blockchain.treasury('driver') halter = await blockchain.treasury('halter') governor = await blockchain.treasury('governor') - treasury = blockchain.openContract(Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode, - loanCode, - driver: driver.address, - halter: halter.address, - governor: governor.address, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content: Cell.EMPTY, - }, treasuryCode)) + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) const deployer = await blockchain.treasury('deployer') const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) @@ -71,7 +96,7 @@ describe('Loan', () => { success: true, outMessagesCount: 0, }) - expect(deployResult.transactions).toHaveLength(2); + expect(deployResult.transactions).toHaveLength(2) fees = await treasury.getFees() @@ -80,7 +105,8 @@ describe('Loan', () => { electorAddress = getElector(blockchain) }) - it('should deploy treasury', async () => { + it('should deploy treasury', () => { + return }) it('should save a loan request', async () => { @@ -137,13 +163,16 @@ describe('Loan', () => { const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -298,13 +327,16 @@ describe('Loan', () => { const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -382,10 +414,7 @@ describe('Loan', () => { // await treasury.sendVsetChanged({ roundSince: until1 }) await treasury.sendMessage(driver.getSender(), { value: '0.1', - body: beginCell() - .storeUint(op.vsetChanged, 32) - .storeUint(until1, 32) - .endCell() + body: beginCell().storeUint(op.vsetChanged, 32).storeUint(until1, 32).endCell(), }) fail() } catch (e) { @@ -419,13 +448,16 @@ describe('Loan', () => { const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -473,13 +505,16 @@ describe('Loan', () => { const credits = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.BigVarUint(4)) credits.set(BigInt('0x' + loan2.address.toRawString().split(':')[1]), toNano('350260')) credits.set(BigInt('0x' + loan3.address.toRawString().split(':')[1]), toNano('350270')) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }), credits }), - balance: toNano('350260') + toNano('350270') + toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }), credits }), + balance: toNano('350260') + toNano('350270') + toNano('1'), + }), + ) const vset3 = createVset(0n, 1n) setConfig(blockchain, config.currentValidators, vset3) @@ -490,17 +525,20 @@ describe('Loan', () => { await treasury.sendVsetChanged({ roundSince: until1 }) const state = await treasury.getTreasuryState() - const participation = state.participations.get(until1) || {} + const participation = state.participations.get(until1) ?? {} participation.stakeHeldUntil = 0n // set stake_held_until to zero state.participations.set(until1, participation) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10'), + }), + ) const result = await treasury.sendFinishParticipation({ roundSince: until1 }) expect(result.transactions).toHaveTransaction({ @@ -567,7 +605,7 @@ describe('Loan', () => { outMessagesCount: 1, }) expect(result.transactions).toHaveTransaction({ - from:loan2.address, + from: loan2.address, to: treasury.address, value: between('350261', '350262'), body: bodyOp(op.recoverStakeResult), @@ -575,7 +613,7 @@ describe('Loan', () => { outMessagesCount: 2, }) expect(result.transactions).toHaveTransaction({ - from:loan3.address, + from: loan3.address, to: treasury.address, value: between('350271', '350272'), body: bodyOp(op.recoverStakeResult), @@ -647,13 +685,16 @@ describe('Loan', () => { const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: 0n }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: 0n }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -839,13 +880,16 @@ describe('Loan', () => { const vset1 = createVset(since1, until1) setConfig(blockchain, config.currentValidators, vset1) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: 0n }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: 0n }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -969,13 +1013,16 @@ describe('Loan', () => { await treasury.sendSetBalancedRounds(halter.getSender(), { value: '0.1', newBalancedRounds: true }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), + balance: toNano('1'), + }), + ) const validator1 = await blockchain.treasury('validator1') const validator2 = await blockchain.treasury('validator2') @@ -1113,13 +1160,16 @@ describe('Loan', () => { const wallet = blockchain.openContract(Wallet.createFromAddress(walletAddress)) await wallet.sendStakeCoins(driver.getSender(), { value: '0.1', roundSince: 0n }) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), - balance: toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }) }), + balance: toNano('1'), + }), + ) const validator = await blockchain.treasury('validator') const loanAddress = await treasury.getLoanAddress(validator.address, until1) @@ -1152,13 +1202,16 @@ describe('Loan', () => { const credits = Dictionary.empty(Dictionary.Keys.BigUint(256), Dictionary.Values.BigVarUint(4)) credits.set(BigInt('0x' + loan.address.toRawString().split(':')[1]), toNano('350260')) - await blockchain.setShardAccount(electorAddress, createShardAccount({ - workchain: -1, - address: electorAddress, - code: electorCode, - data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }), credits }), - balance: toNano('350260') + toNano('350270') + toNano('1'), - })) + await blockchain.setShardAccount( + electorAddress, + createShardAccount({ + workchain: -1, + address: electorAddress, + code: electorCode, + data: electorConfigToCell({ currentElection: createElectionConfig({ electAt: until1 }), credits }), + balance: toNano('350260') + toNano('350270') + toNano('1'), + }), + ) const vset3 = createVset(0n, 1n) setConfig(blockchain, config.currentValidators, vset3) @@ -1173,17 +1226,20 @@ describe('Loan', () => { expect(result4.transactions).toHaveLength(1) const state = await treasury.getTreasuryState() - const participation = state.participations.get(until1) || {} + const participation = state.participations.get(until1) ?? {} participation.stakeHeldUntil = 0n // set stake_held_until to zero state.participations.set(until1, participation) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('10'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('10'), + }), + ) const result5 = await treasury.sendFinishParticipation({ roundSince: until1 }) expect(result5.transactions).toHaveLength(8) @@ -1211,11 +1267,7 @@ describe('Loan', () => { it('should handle loan request edge cases', async () => { const count = 10n - const maxValidators = beginCell() - .storeUint(count, 16) - .storeUint(count, 16) - .storeUint(count, 16) - .endCell() + const maxValidators = beginCell().storeUint(count, 16).storeUint(count, 16).storeUint(count, 16).endCell() setConfig(blockchain, config.validators, maxValidators) const times = await treasury.getTimes() @@ -1253,13 +1305,16 @@ describe('Loan', () => { state1.balancedRounds = true state1.totalValidatorsStake = toNano('1000') * count const fakeData1 = treasuryConfigToCell(state1) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData1, - balance: toNano('10') + toNano('1001.72') * count, - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData1, + balance: toNano('10') + toNano('1001.72') * count, + }), + ) const validator = await blockchain.treasury('validator') const result1 = await treasury.sendRequestLoan(validator.getSender(), { diff --git a/tests/Text.spec.ts b/tests/Text.spec.ts index cf17d42..e983236 100644 --- a/tests/Text.spec.ts +++ b/tests/Text.spec.ts @@ -12,7 +12,7 @@ describe('Text Interface', () => { let walletCode: Cell let loanCode: Cell - afterAll(async () => { + afterAll(() => { logCodeSizes(treasuryCode, walletCode, loanCode) logTotalFees() }) @@ -35,25 +35,30 @@ describe('Text Interface', () => { driver = await blockchain.treasury('driver') halter = await blockchain.treasury('halter') governor = await blockchain.treasury('governor') - treasury = blockchain.openContract(Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode, - loanCode, - driver: driver.address, - halter: halter.address, - governor: governor.address, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content: Cell.EMPTY, - }, treasuryCode)) + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) const deployer = await blockchain.treasury('deployer') const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) @@ -67,14 +72,15 @@ describe('Text Interface', () => { success: true, outMessagesCount: 0, }) - expect(deployResult.transactions).toHaveLength(2); + expect(deployResult.transactions).toHaveLength(2) fees = await treasury.getFees() await treasury.sendTopUp(deployer.getSender(), { value: fees.treasuryStorage }) }) - it('should deploy treasury', async () => { + it('should deploy treasury', () => { + return }) it('should deposit coins for comment d', async () => { @@ -120,7 +126,7 @@ describe('Text Interface', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage, '0.1') expect(tokens).toBeTonValue('0') expect(staking.keys()).toHaveLength(1) @@ -197,7 +203,7 @@ describe('Text Interface', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeTonValue(treasuryState.totalTokens) expect(staking.keys()).toHaveLength(0) @@ -267,7 +273,7 @@ describe('Text Interface', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeTonValue('0') expect(staking.keys()).toHaveLength(0) @@ -338,7 +344,7 @@ describe('Text Interface', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeBetween('2.8', '2.9') expect(staking.keys()).toHaveLength(0) diff --git a/tests/Wallet.spec.ts b/tests/Wallet.spec.ts index 335a560..297d6d2 100644 --- a/tests/Wallet.spec.ts +++ b/tests/Wallet.spec.ts @@ -4,7 +4,14 @@ import '@ton-community/test-utils' import { Cell, Dictionary, beginCell, toNano } from 'ton-core' import { between, bodyOp, logComputeGas, logTotalFees, accumulateFees } from './helper' import { op } from '../wrappers/common' -import { Fees, ParticipationState, Treasury, participationDictionaryValue, rewardDictionaryValue, treasuryConfigToCell } from '../wrappers/Treasury' +import { + Fees, + ParticipationState, + Treasury, + participationDictionaryValue, + rewardDictionaryValue, + treasuryConfigToCell, +} from '../wrappers/Treasury' import { Wallet } from '../wrappers/Wallet' describe('Wallet', () => { @@ -12,7 +19,7 @@ describe('Wallet', () => { let walletCode: Cell let loanCode: Cell - afterAll(async () => { + afterAll(() => { logTotalFees() }) @@ -34,25 +41,30 @@ describe('Wallet', () => { driver = await blockchain.treasury('driver') halter = await blockchain.treasury('halter') governor = await blockchain.treasury('governor') - treasury = blockchain.openContract(Treasury.createFromConfig({ - totalCoins: 0n, - totalTokens: 0n, - totalStaking: 0n, - totalUnstaking: 0n, - totalValidatorsStake: 0n, - participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), - balancedRounds: false, - stopped: false, - walletCode, - loanCode, - driver: driver.address, - halter: halter.address, - governor: governor.address, - proposedGovernor: null, - governanceFee: 4096n, - rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), - content: Cell.EMPTY, - }, treasuryCode)) + treasury = blockchain.openContract( + Treasury.createFromConfig( + { + totalCoins: 0n, + totalTokens: 0n, + totalStaking: 0n, + totalUnstaking: 0n, + totalValidatorsStake: 0n, + participations: Dictionary.empty(Dictionary.Keys.BigUint(32), participationDictionaryValue), + balancedRounds: false, + stopped: false, + walletCode, + loanCode, + driver: driver.address, + halter: halter.address, + governor: governor.address, + proposedGovernor: null, + governanceFee: 4096n, + rewardsHistory: Dictionary.empty(Dictionary.Keys.BigUint(32), rewardDictionaryValue), + content: Cell.EMPTY, + }, + treasuryCode, + ), + ) const deployer = await blockchain.treasury('deployer') const deployResult = await treasury.sendDeploy(deployer.getSender(), { value: '0.01' }) @@ -66,14 +78,15 @@ describe('Wallet', () => { success: true, outMessagesCount: 0, }) - expect(deployResult.transactions).toHaveLength(2); + expect(deployResult.transactions).toHaveLength(2) fees = await treasury.getFees() await treasury.sendTopUp(deployer.getSender(), { value: fees.treasuryStorage }) }) - it('should deploy treasury', async () => { + it('should deploy treasury', () => { + return }) it('should deposit coins', async () => { @@ -119,7 +132,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage, '0.1') expect(tokens).toBeTonValue('0') expect(staking.keys()).toHaveLength(1) @@ -173,7 +186,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage, '0.1') expect(tokens).toBeTonValue('0') expect(staking.keys()).toHaveLength(1) @@ -228,7 +241,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage, '0.1') expect(tokens).toBeTonValue('0') expect(staking.keys()).toHaveLength(1) @@ -297,7 +310,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeTonValue(treasuryState.totalTokens) expect(staking.keys()).toHaveLength(0) @@ -370,14 +383,14 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const wallet1Balance = await wallet1.getBalance() - const [ tokens1, staking1, unstaking1 ] = await wallet1.getWalletState() + const [tokens1, staking1, unstaking1] = await wallet1.getWalletState() expect(wallet1Balance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens1).toBeBetween('0.8', '0.9') expect(staking1.keys()).toHaveLength(0) expect(unstaking1).toBeTonValue('0') const wallet2Balance = await wallet2.getBalance() - const [ tokens2, staking2, unstaking2 ] = await wallet2.getWalletState() + const [tokens2, staking2, unstaking2] = await wallet2.getWalletState() expect(wallet2Balance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens2).toBeTonValue('9') expect(staking2.keys()).toHaveLength(0) @@ -451,14 +464,14 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const wallet1Balance = await wallet1.getBalance() - const [ tokens1, staking1, unstaking1 ] = await wallet1.getWalletState() + const [tokens1, staking1, unstaking1] = await wallet1.getWalletState() expect(wallet1Balance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens1).toBeBetween('0.8', '0.9') expect(staking1.keys()).toHaveLength(0) expect(unstaking1).toBeTonValue('0') const wallet2Balance = await wallet2.getBalance() - const [ tokens2, staking2, unstaking2 ] = await wallet2.getWalletState() + const [tokens2, staking2, unstaking2] = await wallet2.getWalletState() expect(wallet2Balance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens2).toBeBetween('13.8', '13.9') expect(staking2.keys()).toHaveLength(0) @@ -522,7 +535,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeBetween('2.8', '2.9') expect(staking.keys()).toHaveLength(0) @@ -586,7 +599,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeTonValue(treasuryState.totalTokens) expect(staking.keys()).toHaveLength(0) @@ -645,13 +658,16 @@ describe('Wallet', () => { const fakeParticipation = { state: ParticipationState.Staked } state.participations.set(roundSince, fakeParticipation) const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: await treasury.getBalance(), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: await treasury.getBalance(), + }), + ) const staker = await blockchain.treasury('staker') await treasury.sendDepositCoins(staker.getSender(), { value: '10' }) const walletAddress = await treasury.getWalletAddress(staker.address) @@ -702,7 +718,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeTonValue(treasuryState.totalTokens) expect(staking.keys()).toHaveLength(1) @@ -721,13 +737,16 @@ describe('Wallet', () => { await wallet.sendUnstakeTokens(staker.getSender(), { value: '0.2', tokens: '7' }) const state = await treasury.getTreasuryState() const fakeData = treasuryConfigToCell(state) - await blockchain.setShardAccount(treasury.address, createShardAccount({ - workchain: 0, - address: treasury.address, - code: treasuryCode, - data: fakeData, - balance: toNano('5') + toNano('10'), - })) + await blockchain.setShardAccount( + treasury.address, + createShardAccount({ + workchain: 0, + address: treasury.address, + code: treasuryCode, + data: fakeData, + balance: toNano('5') + toNano('10'), + }), + ) const result = await wallet.sendWithdrawTokens(staker.getSender(), { value: '0.1' }) expect(result.transactions).toHaveTransaction({ @@ -774,7 +793,7 @@ describe('Wallet', () => { expect(treasuryState.totalValidatorsStake).toBeTonValue('0') const walletBalance = await wallet.getBalance() - const [ tokens, staking, unstaking ] = await wallet.getWalletState() + const [tokens, staking, unstaking] = await wallet.getWalletState() expect(walletBalance).toBeBetween(fees.walletStorage - 1n, fees.walletStorage) expect(tokens).toBeBetween('2.8', '2.9') expect(staking.keys()).toHaveLength(0) diff --git a/tests/helper.ts b/tests/helper.ts index fb93333..aabc8d4 100644 --- a/tests/helper.ts +++ b/tests/helper.ts @@ -1,5 +1,5 @@ -import { expect } from '@jest/globals' -import { Blockchain, BlockchainTransaction, printTransactionFees } from '@ton-community/sandbox' +/* eslint-disable @typescript-eslint/no-unnecessary-condition */ +import { Blockchain, BlockchainTransaction } from '@ton-community/sandbox' import type { MatcherFunction } from 'expect' import { Address, Builder, Cell, Dictionary, beginCell, fromNano, toNano } from 'ton-core' import { mnemonicNew, mnemonicToPrivateKey, sign } from 'ton-crypto' @@ -28,71 +28,52 @@ export function between(a: bigint | string, b: bigint | string): (x?: bigint) => } } -export const toBeBetween: MatcherFunction<[a: unknown, b: unknown]> = - function (actual, a, b) { - if ( - (typeof a !== 'bigint' && typeof a !== 'string') || - (typeof b !== 'bigint' && typeof b !== 'string') || - typeof actual !== 'bigint' - ) { - throw new Error('invalid type') - } - - const pass = between(a, b)(actual) - if (pass) { - return { - message: () => - `expected ${this.utils.printReceived(actual)} not to be between ${this.utils.printExpected( - `[${a}, ${b}]` - )}`, - pass: true, - } - } else { - return { - message: () => - `expected ${this.utils.printReceived(actual)} to be between ${this.utils.printExpected( - `[${a}, ${b}]` - )}`, - pass: false, - } - } +export const toBeBetween: MatcherFunction<[a: unknown, b: unknown]> = function (actual, a, b) { + if ( + (typeof a !== 'bigint' && typeof a !== 'string') || + (typeof b !== 'bigint' && typeof b !== 'string') || + typeof actual !== 'bigint' + ) { + throw new Error('invalid type') } -export const toBeTonValue: MatcherFunction<[v: unknown]> = - function (actual, v) { - v = typeof v === 'string' ? toNano(v) : v - if (typeof v !== 'bigint' || typeof actual !== 'bigint') { - throw new Error('invalid type') + const pass = between(a, b)(actual) + if (pass) { + return { + message: () => + `expected ${this.utils.printReceived(actual)} not to be between ${this.utils.printExpected( + `[${a}, ${b}]`, + )}`, + pass: true, } - const pass = actual === v - if (pass) { - return { - message: () => - `expected ${this.utils.printReceived(actual)} not to be ${this.utils.printExpected(v)} nanoTON`, - pass: true, - } - } else { - return { - message: () => - `expected ${this.utils.printReceived(actual)} to be ${this.utils.printExpected(v)} nanoTON`, - pass: false, - } + } else { + return { + message: () => + `expected ${this.utils.printReceived(actual)} to be between ${this.utils.printExpected( + `[${a}, ${b}]`, + )}`, + pass: false, } } +} -expect.extend({ - toBeBetween, - toBeTonValue, -}) - -declare module 'expect' { - interface AsymmetricMatchers { - toBeBetween(a: bigint | string, b: bigint | string): void - toBeTonValue(v: bigint | string): void +export const toBeTonValue: MatcherFunction<[v: unknown]> = function (actual, v) { + v = typeof v === 'string' ? toNano(v) : v + if (typeof v !== 'bigint' || typeof actual !== 'bigint') { + throw new Error('invalid type') } - interface Matchers { - toBeBetween(a: bigint | string, b: bigint | string): R - toBeTonValue(v: bigint | string): R + const pass = actual === v + if (pass) { + return { + message: () => + `expected ${this.utils.printReceived(actual)} not to be ${this.utils.printExpected(v)} nanoTON`, + pass: true, + } + } else { + return { + message: () => `expected ${this.utils.printReceived(actual)} to be ${this.utils.printExpected(v)} nanoTON`, + pass: false, + } } } @@ -115,7 +96,7 @@ export async function createNewStakeMsg(loanAddress: Address, roundSince: bigint .storeBuffer(loanAddress.hash, 32) // 256 bits .storeBuffer(adnl.publicKey, 32) // 256 bits .endCell() - const signature = sign(confirmation.bits.subbuffer(0, 608) || Buffer.from(''), keypair.secretKey) + const signature = sign(confirmation.bits.subbuffer(0, 608) ?? Buffer.from(''), keypair.secretKey) return beginCell() .storeBuffer(keypair.publicKey, 32) // 256 bits .storeUint(roundSince, 32) @@ -130,8 +111,8 @@ export function createVset(since: bigint, until: bigint, total?: bigint, main?: .storeUint(0x12, 8) .storeUint(since, 32) .storeUint(until, 32) - .storeUint(total || 1n, 16) - .storeUint(main || 1n, 16) + .storeUint(total ?? 1n, 16) + .storeUint(main ?? 1n, 16) .storeMaybeRef(list) .endCell() } @@ -147,11 +128,11 @@ export function setConfig(blockchain: Blockchain, index: bigint, value: Cell) { export function getElector(blockchain: Blockchain): Address { const config = Dictionary.loadDirect(Dictionary.Keys.BigInt(32), Dictionary.Values.Cell(), blockchain.config) - const electorAddr = config.get(1n)?.beginParse().loadUintBig(256) || 0n + const electorAddr = config.get(1n)?.beginParse().loadUintBig(256) ?? 0n return Address.parseRaw('-1:' + electorAddr.toString(16)) } -export let totalFees: bigint = 0n +export let totalFees = 0n export function accumulateFees(transactions: BlockchainTransaction[]) { totalFees = transactions.reduce((acc, tx) => acc + tx.totalFees.coins, totalFees) @@ -173,16 +154,16 @@ export function logCodeSizes(treasuryCode: Cell, walletCode: Cell, loanCode: Cel } export function logComputeGas(opLabel: string, opCode: number, tx: BlockchainTransaction) { - if (! bodyOp(opCode)(tx.inMessage?.body || Cell.EMPTY)) { - throw 'invalida transaction to log compute gas for op ' + opLabel + if (!bodyOp(opCode)(tx.inMessage?.body ?? Cell.EMPTY)) { + throw new Error('invalida transaction to log compute gas for op ' + opLabel) } const logs = tx.blockchainLogs const usedIndex = logs.indexOf('used=') const commaIndex = logs.indexOf(',', usedIndex) const usedGas = logs.substring(usedIndex + 5, commaIndex) - const roundedGas = Math.ceil(parseInt(usedGas, 10) / 1000 * 1.2) * 1000 + const roundedGas = Math.ceil((parseInt(usedGas, 10) / 1000) * 1.2) * 1000 if (logs.lastIndexOf('used=') !== usedIndex) { - throw 'unexpected second "used" field in calculating gas' + throw new Error('unexpected second "used" field in calculating gas') } if (!muteLogComputeGas) { console.info('compute gas for gas::%s: used: %s rounded up: %s', opLabel, usedGas, roundedGas) diff --git a/tests/setup-jest.ts b/tests/setup-jest.ts new file mode 100644 index 0000000..6201034 --- /dev/null +++ b/tests/setup-jest.ts @@ -0,0 +1,7 @@ +import '@ton-community/test-utils' +import { toBeBetween, toBeTonValue } from './helper' + +expect.extend({ + toBeBetween, + toBeTonValue, +}) diff --git a/wrappers/Loan.compile.ts b/wrappers/Loan.compile.ts index d5a5c90..ed14e32 100644 --- a/wrappers/Loan.compile.ts +++ b/wrappers/Loan.compile.ts @@ -1,6 +1,6 @@ -import { CompilerConfig } from '@ton-community/blueprint'; +import { CompilerConfig } from '@ton-community/blueprint' export const compile: CompilerConfig = { lang: 'func', targets: ['contracts/loan.fc'], -}; +} diff --git a/wrappers/Loan.ts b/wrappers/Loan.ts index 1f64840..3850fef 100644 --- a/wrappers/Loan.ts +++ b/wrappers/Loan.ts @@ -1,6 +1,6 @@ import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider } from 'ton-core' -export type LoanConfig = { +export interface LoanConfig { elector?: Address treasury: Address validator: Address @@ -17,7 +17,7 @@ export function loanConfigToCell(config: LoanConfig): Cell { } export class Loan implements Contract { - constructor(readonly address: Address, readonly init?: { code: Cell, data: Cell }) {} + constructor(readonly address: Address, readonly init?: { code: Cell; data: Cell }) {} static createFromAddress(address: Address) { return new Loan(address) diff --git a/wrappers/Treasury.ts b/wrappers/Treasury.ts index 7d03aa7..b6d9b64 100644 --- a/wrappers/Treasury.ts +++ b/wrappers/Treasury.ts @@ -1,7 +1,22 @@ -import { Address, beginCell, Builder, Cell, Contract, contractAddress, ContractProvider, ContractState, Dictionary, DictionaryValue, Sender, SendMode, Slice, TupleBuilder } from 'ton-core' +import { + Address, + beginCell, + Builder, + Cell, + Contract, + contractAddress, + ContractProvider, + ContractState, + Dictionary, + DictionaryValue, + Sender, + SendMode, + Slice, + TupleBuilder, +} from 'ton-core' import { op, tonValue } from './common' -export type Times = { +export interface Times { currentRoundSince: bigint participateSince: bigint participateUntil: bigint @@ -10,7 +25,7 @@ export type Times = { stakeHeldFor: bigint } -export type Fees = { +export interface Fees { depositCoinsFee: bigint unstakeTokensFee: bigint sendTokensFee: bigint @@ -20,9 +35,7 @@ export type Fees = { loanStorage: bigint } -export type True = {} - -export type Reward = { +export interface Reward { staked: bigint recovered: bigint } @@ -36,7 +49,7 @@ export enum ParticipationState { Recovering, } -export type Request = { +export interface Request { minPayment: bigint validatorRewardShare: bigint loanAmount: bigint @@ -45,10 +58,10 @@ export type Request = { newStakeMsg: Cell } -export type Participation = { +export interface Participation { state?: ParticipationState size?: bigint - sorted?: Dictionary> + sorted?: Dictionary> requests?: Dictionary rejected?: Dictionary accepted?: Dictionary @@ -62,7 +75,7 @@ export type Participation = { stakeHeldUntil?: bigint } -export type TreasuryConfig = { +export interface TreasuryConfig { totalCoins: bigint totalTokens: bigint totalStaking: bigint @@ -90,13 +103,13 @@ export function treasuryConfigToCell(config: TreasuryConfig): Cell { .storeMaybeRef(config.proposedGovernor) .storeUint(config.governanceFee, 16) .storeDict(config.rewardsHistory) - .storeRef(config.content || Cell.EMPTY) + .storeRef(config.content) return beginCell() - .storeCoins(config.totalCoins || 0) - .storeCoins(config.totalTokens || 0) - .storeCoins(config.totalStaking || 0) - .storeCoins(config.totalUnstaking || 0) - .storeCoins(config.totalValidatorsStake || 0) + .storeCoins(config.totalCoins) + .storeCoins(config.totalTokens) + .storeCoins(config.totalStaking) + .storeCoins(config.totalUnstaking) + .storeCoins(config.totalValidatorsStake) .storeDict(config.participations) .storeBit(config.balancedRounds) .storeBit(config.stopped) @@ -106,40 +119,38 @@ export function treasuryConfigToCell(config: TreasuryConfig): Cell { .endCell() } -export const trueDictionaryValue: DictionaryValue = { - serialize: function(src: True, builder: Builder) { +export const emptyDictionaryValue: DictionaryValue = { + serialize: function () { + return }, - parse: function(src: Slice): True { + parse: function (): unknown { return {} - } + }, } export const rewardDictionaryValue: DictionaryValue = { - serialize: function(src: Reward, builder: Builder) { - builder - .storeCoins(src.staked) - .storeCoins(src.recovered) + serialize: function (src: Reward, builder: Builder) { + builder.storeCoins(src.staked).storeCoins(src.recovered) }, - parse: function(src: Slice): Reward { + parse: function (src: Slice): Reward { return { staked: src.loadCoins(), recovered: src.loadCoins(), } - } + }, } -export const sortedDictionaryValue: DictionaryValue> = { - serialize: function(src: Dictionary, builder: Builder) { - builder - .storeRef(beginCell().storeDictDirect(src)) +export const sortedDictionaryValue: DictionaryValue> = { + serialize: function (src: Dictionary, builder: Builder) { + builder.storeRef(beginCell().storeDictDirect(src)) + }, + parse: function (src: Slice): Dictionary { + return src.loadRef().beginParse().loadDictDirect(Dictionary.Keys.BigUint(256), emptyDictionaryValue) }, - parse: function(src: Slice): Dictionary { - return src.loadRef().beginParse().loadDictDirect(Dictionary.Keys.BigUint(256), trueDictionaryValue) - } } export const requestDictionaryValue: DictionaryValue = { - serialize: function(src: Request, builder: Builder) { + serialize: function (src: Request, builder: Builder) { builder .storeCoins(src.minPayment) .storeUint(src.validatorRewardShare, 8) @@ -148,7 +159,7 @@ export const requestDictionaryValue: DictionaryValue = { .storeCoins(src.stakeAmount) .storeRef(src.newStakeMsg) }, - parse: function(src: Slice): Request { + parse: function (src: Slice): Request { return { minPayment: src.loadCoins(), validatorRewardShare: src.loadUintBig(8), @@ -157,14 +168,14 @@ export const requestDictionaryValue: DictionaryValue = { stakeAmount: src.loadCoins(), newStakeMsg: src.loadRef(), } - } + }, } export const participationDictionaryValue: DictionaryValue = { - serialize: function(src: Participation, builder: Builder) { + serialize: function (src: Participation, builder: Builder) { builder - .storeUint(src.state || 0, 3) - .storeUint(src.size || 0, 16) + .storeUint(src.state ?? 0, 3) + .storeUint(src.size ?? 0, 16) .storeDict(src.sorted) .storeDict(src.requests) .storeDict(src.rejected) @@ -172,13 +183,13 @@ export const participationDictionaryValue: DictionaryValue = { .storeDict(src.accrued) .storeDict(src.staked) .storeDict(src.recovering) - .storeCoins(src.totalStaked || 0) - .storeCoins(src.totalRecovered || 0) - .storeUint(src.currentVsetHash || 0, 256) - .storeUint(src.stakeHeldFor || 0, 32) - .storeUint(src.stakeHeldUntil || 0, 32) + .storeCoins(src.totalStaked ?? 0) + .storeCoins(src.totalRecovered ?? 0) + .storeUint(src.currentVsetHash ?? 0, 256) + .storeUint(src.stakeHeldFor ?? 0, 32) + .storeUint(src.stakeHeldUntil ?? 0, 32) }, - parse: function(src: Slice): Participation { + parse: function (src: Slice): Participation { return { state: src.loadUint(3), size: src.loadUintBig(16), @@ -195,11 +206,11 @@ export const participationDictionaryValue: DictionaryValue = { stakeHeldFor: src.loadUintBig(32), stakeHeldUntil: src.loadUintBig(32), } - } + }, } export class Treasury implements Contract { - constructor(readonly address: Address, readonly init?: { code: Cell, data: Cell }) {} + constructor(readonly address: Address, readonly init?: { code: Cell; data: Cell }) {} static createFromAddress(address: Address) { return new Treasury(address) @@ -211,51 +222,67 @@ export class Treasury implements Contract { return new Treasury(contractAddress(workchain, init), init) } - async sendMessage(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - body?: Cell | string - }) { + async sendMessage( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + body?: Cell | string + }, + ) { await provider.internal(via, opts) } - async sendDeploy(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendDeploy( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendTopUp(provider, via, opts) } - async sendTopUp(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendTopUp( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.topUp, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .endCell(), }) } - async sendDepositCoins(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - referrer?: Address - }) { + async sendDepositCoins( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + referrer?: Address + }, + ) { const builder = beginCell() .storeUint(op.depositCoins, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) if (opts.referrer != undefined) { builder.storeAddress(opts.referrer) } @@ -263,321 +290,386 @@ export class Treasury implements Contract { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, - body: builder.endCell() + body: builder.endCell(), }) } - async sendProvideWalletAddress(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - owner: Address - includeAddress?: boolean - }) { + async sendProvideWalletAddress( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + owner: Address + includeAddress?: boolean + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.provideWalletAddress, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.owner) - .storeBit(opts.includeAddress || false) - .endCell() + .storeBit(opts.includeAddress ?? false) + .endCell(), }) } - async sendRequestLoan(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - roundSince: bigint - loanAmount: bigint | string - minPayment: bigint | string - validatorRewardShare: bigint - newStakeMsg: Cell - }) { + async sendRequestLoan( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + roundSince: bigint + loanAmount: bigint | string + minPayment: bigint | string + validatorRewardShare: bigint + newStakeMsg: Cell + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.requestLoan, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) .storeCoins(tonValue(opts.loanAmount)) .storeCoins(tonValue(opts.minPayment)) .storeUint(opts.validatorRewardShare, 8) .storeRef(opts.newStakeMsg) - .endCell() + .endCell(), }) } - async sendParticipateInElection(provider: ContractProvider, opts: { - queryId?: bigint - roundSince: bigint - }) { + async sendParticipateInElection( + provider: ContractProvider, + opts: { + queryId?: bigint + roundSince: bigint + }, + ) { const message = beginCell() .storeUint(op.participateInElection, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) .endCell() await provider.external(message) } - async sendVsetChanged(provider: ContractProvider, opts: { - queryId?: bigint - roundSince: bigint - }) { + async sendVsetChanged( + provider: ContractProvider, + opts: { + queryId?: bigint + roundSince: bigint + }, + ) { const message = beginCell() .storeUint(op.vsetChanged, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) .endCell() await provider.external(message) } - async sendFinishParticipation(provider: ContractProvider, opts: { - queryId?: bigint - roundSince: bigint - }) { + async sendFinishParticipation( + provider: ContractProvider, + opts: { + queryId?: bigint + roundSince: bigint + }, + ) { const message = beginCell() .storeUint(op.finishParticipation, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) .endCell() await provider.external(message) } - async sendProposeGovernor(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newGovernor: Address - }) { + async sendProposeGovernor( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newGovernor: Address + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.proposeGovernor, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.newGovernor) - .endCell() + .endCell(), }) } - async sendAcceptGovernance(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendAcceptGovernance( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.acceptGovernance, 32) - .storeUint(opts.queryId || 0, 64) - .endCell() + .storeUint(opts.queryId ?? 0, 64) + .endCell(), }) } - async sendSetHalter(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newHalter: Address - }) { + async sendSetHalter( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newHalter: Address + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setHalter, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.newHalter) - .endCell() + .endCell(), }) } - async sendSetStopped(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newStopped: boolean - }) { + async sendSetStopped( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newStopped: boolean + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setStopped, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeBit(opts.newStopped) - .endCell() + .endCell(), }) } - async sendSetDriver(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newDriver: Address - }) { + async sendSetDriver( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newDriver: Address + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setDriver, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.newDriver) - .endCell() + .endCell(), }) } - async sendSetContent(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newContent: Cell - }) { + async sendSetContent( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newContent: Cell + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setContent, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeRef(opts.newContent) - .endCell() + .endCell(), }) } - async sendSetGovernanceFee(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newGovernanceFee: bigint - }) { + async sendSetGovernanceFee( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newGovernanceFee: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setGovernanceFee, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.newGovernanceFee, 16) - .endCell() + .endCell(), }) } - async sendSetBalancedRounds(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newBalancedRounds: boolean - }) { + async sendSetBalancedRounds( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newBalancedRounds: boolean + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.setBalancedRounds, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeBit(opts.newBalancedRounds) - .endCell() + .endCell(), }) } - async sendSendMessageToLoan(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - validator: Address - roundSince: bigint - message: Cell - }) { + async sendSendMessageToLoan( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + validator: Address + roundSince: bigint + message: Cell + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.sendMessageToLoan, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.validator) .storeUint(opts.roundSince, 32) .storeRef(opts.message) - .endCell() + .endCell(), }) } - async sendSendProcessLoanRequests(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - roundSince: bigint - }) { + async sendSendProcessLoanRequests( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + roundSince: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.sendProcessLoanRequests, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) - .endCell() + .endCell(), }) } - async sendUpgradeCode(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - newCode: Cell - rest?: Builder - }) { + async sendUpgradeCode( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + newCode: Cell + rest?: Builder + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.upgradeCode, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeRef(opts.newCode) - .storeBuilder(opts.rest || beginCell()) - .endCell() + .storeBuilder(opts.rest ?? beginCell()) + .endCell(), }) } - async sendWithdrawSurplus(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendWithdrawSurplus( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.withdrawSurplus, 32) - .storeUint(opts.queryId || 0, 64) - .endCell() + .storeUint(opts.queryId ?? 0, 64) + .endCell(), }) } @@ -595,13 +687,7 @@ export class Treasury implements Contract { async getJettonData(provider: ContractProvider): Promise<[bigint, boolean, Address, Cell, Cell]> { const { stack } = await provider.get('get_jetton_data', []) - return [ - stack.readBigNumber(), - stack.readBoolean(), - stack.readAddress(), - stack.readCell(), - stack.readCell(), - ] + return [stack.readBigNumber(), stack.readBoolean(), stack.readAddress(), stack.readCell(), stack.readCell()] } async getWalletAddress(provider: ContractProvider, owner: Address): Promise
{ @@ -627,8 +713,11 @@ export class Treasury implements Contract { totalStaking: stack.readBigNumber(), totalUnstaking: stack.readBigNumber(), totalValidatorsStake: stack.readBigNumber(), - participations: Dictionary.loadDirect(Dictionary.Keys.BigUint(32), participationDictionaryValue, - stack.readCellOpt()), + participations: Dictionary.loadDirect( + Dictionary.Keys.BigUint(32), + participationDictionaryValue, + stack.readCellOpt(), + ), balancedRounds: stack.readBoolean(), stopped: stack.readBoolean(), walletCode: stack.readCell(), @@ -638,8 +727,11 @@ export class Treasury implements Contract { governor: stack.readAddress(), proposedGovernor: stack.readCellOpt(), governanceFee: stack.readBigNumber(), - rewardsHistory: Dictionary.loadDirect(Dictionary.Keys.BigUint(32), rewardDictionaryValue, - stack.readCellOpt()), + rewardsHistory: Dictionary.loadDirect( + Dictionary.Keys.BigUint(32), + rewardDictionaryValue, + stack.readCellOpt(), + ), content: stack.readCell(), } } @@ -657,7 +749,11 @@ export class Treasury implements Contract { accepted: Dictionary.loadDirect(Dictionary.Keys.BigUint(256), requestDictionaryValue, stack.readCellOpt()), accrued: Dictionary.loadDirect(Dictionary.Keys.BigUint(256), requestDictionaryValue, stack.readCellOpt()), staked: Dictionary.loadDirect(Dictionary.Keys.BigUint(256), requestDictionaryValue, stack.readCellOpt()), - recovering: Dictionary.loadDirect(Dictionary.Keys.BigUint(256), requestDictionaryValue, stack.readCellOpt()), + recovering: Dictionary.loadDirect( + Dictionary.Keys.BigUint(256), + requestDictionaryValue, + stack.readCellOpt(), + ), totalStaked: stack.readBigNumber(), totalRecovered: stack.readBigNumber(), currentVsetHash: stack.readBigNumber(), diff --git a/wrappers/Wallet.ts b/wrappers/Wallet.ts index 88e3261..c3f13c5 100644 --- a/wrappers/Wallet.ts +++ b/wrappers/Wallet.ts @@ -1,7 +1,18 @@ -import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Dictionary, Sender, SendMode, Slice } from 'ton-core' +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Dictionary, + Sender, + SendMode, + Slice, +} from 'ton-core' import { op, tonValue } from './common' -type WalletConfig = { +interface WalletConfig { owner: Address treasury: Address tokens: bigint @@ -26,7 +37,7 @@ function toStakingDict(dict: Cell | null): Dictionary { } export class Wallet implements Contract { - constructor(readonly address: Address, readonly init?: { code: Cell, data: Cell }) {} + constructor(readonly address: Address, readonly init?: { code: Cell; data: Cell }) {} static createFromAddress(address: Address) { return new Wallet(address) @@ -38,149 +49,177 @@ export class Wallet implements Contract { return new Wallet(contractAddress(workchain, init), init) } - async sendMessage(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - body?: Cell | string - }) { + async sendMessage( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + body?: Cell | string + }, + ) { await provider.internal(via, opts) } - async sendTopUp(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendTopUp( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.topUp, 32) - .storeUint(opts.queryId || 0, 64) - .endCell() + .storeUint(opts.queryId ?? 0, 64) + .endCell(), }) } - async sendStakeCoins(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - roundSince: bigint - returnExcess?: Address - }) { + async sendStakeCoins( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + roundSince: bigint + returnExcess?: Address + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.stakeCoins, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeUint(opts.roundSince, 32) .storeAddress(opts.returnExcess) - .endCell() + .endCell(), }) } - async sendSendTokens(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - tokens: bigint | string - recipient: Address - returnExcess?: Address - customPayload?: Cell - forwardTonAmount?: bigint | string - forwardPayload?: Slice - }) { + async sendSendTokens( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + tokens: bigint | string + recipient: Address + returnExcess?: Address + customPayload?: Cell + forwardTonAmount?: bigint | string + forwardPayload?: Slice + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.sendTokens, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeCoins(tonValue(opts.tokens)) .storeAddress(opts.recipient) .storeAddress(opts.returnExcess) .storeMaybeRef(opts.customPayload) - .storeCoins(tonValue(opts.forwardTonAmount || 0n)) - .storeSlice(opts.forwardPayload || beginCell().storeUint(0, 1).endCell().beginParse()) - .endCell() + .storeCoins(tonValue(opts.forwardTonAmount ?? 0n)) + .storeSlice(opts.forwardPayload ?? beginCell().storeUint(0, 1).endCell().beginParse()) + .endCell(), }) } - async sendUnstakeTokens(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - tokens: bigint | string - returnExcess?: Address - customPayload?: Cell - }) { + async sendUnstakeTokens( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + tokens: bigint | string + returnExcess?: Address + customPayload?: Cell + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.unstakeTokens, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeCoins(tonValue(opts.tokens)) .storeAddress(opts.returnExcess) .storeMaybeRef(opts.customPayload) - .endCell() + .endCell(), }) } - async sendWithdrawTokens(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - returnExcess?: Address - }) { + async sendWithdrawTokens( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + returnExcess?: Address + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.withdrawTokens, 32) - .storeUint(opts.queryId || 0, 64) + .storeUint(opts.queryId ?? 0, 64) .storeAddress(opts.returnExcess) - .endCell() + .endCell(), }) } - async sendWithdrawSurplus(provider: ContractProvider, via: Sender, opts: { - value: bigint | string - bounce?: boolean - sendMode?: SendMode - queryId?: bigint - }) { + async sendWithdrawSurplus( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint | string + bounce?: boolean + sendMode?: SendMode + queryId?: bigint + }, + ) { await this.sendMessage(provider, via, { value: opts.value, bounce: opts.bounce, sendMode: opts.sendMode, body: beginCell() .storeUint(op.withdrawSurplus, 32) - .storeUint(opts.queryId || 0, 64) - .endCell() + .storeUint(opts.queryId ?? 0, 64) + .endCell(), }) } async getWalletData(provider: ContractProvider): Promise<[bigint, Address, Address, Cell]> { const { stack } = await provider.get('get_wallet_data', []) - return [ stack.readBigNumber(), stack.readAddress(), stack.readAddress(), stack.readCell() ] + return [stack.readBigNumber(), stack.readAddress(), stack.readAddress(), stack.readCell()] } async getWalletState(provider: ContractProvider): Promise<[bigint, Dictionary, bigint]> { const { stack } = await provider.get('get_wallet_state', []) - return [ stack.readBigNumber(), toStakingDict(stack.readCellOpt()), stack.readBigNumber() ] + return [stack.readBigNumber(), toStakingDict(stack.readCellOpt()), stack.readBigNumber()] } async getBalance(provider: ContractProvider): Promise { diff --git a/wrappers/common.ts b/wrappers/common.ts index b5b4429..aeff029 100644 --- a/wrappers/common.ts +++ b/wrappers/common.ts @@ -1,4 +1,4 @@ -import { toNano } from "ton-core" +import { toNano } from 'ton-core' export const op = { newStake: 0x4e73744b, diff --git a/wrappers/elector-test/Elector.ts b/wrappers/elector-test/Elector.ts index 44b197f..9304b7c 100644 --- a/wrappers/elector-test/Elector.ts +++ b/wrappers/elector-test/Elector.ts @@ -1,6 +1,15 @@ -import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Dictionary, TupleBuilder } from 'ton-core' +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Dictionary, + TupleBuilder, +} from 'ton-core' -export type ElectorConfig = { +export interface ElectorConfig { currentElection?: Cell credits?: Dictionary pastElections?: Cell @@ -14,13 +23,13 @@ export function electorConfigToCell(config: ElectorConfig): Cell { .storeMaybeRef(config.currentElection) .storeDict(config.credits) .storeMaybeRef(config.pastElections) - .storeCoins(config.coins || 0) - .storeUint(config.activeId || 0, 32) - .storeUint(config.activeHash || 0, 256) + .storeCoins(config.coins ?? 0) + .storeUint(config.activeId ?? 0, 32) + .storeUint(config.activeHash ?? 0, 256) .endCell() } -export type ElectionConfig = { +export interface ElectionConfig { electAt?: bigint electClose?: bigint minStake?: bigint @@ -32,18 +41,18 @@ export type ElectionConfig = { export function createElectionConfig(config: ElectionConfig): Cell { return beginCell() - .storeUint(config.electAt || 0, 32) - .storeUint(config.electClose || 0, 32) - .storeCoins(config.minStake || 0) - .storeCoins(config.totalStake || 0) + .storeUint(config.electAt ?? 0, 32) + .storeUint(config.electClose ?? 0, 32) + .storeCoins(config.minStake ?? 0) + .storeCoins(config.totalStake ?? 0) .storeMaybeRef(config.members) - .storeBit(config.failed || false) - .storeBit(config.finished || false) + .storeBit(config.failed ?? false) + .storeBit(config.finished ?? false) .endCell() } export class Elector implements Contract { - constructor(readonly address: Address, readonly init?: { code: Cell, data: Cell }) {} + constructor(readonly address: Address, readonly init?: { code: Cell; data: Cell }) {} static createFromAddress(address: Address) { return new Elector(address) diff --git a/wrappers/elector-test/elector-code.fc b/wrappers/elector-test/elector-code.fc index fabb8e7..97e2888 100644 --- a/wrappers/elector-test/elector-code.fc +++ b/wrappers/elector-test/elector-code.fc @@ -341,7 +341,7 @@ _ unfreeze_all(credits, past_elections, elect_id) inline_ref { var (unfreeze_at, stake_held, vset_hash, fdict, tot_stakes, bonuses, complaints) = fs.unpack_past_election(); ;; tot_stakes = fdict.stakes_sum(); ;; TEMP BUGFIX var unused_prizes = (bonuses > 0) ? - credits~unfreeze_with_bonuses(fdict, tot_stakes, bonuses) : + credits~unfreeze_with_bonuses(fdict, tot_stakes, bonuses) : credits~unfreeze_without_bonuses(fdict, tot_stakes); return (credits, past_elections, unused_prizes); } @@ -857,8 +857,8 @@ int conduct_elections(ds, elect, credits) impure { ;; add frozen to the dictionary of past elections var past_elections = ds~load_dict(); past_elections~udict_set_builder(32, elect_at, pack_past_election( - start + elect_for + stake_held, stake_held, vset.cell_hash(), - frozen, total_stakes, 0, null())); + start + elect_for + stake_held, stake_held, vset.cell_hash(), + frozen, total_stakes, 0, null())); ;; store credits and frozen until end set_data(begin_cell() .store_dict(elect) diff --git a/wrappers/upgrade-code-test/only_upgrade.fc b/wrappers/upgrade-code-test/only_upgrade.fc index 4353ced..afd439f 100644 --- a/wrappers/upgrade-code-test/only_upgrade.fc +++ b/wrappers/upgrade-code-test/only_upgrade.fc @@ -1,6 +1,18 @@ #include "../../contracts/imports/utils.fc"; +global slice governor; + +() load_data() impure inline_ref { + slice ds = get_data().begin_parse(); + governor = ds~load_msg_addr(); +} + +() unpack_extension() impure inline_ref { +} + () upgrade_data(slice src, int query_id, slice s) impure method_id { + ;; Add code for upgrading date here. + ;; This just messes with data for test. begin_cell() .store_slice(s~load_msg_addr()) @@ -8,16 +20,21 @@ .end_cell() .set_data(); + ;; Do not change the following code. + load_data(); + unpack_extension(); + + throw_unless(err::access_denied, equal_slice_bits(src, governor)); + builder excess = begin_cell() .store_uint(op::gas_excess, 32) .store_uint(query_id, 64); send_msg(false, src.to_builder(), null(), excess, 0, send::remaining_value + send::ignore_errors); + + throw(0); } () upgrade_code(slice src, slice s) impure { - slice ds = get_data().begin_parse(); - slice governor = ds~load_msg_addr(); - int query_id = s~load_uint(64); cell new_code = s~load_ref(); ;; no s.end_parse(), allow additional data in message body @@ -27,10 +44,11 @@ set_code(new_code); set_c3(new_code.begin_parse().bless()); upgrade_data(src, query_id, s); - throw(0); } () recv_internal(cell in_msg_full, slice in_msg_body) impure { + load_data(); + slice cs = in_msg_full.begin_parse(); int flags = cs~load_uint(4); slice src = cs~load_msg_addr(); diff --git a/wrappers/upgrade-code-test/reset_data.fc b/wrappers/upgrade-code-test/reset_data.fc index 15ae7f4..c5b418b 100644 --- a/wrappers/upgrade-code-test/reset_data.fc +++ b/wrappers/upgrade-code-test/reset_data.fc @@ -48,15 +48,25 @@ global cell content; } () upgrade_data(slice src, int query_id, slice s) impure method_id { + ;; Add code for upgrading date here. + ;; This just resets data back to its previous state. slice ds = get_data().begin_parse(); ds~load_msg_addr(); ds~load_ref().set_data(); + ;; Do not change the following code. + load_data(); + unpack_extension(); + + throw_unless(err::access_denied, equal_slice_bits(src, governor)); + builder excess = begin_cell() .store_uint(op::gas_excess, 32) .store_uint(query_id, 64); send_msg(false, src.to_builder(), null(), excess, 0, send::remaining_value + send::ignore_errors); + + throw(0); } () upgrade_code(slice src, slice s) impure { @@ -71,7 +81,6 @@ global cell content; set_code(new_code); set_c3(new_code.begin_parse().bless()); upgrade_data(src, query_id, s); - throw(0); } () recv_internal(cell in_msg_full, slice in_msg_body) impure { diff --git a/yarn.lock b/yarn.lock index 99dc5ba..c80ed2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@adobe/css-tools@^4.0.1": version "4.2.0" resolved "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz" @@ -323,6 +328,57 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" + integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== + +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.51.0": + version "8.51.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" + integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== + +"@humanwhocodes/config-array@^0.11.11": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@ipld/dag-pb@2.1.18", "@ipld/dag-pb@^2.0.2": version "2.1.18" resolved "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-2.1.18.tgz" @@ -594,6 +650,27 @@ multiformats "^9.5.4" murmurhash3js-revisited "^3.0.0" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@orbs-network/ton-access@^2.3.3": version "2.3.3" resolved "https://registry.npmjs.org/@orbs-network/ton-access/-/ton-access-2.3.3.tgz" @@ -886,6 +963,11 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/json-schema@^7.0.12": + version "7.0.13" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" + integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + "@types/long@^4.0.1": version "4.0.2" resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" @@ -901,6 +983,11 @@ resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz" integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== +"@types/semver@^7.5.0": + version "7.5.3" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" + integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" @@ -925,6 +1012,96 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d" + integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/type-utils" "6.7.4" + "@typescript-eslint/utils" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435" + integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA== + dependencies: + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386" + integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A== + dependencies: + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" + +"@typescript-eslint/type-utils@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321" + integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ== + dependencies: + "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/utils" "6.7.4" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897" + integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA== + +"@typescript-eslint/typescript-estree@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a" + integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ== + dependencies: + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/visitor-keys" "6.7.4" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2" + integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.7.4" + "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/typescript-estree" "6.7.4" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.7.4": + version "6.7.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043" + integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA== + dependencies: + "@typescript-eslint/types" "6.7.4" + eslint-visitor-keys "^3.4.1" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" @@ -935,6 +1112,21 @@ acorn@^8.4.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" @@ -991,6 +1183,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + aria-query@^5.0.0: version "5.1.3" resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz" @@ -1006,6 +1203,11 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" @@ -1417,7 +1619,7 @@ create-require@^1.1.0: resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1436,7 +1638,7 @@ dataloader@^2.0.0: resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz" integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1472,6 +1674,11 @@ deep-equal@^2.0.5: which-collection "^1.0.1" which-typed-array "^1.1.9" +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + deepmerge@^4.2.2: version "4.3.0" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz" @@ -1512,6 +1719,20 @@ diff@^4.0.1: resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dom-accessibility-api@^0.5.6: version "0.5.16" resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz" @@ -1587,11 +1808,110 @@ escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" + integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.51.0: + version "8.51.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" + integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.51.0" + "@humanwhocodes/config-array" "^0.11.11" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz" @@ -1645,11 +1965,39 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" @@ -1664,6 +2012,13 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" @@ -1679,6 +2034,28 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + follow-redirects@^1.14.7, follow-redirects@^1.14.9: version "1.15.2" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" @@ -1755,6 +2132,20 @@ get-stream@^6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" @@ -1772,6 +2163,25 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^13.19.0: + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + gopd@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" @@ -1784,6 +2194,11 @@ graceful-fs@^4.2.9: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + hamt-sharding@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/hamt-sharding/-/hamt-sharding-2.0.1.tgz" @@ -1868,6 +2283,19 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" @@ -2039,6 +2467,11 @@ is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" @@ -2049,6 +2482,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz" @@ -2076,6 +2516,11 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" @@ -2620,16 +3065,38 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" @@ -2640,6 +3107,13 @@ jssha@3.2.0: resolved "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz" integrity sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -2650,6 +3124,14 @@ leven@^3.1.0: resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" @@ -2662,11 +3144,23 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -2737,6 +3231,11 @@ merge-stream@^2.0.0: resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + micromatch@^4.0.4: version "4.0.5" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" @@ -2767,7 +3266,7 @@ min-indent@^1.0.0: resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2906,6 +3405,18 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + ora@^5.4.1: version "5.4.1" resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" @@ -2933,7 +3444,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.1.0: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -2947,6 +3458,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" @@ -2960,6 +3478,13 @@ param-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-json@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" @@ -3011,6 +3536,11 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" @@ -3038,6 +3568,11 @@ prando@^6.0.1: resolved "https://registry.npmjs.org/prando/-/prando-6.0.1.tgz" integrity sha512-ghUWxQ1T9IJmPu6eshc3VU0OwveUtXQ33ZLXYUcz1Oc5ppKLDXKp0TBDj6b0epwhEctzcQSNGR2iHyvQSn4W5A== +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prettier@^2.8.8: version "2.8.8" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" @@ -3079,6 +3614,11 @@ protobufjs@^6.10.2: "@types/node" ">=13.7.0" long "^4.0.0" +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + pure-rand@^6.0.0: version "6.0.2" resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz" @@ -3096,6 +3636,11 @@ qs@^6.11.0: dependencies: side-channel "^1.0.4" +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + rabin-wasm@^0.1.4: version "0.1.5" resolved "https://registry.npmjs.org/rabin-wasm/-/rabin-wasm-0.1.5.tgz" @@ -3165,6 +3710,11 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" @@ -3192,11 +3742,30 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + run-async@^2.4.0: version "2.4.1" resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + rxjs@^7.5.5: version "7.8.0" resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz" @@ -3226,6 +3795,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + sentence-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz" @@ -3421,6 +3997,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + through@^2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" @@ -3529,6 +4110,11 @@ tr46@~0.0.3: resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + ts-jest@^29.1.0: version "29.1.0" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz" @@ -3577,11 +4163,23 @@ tweetnacl@1.0.3, tweetnacl@^1.0.3: resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-detect@4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" @@ -3621,6 +4219,13 @@ upper-case@^2.0.2: dependencies: tslib "^2.0.3" +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"