diff --git a/README.md b/README.md index 63b93f2..cb2cf6e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,39 @@ Now change paths to artifacts [here](src/basset_vault/definition.ts) 3. `docker pull terramoney/localterra-core:bombay` 4. `docker-compose up` +To speed up local terra, + +Comment out this section +``` +# # How long we wait for a proposal block before prevoting nil +# timeout_propose = "3s" +# # How much timeout_propose increases with each round +# timeout_propose_delta = "500ms" +# # How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) +# timeout_prevote = "1s" +# # How much the timeout_prevote increases with each round +# timeout_prevote_delta = "500ms" +# # How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) +# timeout_precommit = "1s" +# # How much the timeout_precommit increases with each round +# timeout_precommit_delta = "500ms" +# # How long we wait after committing a block, before starting on the new +# # height (this gives us a chance to receive some more precommits, even +# # though we already have +2/3). +# timeout_commit = "5s" +``` + +To this section +``` +timeout_precommit = "200ms" +timeout_propose = "200ms" +timeout_propose_delta = "200ms" +timeout_prevote = "200ms" +timeout_prevote_delta = "200ms" +timeout_precommit_delta = "200ms" +timeout_commit = "200ms" +``` + # Usage [start localterra](#start-localterra) before run scripts. @@ -88,3 +121,29 @@ Now change paths to artifacts [here](src/basset_vault/definition.ts) - `npm run psi-distr-integration-tests` - run psi distribution integration tests - `npm run bvault-integration-tests` - run basset vault integration tests + +### Basset vault integration tests + +`npm run bvault-integration-tests -- borrow_more_on_bluna_price_increasing` may fail because of anchor inaccuracy on low localterra timeouts, so that for this test use localterra configuration with default timeouts: + +```toml +timeout_propose = "3s" +timeout_propose_delta = "500ms" +timeout_prevote = "1s" +timeout_prevote_delta = "500ms" +timeout_precommit = "1s" +timeout_precommit_delta = "500ms" +timeout_commit = "5s" +``` + +`npm run bvault-integration-tests -- bvault_deposit_and_withdraw_half` needs to be runned with low localterra timeouts: + +```toml +timeout_precommit = "200ms" +timeout_propose = "200ms" +timeout_propose_delta = "200ms" +timeout_prevote = "200ms" +timeout_prevote_delta = "200ms" +timeout_precommit_delta = "200ms" +timeout_commit = "200ms" +``` diff --git a/src/basset_vault/definition.ts b/src/basset_vault/definition.ts index 64ede1b..68d8d20 100644 --- a/src/basset_vault/definition.ts +++ b/src/basset_vault/definition.ts @@ -9,7 +9,8 @@ import { GovernanceConfig, init_astroport_factory, PSiTokensOwner, - TokenConfig + TokenConfig, + is_prod, } from './../config'; import { create_contract, @@ -25,6 +26,7 @@ import {AnchorMarketInfo} from "../integration_tests/deploy_anchor/config"; const artifacts_path = "wasm_artifacts"; const path_to_cosmwasm_artifacts = `${artifacts_path}/cosmwasm_plus`; const path_to_basset_vault_artifacts = `${artifacts_path}/nexus/basset_vaults`; +const path_to_basset_vault_integration_tests_artifacts = `${artifacts_path}/nexus/basset_vaults_integration_tests`; const path_to_services_contracts_artifacts = `${artifacts_path}/nexus/services`; const path_to_terraswap_contracts_artifacts = `${artifacts_path}/terraswap`; const path_to_astroport_contracts_artifacts = `${artifacts_path}/astroport`; @@ -47,6 +49,9 @@ const nasset_token_config_holder_wasm = `${path_to_basset_vault_artifacts}/basse const nasset_token_rewards_wasm = `${path_to_basset_vault_artifacts}/basset_vault_nasset_rewards.wasm`; const psi_distributor_wasm = `${path_to_basset_vault_artifacts}/basset_vault_psi_distributor.wasm`; // =================================================== +const basset_vault_integration_tests_wasm = `${path_to_basset_vault_integration_tests_artifacts}/basset_vault_basset_vault.wasm`; +const basset_vault_strategy_integration_tests_wasm = `${path_to_basset_vault_integration_tests_artifacts}/basset_vault_basset_vault_strategy.wasm`; +// =================================================== async function init_psi_token(lcd_client: LCDClient, sender: Wallet, code_id: number, init_msg: TokenConfig): Promise { let contract_addr = await instantiate_contract(lcd_client, sender, sender.key.accAddress, code_id, init_msg); @@ -128,9 +133,9 @@ export async function full_init(lcd_client: LCDClient, sender: Wallet, psi_token console.log(`psi_distributor uploaded\n\tcode_id: ${psi_distributor_code_id}`); console.log(`=======================`); - let basset_vault_strategy_code_id = await store_contract(lcd_client, sender, basset_vault_strategy_contract_wasm); + let basset_vault_strategy_code_id = await store_contract(lcd_client, sender, is_prod(lcd_client) ? basset_vault_strategy_contract_wasm : basset_vault_strategy_integration_tests_wasm); console.log(`basset_vault_strategy uploaded\n\tcode_id: ${basset_vault_strategy_code_id}`); - let basset_vault_code_id = await store_contract(lcd_client, sender, basset_vault_wasm); + let basset_vault_code_id = await store_contract(lcd_client, sender, is_prod(lcd_client) ? basset_vault_wasm : basset_vault_integration_tests_wasm); console.log(`basset_vault uploaded\n\tcode_id: ${basset_vault_code_id}`); console.log(`=======================`); // bLUNA @@ -139,11 +144,16 @@ export async function full_init(lcd_client: LCDClient, sender: Wallet, psi_token // instantiate basset_vault_strategy for bLuna let basset_vault_strategy_config_for_bluna = BassetVaultStrategyConfigForbLuna(lcd_client, governance_contract_addr); - if (anchor_market_info != null && anchor_market_info !== undefined) { - basset_vault_strategy_config_for_bluna.basset_token_addr = anchor_market_info.bluna_token_addr; + if (anchor_market_info !== null && anchor_market_info !== undefined) { basset_vault_strategy_config_for_bluna.oracle_contract_addr = anchor_market_info.oracle_addr; + basset_vault_strategy_config_for_bluna.basset_token_addr = anchor_market_info.bluna_token_addr; + basset_vault_strategy_config_for_bluna.anchor_market_addr = anchor_market_info.contract_addr; + basset_vault_strategy_config_for_bluna.anchor_interest_model_addr = anchor_market_info.interest_model_addr; + basset_vault_strategy_config_for_bluna.anchor_overseer_addr = anchor_market_info.overseer_addr; + basset_vault_strategy_config_for_bluna.anchor_token_addr = anchor_market_info.anchor_token_addr; + basset_vault_strategy_config_for_bluna.anc_ust_swap_addr = anchor_market_info.anc_stable_swap_addr; } - + let basset_vault_strategy_contract_addr_for_bluna = await instantiate_contract(lcd_client, sender, sender.key.accAddress, basset_vault_strategy_code_id, basset_vault_strategy_config_for_bluna); console.log(`basset_vault_strategy_for_bluna instantiated\n\taddress: ${basset_vault_strategy_contract_addr_for_bluna}`); console.log(`=======================`); @@ -159,6 +169,7 @@ export async function full_init(lcd_client: LCDClient, sender: Wallet, psi_token basset_vault_config_for_bluna.anc_stable_swap_addr = anchor_market_info.anc_stable_swap_addr; basset_vault_config_for_bluna.basset_addr = anchor_market_info.bluna_token_addr; basset_vault_config_for_bluna.a_custody_basset_addr = anchor_market_info.bluna_custody_addr; + basset_vault_config_for_bluna.a_basset_reward_addr = anchor_market_info.bluna_reward_addr; } basset_vault_info_for_bluna = await init_basset_vault(lcd_client, sender, basset_vault_code_id, basset_vault_config_for_bluna); @@ -170,10 +181,17 @@ export async function full_init(lcd_client: LCDClient, sender: Wallet, psi_token { // instantiate basset_vault_strategy for bETH let basset_vault_strategy_config_for_beth = BassetVaultStrategyConfigForbEth(lcd_client, governance_contract_addr); - if (anchor_market_info != null && anchor_market_info !== undefined) { - basset_vault_strategy_config_for_beth.basset_token_addr = anchor_market_info.beth_token_addr; + + if (anchor_market_info !== null && anchor_market_info !== undefined) { basset_vault_strategy_config_for_beth.oracle_contract_addr = anchor_market_info.oracle_addr; + basset_vault_strategy_config_for_beth.basset_token_addr = anchor_market_info.beth_token_addr; + basset_vault_strategy_config_for_beth.anchor_market_addr = anchor_market_info.contract_addr; + basset_vault_strategy_config_for_beth.anchor_interest_model_addr = anchor_market_info.interest_model_addr; + basset_vault_strategy_config_for_beth.anchor_overseer_addr = anchor_market_info.overseer_addr; + basset_vault_strategy_config_for_beth.anchor_token_addr = anchor_market_info.anchor_token_addr; + basset_vault_strategy_config_for_beth.anc_ust_swap_addr = anchor_market_info.anc_stable_swap_addr; } + let basset_vault_strategy_contract_addr_for_beth = await instantiate_contract(lcd_client, sender, sender.key.accAddress, basset_vault_strategy_code_id, basset_vault_strategy_config_for_beth); console.log(`basset_vault_strategy_for_beth instantiated\n\taddress: ${basset_vault_strategy_contract_addr_for_beth}`); console.log(`=======================`); @@ -189,6 +207,7 @@ export async function full_init(lcd_client: LCDClient, sender: Wallet, psi_token basset_vault_config_for_beth.anc_stable_swap_addr = anchor_market_info.anc_stable_swap_addr; basset_vault_config_for_beth.basset_addr = anchor_market_info.beth_token_addr; basset_vault_config_for_beth.a_custody_basset_addr = anchor_market_info.beth_custody_addr; + basset_vault_config_for_beth.a_basset_reward_addr = anchor_market_info.beth_reward_addr; } basset_vault_info_for_beth = await init_basset_vault(lcd_client, sender, basset_vault_code_id, basset_vault_config_for_beth); diff --git a/src/config.ts b/src/config.ts index cb5ed34..c7862e5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -31,10 +31,14 @@ export function is_prod(lcd_client: LCDClient): boolean { return lcd_client.config.chainID.startsWith("columbus"); } +export function is_localterra(lcd_client: LCDClient): boolean { + return lcd_client.config.chainID === "localterra"; +} + // ================================================ export async function init_terraswap_factory(lcd_client: LCDClient, sender: Wallet, cw20_code_id: number): Promise { - if (lcd_client.config.chainID === "localterra") { + if (is_localterra(lcd_client)) { console.log(`in localterra, so storing our own terraswap contracts`); let terraswap_factory_code_id = await store_contract(lcd_client, sender, terraswap_factory_wasm); console.log(`terraswap_factory uploaded\n\tcode_id: ${terraswap_factory_code_id}`); @@ -53,7 +57,7 @@ export async function init_terraswap_factory(lcd_client: LCDClient, sender: Wall } export async function init_astroport_factory(lcd_client: LCDClient, sender: Wallet, cw20_code_id: number): Promise { - if (lcd_client.config.chainID === "localterra") { + if (is_localterra(lcd_client)) { console.log(`in localterra, so storing our own astroport contracts`); let astroport_factory_code_id = await store_contract(lcd_client, sender, astroport_factory_wasm); console.log(`astroport_factory uploaded\n\tcode_id: ${astroport_factory_code_id}`); @@ -305,6 +309,13 @@ export interface BassetVaultStrategyConfig { basset_max_ltv: string, buffer_part: string, price_timeframe: number, + anchor_market_addr: string, + anchor_interest_model_addr: string, + anchor_overseer_addr: string, + anchor_token_addr: string, + anc_ust_swap_addr: string, + staking_apr: string, + holding_window: string, } export function prod_BassetVaultStrategyConfigForbLuna(governance_contract_addr: string): BassetVaultStrategyConfig { @@ -319,6 +330,13 @@ export function prod_BassetVaultStrategyConfigForbLuna(governance_contract_addr: basset_max_ltv: "0.6", buffer_part: "0.018", price_timeframe: 25, + anchor_market_addr: "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s", + anchor_interest_model_addr: "terra1kq8zzq5hufas9t0kjsjc62t2kucfnx8txf547n", + anchor_overseer_addr: "terra1tmnqgvg567ypvsvk6rwsga3srp7e3lg6u0elp8", + anchor_token_addr: "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + anc_ust_swap_addr: "terra1qr2k6yjjd5p2kaewqvg93ag74k6gyjr7re37fs", + staking_apr: "0.0", + holding_window: "0.02", } } @@ -334,6 +352,13 @@ export function testnet_BassetVaultStrategyConfigForbLuna(governance_contract_ad basset_max_ltv: "0.6", buffer_part: "0.018", price_timeframe: 25, + anchor_market_addr: "terra15dwd5mj8v59wpj0wvt233mf5efdff808c5tkal", + anchor_interest_model_addr: "terra1m25aqupscdw2kw4tnq5ql6hexgr34mr76azh5x", + anchor_overseer_addr: "terra1qljxd0y3j3gk97025qvl3lgq8ygup4gsksvaxv", + anchor_token_addr: "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc", + anc_ust_swap_addr: "terra1wfvczps2865j0awnurk9m04u7wdmd6qv3fdnvz", + staking_apr: "0.0", + holding_window: "0.02", } } @@ -357,6 +382,13 @@ export function prod_BassetVaultStrategyConfigForbEth(governance_contract_addr: basset_max_ltv: "0.6", buffer_part: "0.018", price_timeframe: 25, + anchor_market_addr: "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s", + anchor_interest_model_addr: "terra1kq8zzq5hufas9t0kjsjc62t2kucfnx8txf547n", + anchor_overseer_addr: "terra1tmnqgvg567ypvsvk6rwsga3srp7e3lg6u0elp8", + anchor_token_addr: "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + anc_ust_swap_addr: "terra1qr2k6yjjd5p2kaewqvg93ag74k6gyjr7re37fs", + staking_apr: "0.0", + holding_window: "0.02", } } @@ -372,6 +404,13 @@ export function testnet_BassetVaultStrategyConfigForbEth(governance_contract_add basset_max_ltv: "0.6", buffer_part: "0.018", price_timeframe: 25, + anchor_market_addr: "terra15dwd5mj8v59wpj0wvt233mf5efdff808c5tkal", + anchor_interest_model_addr: "terra1m25aqupscdw2kw4tnq5ql6hexgr34mr76azh5x", + anchor_overseer_addr: "terra1qljxd0y3j3gk97025qvl3lgq8ygup4gsksvaxv", + anchor_token_addr: "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc", + anc_ust_swap_addr: "terra1wfvczps2865j0awnurk9m04u7wdmd6qv3fdnvz", + staking_apr: "0.0", + holding_window: "0.02", } } @@ -429,7 +468,8 @@ export interface BassetVaultConfig { ///fees, need to calc how much send to governance and community pools fee_rate: string, tax_rate: string, - ts_factory_addr: string + ts_factory_addr: string, + a_basset_reward_addr: string, } export function prod_BassetVaultConfigForbLuna( @@ -442,7 +482,7 @@ export function prod_BassetVaultConfigForbLuna( psi_token_addr: string, psi_stable_swap_contract_addr: string, basset_vault_strategy_contract_addr: string, - ts_factory_addr: string + ts_factory_addr: string, ): BassetVaultConfig { return { gov_addr: governance_contract_addr, @@ -474,6 +514,7 @@ export function prod_BassetVaultConfigForbLuna( fee_rate: "0.5", tax_rate: "0.25", ts_factory_addr: ts_factory_addr, + a_basset_reward_addr: "terra17yap3mhph35pcwvhza38c2lkj7gzywzy05h7l0", } } @@ -487,7 +528,7 @@ export function testnet_BassetVaultConfigForbLuna( psi_token_addr: string, psi_stable_swap_contract_addr: string, basset_vault_strategy_contract_addr: string, - ts_factory_addr: string + ts_factory_addr: string, ): BassetVaultConfig { return { gov_addr: governance_contract_addr, @@ -518,7 +559,8 @@ export function testnet_BassetVaultConfigForbLuna( ///fees, need to calc how much send to governance and community pools fee_rate: "0.5", tax_rate: "0.25", - ts_factory_addr: ts_factory_addr + ts_factory_addr: ts_factory_addr, + a_basset_reward_addr: "terra1ac24j6pdxh53czqyrkr6ygphdeftg7u3958tl2", } } @@ -533,7 +575,7 @@ export function BassetVaultConfigForbLuna( psi_token_addr: string, psi_stable_swap_contract_addr: string, basset_vault_strategy_contract_addr: string, - ts_factory_addr: string + ts_factory_addr: string, ): BassetVaultConfig { if (is_prod(lcd_client)) { return prod_BassetVaultConfigForbLuna( @@ -546,7 +588,7 @@ export function BassetVaultConfigForbLuna( psi_token_addr, psi_stable_swap_contract_addr, basset_vault_strategy_contract_addr, - ts_factory_addr + ts_factory_addr, ); } else { return testnet_BassetVaultConfigForbLuna( @@ -559,7 +601,7 @@ export function BassetVaultConfigForbLuna( psi_token_addr, psi_stable_swap_contract_addr, basset_vault_strategy_contract_addr, - ts_factory_addr + ts_factory_addr, ); } } @@ -605,7 +647,8 @@ export function prod_BassetVaultConfigForbEth( ///fees, need to calc how much send to governance and community pools fee_rate: "0.5", tax_rate: "0.25", - ts_factory_addr: ts_factory_addr + ts_factory_addr: ts_factory_addr, + a_basset_reward_addr: "terra1939tzfn4hn960ychpcsjshu8jds3zdwlp8jed9", } } @@ -619,7 +662,7 @@ export function testnet_BassetVaultConfigForbEth( psi_token_addr: string, psi_stable_swap_contract_addr: string, basset_vault_strategy_contract_addr: string, - ts_factory_addr: string + ts_factory_addr: string, ): BassetVaultConfig { return { gov_addr: governance_contract_addr, @@ -650,7 +693,8 @@ export function testnet_BassetVaultConfigForbEth( ///fees, need to calc how much send to governance and community pools fee_rate: "0.5", tax_rate: "0.25", - ts_factory_addr: ts_factory_addr + ts_factory_addr: ts_factory_addr, + a_basset_reward_addr: "terra1ja3snkedk4t0zp7z3ljd064hcln8dsv5x004na", } } @@ -665,7 +709,7 @@ export function BassetVaultConfigForbEth( psi_token_addr: string, psi_stable_swap_contract_addr: string, basset_vault_strategy_contract_addr: string, - ts_factory_addr: string + ts_factory_addr: string, ): BassetVaultConfig { if (is_prod(lcd_client)) { return prod_BassetVaultConfigForbEth( @@ -691,7 +735,7 @@ export function BassetVaultConfigForbEth( psi_token_addr, psi_stable_swap_contract_addr, basset_vault_strategy_contract_addr, - ts_factory_addr + ts_factory_addr, ); } } diff --git a/src/integration_tests/basset_vault/config.ts b/src/integration_tests/basset_vault/config.ts index 3308704..c648eda 100644 --- a/src/integration_tests/basset_vault/config.ts +++ b/src/integration_tests/basset_vault/config.ts @@ -38,6 +38,7 @@ export interface AddressesHolderConfig { aterra_token_addr: string, anchor_oracle_addr: string, anchor_overseer_addr: string, + anchor_interest_model_addr: string, basset_vault_for_bluna_addr: string, nluna_token_addr: string, basset_vault_for_beth_addr: string, @@ -47,6 +48,7 @@ export interface AddressesHolderConfig { anchor_custody_bluna_addr: string, beth_token_addr: string, anchor_custody_beth_addr: string, + anc_stable_swap_addr: string, } export function AddressesHolderConfig( @@ -60,6 +62,7 @@ export function AddressesHolderConfig( aterra_token_addr: anchor_market_info.aterra_token_addr, anchor_oracle_addr: anchor_market_info.oracle_addr, anchor_overseer_addr: anchor_market_info.overseer_addr, + anchor_interest_model_addr: anchor_market_info.interest_model_addr, basset_vault_for_bluna_addr: basset_vault_info_for_bluna.addr, nluna_token_addr: basset_vault_info_for_bluna.nasset_token_addr, basset_vault_for_beth_addr: basset_vault_info_for_beth.addr, @@ -69,6 +72,7 @@ export function AddressesHolderConfig( anchor_custody_bluna_addr: anchor_market_info.bluna_custody_addr, beth_token_addr: anchor_market_info.beth_token_addr, anchor_custody_beth_addr: anchor_market_info.beth_custody_addr, + anc_stable_swap_addr: anchor_market_info.anc_stable_swap_addr, } } @@ -89,3 +93,11 @@ export interface AnchorStateResponse { prev_exchange_rate: string, } +export interface PoolResponse { + assets: Asset[], + total_share: string, +} + +export interface Asset { + amount: string, +} diff --git a/src/integration_tests/basset_vault/definition.ts b/src/integration_tests/basset_vault/definition.ts index 24d38f3..bff4d4e 100644 --- a/src/integration_tests/basset_vault/definition.ts +++ b/src/integration_tests/basset_vault/definition.ts @@ -1,8 +1,8 @@ -import {BlockTxBroadcastResult, Coin, getContractEvents, isTxError, LCDClient, Wallet} from '@terra-money/terra.js'; +import {BlockTxBroadcastResult, Coin, getContractEvents, LCDClient, isTxError, LocalTerra, Wallet} from '@terra-money/terra.js'; import {full_init as full_basset_vault_init} from "../../basset_vault/definition"; import {anchor_init} from "../deploy_anchor/definition"; import {create_contract, execute_contract, sleep} from "../../utils"; -import {LOCALTERRA_DEFAULT_VALIDATOR_ADDR} from "../deploy_anchor/config"; +import {LOCALTERRA_DEFAULT_VALIDATOR_ADDR, Uint256} from "../deploy_anchor/config"; import { AddressesHolderConfig, AnchorEpochStateResponse, @@ -10,6 +10,7 @@ import { BalanceResponse, BorrowerInfoResponse, CollateralsResponse, + PoolResponse, TokenInfoResponse, } from "./config" import {isTxSuccess} from "../../transaction"; @@ -18,11 +19,11 @@ import Decimal from 'decimal.js'; // =================================================== const addresses_holder_wasm = "wasm_artifacts/utils/addr_holder.wasm"; - // =================================================== - +const number_of_blocks_per_year = 4656810; +// =================================================== export async function borrow_zero_amount_issue(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { - + console.log(`-= Start 'borrow_zero_amount_issue' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const bluna_token_addr = addresses.bluna_token_addr; @@ -31,11 +32,12 @@ export async function borrow_zero_amount_issue(lcd_client: LCDClient, sender: Wa const basset_vault_for_bluna_addr = addresses.basset_vault_for_bluna_addr; //========================================== - const luna_to_bond = 10; + const luna_to_bond = 7; await feed_price(lcd_client, sender, oracle_addr, bluna_token_addr, 1); await bond_luna(lcd_client, sender, bluna_hub_addr, luna_to_bond); const bluna_to_deposit = await get_token_balance(lcd_client, sender.key.accAddress, bluna_token_addr); //deposit all bluna in contract + console.log("Bluna to deposit:", bluna_to_deposit); await deposit_bluna(lcd_client, sender, bluna_token_addr, basset_vault_for_bluna_addr, bluna_to_deposit); const expected_query_rebalance = { @@ -49,7 +51,7 @@ export async function borrow_zero_amount_issue(lcd_client: LCDClient, sender: Wa } export async function simple_deposit(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { - + console.log(`-= Start 'simple_deposit' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -89,6 +91,7 @@ export async function simple_deposit(lcd_client: LCDClient, sender: Wallet, addr let expected_farmer_nluna_balance_after_deposit = farmer_nluna_balance_before_deposit + additional_nluna_amount; const deposit_result = await deposit_bluna(lcd_client, sender, bluna_token_addr, basset_vault_for_bluna_addr, bluna_to_deposit); + if (deposit_result == undefined) { throw new Error( `Deposit basset failed` @@ -121,6 +124,7 @@ export async function simple_deposit(lcd_client: LCDClient, sender: Wallet, addr } export async function borrow_more_on_bluna_price_increasing(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'borrow_more_on_bluna_price_increasing' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -147,7 +151,6 @@ export async function borrow_more_on_bluna_price_increasing(lcd_client: LCDClien //locked_basset * bluna_price * basset_max_ltv(0,6) * borrow_ltv_aim(0,8) let user_liability = Math.round(collateral * bluna_price * 0.6 * 0.8); await assert_loan(lcd_client, anchor_market_addr, basset_vault_for_bluna_addr, user_liability); - bluna_price = bluna_price * 2; await feed_price(lcd_client, sender, oracle_addr, bluna_token_addr, bluna_price); @@ -162,6 +165,7 @@ export async function borrow_more_on_bluna_price_increasing(lcd_client: LCDClien } export async function repay_on_bluna_price_decreasing(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'repay_on_bluna_price_decreasing' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -202,7 +206,10 @@ export async function repay_on_bluna_price_decreasing(lcd_client: LCDClient, sen console.log(`basset_vault_for_bluna test: "repay_on_bluna_price_decreasing" passed!`); } +// Run this test with default localterra config, otherwise there is a big inaccuracy. +// For more info see comment for the `assert_loan` fn export async function recursive_repay_ok(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'recursive_repay_ok' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -235,7 +242,7 @@ export async function recursive_repay_ok(lcd_client: LCDClient, sender: Wallet, await redeem_stable(lcd_client, sender, aust_token_addr, anchor_market_addr, aust_to_burn); anchor_ust_balance = await query_stable_balance(lcd_client, anchor_market_addr); //check whether there is no UST in anchor_market - assert_numbers_with_inaccuracy(anchor_initial_funds, anchor_ust_balance, 10); + assert_numbers_with_inaccuracy(anchor_initial_funds, anchor_ust_balance, 50); let actual_borrower_info: BorrowerInfoResponse = await lcd_client.wasm.contractQuery(anchor_market_addr, { borrower_info: { @@ -253,8 +260,10 @@ export async function recursive_repay_ok(lcd_client: LCDClient, sender: Wallet, // According to basset_vault_config it's impossible to withdraw more bAsset than 18% of nAsset total supply. // There is only one farmer in our test => farmer nAsset balance is equal to total nAsset supply. // That's why only 15% of deposited bluna to withdraw. - const part_to_withdraw = 0.15; - const withdraw_result = await withdraw_bluna(lcd_client, sender, nluna_token_addr, basset_vault_for_bluna_addr, bluna_to_deposit * part_to_withdraw); + let part_to_withdraw = 0.15; + const amount_to_withdraw = Math.ceil(bluna_to_deposit * part_to_withdraw) + part_to_withdraw = amount_to_withdraw / bluna_to_deposit; + const withdraw_result = await withdraw_bluna(lcd_client, sender, nluna_token_addr, basset_vault_for_bluna_addr, amount_to_withdraw); if (withdraw_result === undefined) { throw new Error( `Withdraw basset failed` @@ -296,6 +305,7 @@ export async function recursive_repay_ok(lcd_client: LCDClient, sender: Wallet, // Repay iterations amount assert shows that its equal to max iterations amount. // Next 3 assets show that loan is not repayed as expected but basset withdrawn and nasset burned export async function recursive_repay_fail(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'recursive_repay_fail' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -308,7 +318,7 @@ export async function recursive_repay_fail(lcd_client: LCDClient, sender: Wallet const nluna_token_addr = addresses.nluna_token_addr; //deposit some UST directly to anchor_marker in order to basset_vault could borrow it - const initial_ust_for_anchor = 100_000_000; + const initial_ust_for_anchor = 99_000_000; await deposit_stable(lcd_client, sender, anchor_market_addr, initial_ust_for_anchor); const luna_to_bond = 100_000_000; @@ -373,6 +383,7 @@ export async function recursive_repay_fail(lcd_client: LCDClient, sender: Wallet } export async function expired_basset_price_rebalance(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'expired_basset_price_rebalance' test =-`); const addresses = await get_addresses(lcd_client, addresses_holder_addr); const anchor_market_addr = addresses.anchor_market_addr; @@ -412,6 +423,179 @@ export async function expired_basset_price_rebalance(lcd_client: LCDClient, send console.log(`basset_vault_for_bluna test: "expired_bluna_price" passed!`); } +export async function withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive' test =-`); + const addresses = await get_addresses(lcd_client, addresses_holder_addr); + + const bluna_price = 1; + await feed_price(lcd_client, sender, addresses.anchor_oracle_addr, addresses.bluna_token_addr, bluna_price); + + await deposit_stable(lcd_client, sender, addresses.anchor_market_addr, 100_000_000); + + const borrow_apr = await query_anchor_borrow_net_apr(lcd_client, addresses); + const earn_apr = await query_anchor_earn_apr(lcd_client, addresses); + const anchor_apr = borrow_apr + earn_apr; + assert(anchor_apr > 0); + + await bond_luna(lcd_client, sender, addresses.bluna_hub_addr, 10_000_000); + const bluna_to_deposit = await get_token_balance(lcd_client, sender.key.accAddress, addresses.bluna_token_addr); + + console.log("Bluna to deposit", bluna_to_deposit); + + await deposit_bluna(lcd_client, sender, addresses.bluna_token_addr, addresses.basset_vault_for_bluna_addr, bluna_to_deposit); + + const collateral = await get_collateral_amount(lcd_client, addresses.anchor_overseer_addr, addresses.basset_vault_for_bluna_addr); + assert_numbers_with_inaccuracy(bluna_to_deposit, collateral, 10); + + await provide_liquidity_to_nasset_psi_swap(lcd_client, sender, addresses, "300000000"); + + await sleep(1000); + + const borrower_info_before_honest_work: BorrowerInfoResponse = await lcd_client.wasm.contractQuery(addresses.anchor_market_addr, { + borrower_info: { + borrower: addresses.basset_vault_for_bluna_addr, + } + }); + + const honest_work = await execute_contract(lcd_client, sender, addresses.basset_vault_for_bluna_addr, { + anyone: { + anyone_msg: { + honest_work: {}, + }, + }, + }); + + const borrower_info_after_honest_work: BorrowerInfoResponse = await lcd_client.wasm.contractQuery(addresses.anchor_market_addr, { + borrower_info: { + borrower: addresses.basset_vault_for_bluna_addr, + } + }); + + assert(borrower_info_before_honest_work.pending_rewards > borrower_info_after_honest_work.pending_rewards, `Pending reward after honest work: ${borrower_info_after_honest_work.pending_rewards}, before: ${borrower_info_before_honest_work.pending_rewards}, transaction: ${JSON.stringify(honest_work)}`); + + const basset_vault_strategy_addr = await query_basset_vault_strategy_addr(lcd_client, addresses.basset_vault_for_bluna_addr); + + // Increase stacking apr to make bvault rebalance to holding + await execute_contract(lcd_client, sender, basset_vault_strategy_addr, { + governance: { + governance_msg: { + update_config: { + staking_apr: (anchor_apr * 1.5).toFixed(8), + } + } + } + }); + + await rebalance(lcd_client, sender, addresses.basset_vault_for_bluna_addr); + + const borrower_info: BorrowerInfoResponse = await lcd_client.wasm.contractQuery(addresses.anchor_market_addr, { + borrower_info: { + borrower: addresses.basset_vault_for_bluna_addr, + } + }); + assert(Number(borrower_info.loan_amount) == 0, `Loan amount after rebalance when apr is negative: ${borrower_info.loan_amount}`); + + { + const collateral = await get_collateral_amount(lcd_client, addresses.anchor_overseer_addr, addresses.basset_vault_for_bluna_addr); + const vault_bassest_balance = await get_token_balance(lcd_client, addresses.basset_vault_for_bluna_addr, addresses.bluna_token_addr); + console.log(`Vault state after rebalance when anchor became not profitable. Collateral: ${collateral}, balance: ${vault_bassest_balance}`); + assert(bluna_to_deposit == vault_bassest_balance); + assert(collateral == 0); + } + + // Make stacking apr zero again to make bvault rebalance to anchor + await execute_contract(lcd_client, sender, basset_vault_strategy_addr, { + governance: { + governance_msg: { + update_config: { + staking_apr: "0.0", + } + } + } + }); + + await feed_price(lcd_client, sender, addresses.anchor_oracle_addr, addresses.bluna_token_addr, bluna_price); + + await rebalance(lcd_client, sender, addresses.basset_vault_for_bluna_addr); + + { + const collateral = await get_collateral_amount(lcd_client, addresses.anchor_overseer_addr, addresses.basset_vault_for_bluna_addr); + const vault_bassest_balance = await get_token_balance(lcd_client, addresses.basset_vault_for_bluna_addr, addresses.bluna_token_addr); + console.log(`Vault state after rebalance when anchor has became profitable again. Collateral: ${collateral}, balance: ${vault_bassest_balance}`); + assert(bluna_to_deposit == collateral); + assert(vault_bassest_balance == 0); + } + + console.log("withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive test passed!") +} + +export async function anchor_apr_calculation(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'anchor_apr_calculation' test =-`); + const addresses = await get_addresses(lcd_client, addresses_holder_addr); + + const basset_vault_strategy_addr = await query_basset_vault_strategy_addr(lcd_client, addresses.basset_vault_for_bluna_addr); + + await execute_contract(lcd_client, sender, addresses.anchor_overseer_addr, { + execute_epoch_operations: {} + }); + + const anchor_apr = await lcd_client.wasm.contractQuery(basset_vault_strategy_addr, { + anchor_apr: {}, + }) as { + earn: number, + borrow: { + distribution_apr: number, + interest_apr: number, + }, + }; + + const borrow_apr = await query_anchor_borrow_net_apr(lcd_client, addresses); + + let queried_borrow_apr = anchor_apr.borrow.distribution_apr - anchor_apr.borrow.interest_apr; + assert_numbers_with_inaccuracy(borrow_apr, queried_borrow_apr, 0.01); // inaccuracy is less than 1 % + + const earn_apr = await query_anchor_earn_apr(lcd_client, addresses); + assert_numbers_with_inaccuracy(earn_apr, anchor_apr.earn, 0.01); // inaccuracy is less than 1 % + + console.log(`Apr calculation test passed:\n\tEarn apr. Expected: ${earn_apr}, calculated: ${anchor_apr.earn}\n\tBorrow apr. Expected: ${borrow_apr}, calculated: ${queried_borrow_apr}`); +} + +export async function bvault_deposit_and_withdraw_half(lcd_client: LCDClient, sender: Wallet, addresses_holder_addr: string) { + console.log(`-= Start 'bvault_deposit_and_withdraw_half' test =-`); + const addresses = await get_addresses(lcd_client, addresses_holder_addr); + + const bluna_price = 1; + await feed_price(lcd_client, sender, addresses.anchor_oracle_addr, addresses.bluna_token_addr, bluna_price); + + await deposit_stable(lcd_client, sender, addresses.anchor_market_addr, 100_000_000); + + await bond_luna(lcd_client, sender, addresses.bluna_hub_addr, 1_000_000); + + const bluna_to_deposit = await get_token_balance(lcd_client, sender.key.accAddress, addresses.bluna_token_addr); + console.log("Bluna to deposit", bluna_to_deposit); + + await deposit_bluna(lcd_client, sender, addresses.bluna_token_addr, addresses.basset_vault_for_bluna_addr, bluna_to_deposit); + + const bluna_to_withdraw = Math.floor(bluna_to_deposit / 2); + + for (let i = 0; i < 10; i++) { + const check_bal = await get_token_balance(lcd_client, sender.key.accAddress, addresses.bluna_token_addr); + if (check_bal > 0) { + break; + } + + await withdraw_bluna(lcd_client, sender, addresses.nluna_token_addr, addresses.basset_vault_for_bluna_addr, bluna_to_withdraw); + } + + let bluna_balance = await get_token_balance(lcd_client, sender.key.accAddress, addresses.bluna_token_addr); + let collateral = await get_collateral_amount(lcd_client, addresses.anchor_overseer_addr, addresses.basset_vault_for_bluna_addr); + + assert(bluna_balance === bluna_to_withdraw, `expected balance: ${bluna_to_withdraw}, actual balance: ${bluna_balance}`); + assert(collateral === (bluna_to_deposit - bluna_to_withdraw), `collateral expected: ${bluna_to_deposit - bluna_to_withdraw}, collateral actual: ${collateral}`); + + console.log(`bvault_deposit_and_withdraw_half test passed`); +} + export async function anchor_nexus_full_init( lcd_client: LCDClient, sender: Wallet, @@ -435,9 +619,248 @@ export async function anchor_nexus_full_init( const addresses_holder_config = AddressesHolderConfig(anchor_market_info, basset_vault_info_for_bluna, basset_vault_info_for_beth); const addresses_holder_addr = await create_contract(lcd_client, sender, "addrs_holder", addresses_holder_wasm, addresses_holder_config); + await setup_anchor_token_distributor(lcd_client, sender, addresses_holder_config); + await provide_liquidity_to_anc_stable_swap(lcd_client, sender, addresses_holder_config); + await provide_liquidity_to_psi_stable_swap(lcd_client, sender, addresses_holder_config); + await setup_anchor(lcd_client, sender, addresses_holder_config); + return addresses_holder_addr; } +async function setup_anchor_token_distributor(lcd_client: LCDClient, sender: Wallet, addresses: AddressesHolderConfig) { + const config = await lcd_client.wasm.contractQuery(addresses.anchor_market_addr, { + config: {}, + }) as { + distributor_contract: string, + }; + await execute_contract(lcd_client, sender, addresses.anchor_token_addr, { + mint: { + recipient: config.distributor_contract, + amount: '1000000000000000', + } + }); +} + +async function provide_liquidity_to_token_stable_swap( + lcd_client: LCDClient, + sender: Wallet, + swap_pair_addr: string, + token_addr: string, + token_amount: Uint256, + stable_amount: Uint256, +) { + await execute_contract(lcd_client, sender, token_addr, { + increase_allowance: { + spender: swap_pair_addr, + amount: token_amount, + } + }); + + await execute_contract(lcd_client, sender, swap_pair_addr, { + provide_liquidity: { + assets: [ + { + info: { + token: { + contract_addr: token_addr, + } + }, + amount: token_amount, + }, + { + info: { + native_token: { + denom: "uusd" + } + }, + amount: stable_amount, + } + ] + } + }, [new Coin("uusd", stable_amount)]); +} + +async function provide_liquidity_to_anc_stable_swap(lcd_client: LCDClient, sender: Wallet, addresses: AddressesHolderConfig) { + let anc_amount = "100000000000000"; + let stable_amount = "300000000000000"; + + await execute_contract(lcd_client, sender, addresses.anchor_token_addr, { + mint: { + recipient: sender.key.accAddress, + amount: anc_amount, + } + }); + + await provide_liquidity_to_token_stable_swap(lcd_client, sender, addresses.anc_stable_swap_addr, addresses.anchor_token_addr, anc_amount, stable_amount); +} + +async function provide_liquidity_to_psi_stable_swap(lcd_client: LCDClient, sender: Wallet, addresses: AddressesHolderConfig) { + let amount = "300000000000000"; + + const basset_config = await lcd_client.wasm.contractQuery(addresses.basset_vault_for_bluna_addr, { + config: {}, + }) as { + psi_stable_swap_contract_addr: string, + psi_token_addr: string, + }; + + await provide_liquidity_to_token_stable_swap(lcd_client, sender, basset_config.psi_stable_swap_contract_addr, basset_config.psi_token_addr, amount, amount); +} + +async function setup_anchor(lcd_client: LCDClient, sender: Wallet, addresses: AddressesHolderConfig) { + const bluna_token_addr = addresses.bluna_token_addr; + + await feed_price(lcd_client, sender, addresses.anchor_oracle_addr, bluna_token_addr, 1); + + await deposit_stable(lcd_client, sender, addresses.anchor_market_addr, "10000000000"); + + const bluna_to_deposit = "15000000000"; + + await bond_luna(lcd_client, sender, addresses.bluna_hub_addr, bluna_to_deposit); + + await get_token_balance(lcd_client, sender.key.accAddress, bluna_token_addr); + + const send_bluna_msg = { + deposit_collateral: {} + }; + + await execute_contract(lcd_client, sender, bluna_token_addr, { + send: { + contract: addresses.anchor_custody_bluna_addr, + amount: bluna_to_deposit, + msg: Buffer.from(JSON.stringify(send_bluna_msg)).toString('base64'), + } + }); + + await execute_contract(lcd_client, sender, addresses.anchor_overseer_addr, { + lock_collateral: { + collaterals: [[bluna_token_addr, String(bluna_to_deposit)]] + } + }); + + const ust_to_borrow = "9000000000"; + + await execute_contract(lcd_client, sender, addresses.anchor_market_addr, { + borrow_stable: { + borrow_amount: ust_to_borrow, + } + }); +} + +async function query_anchor_borrow_net_apr(lcd_client: LCDClient, addresses: AddressesHolderConfig): Promise { + const market_state = await lcd_client.wasm.contractQuery(addresses.anchor_market_addr, { + state: {}, + }) as { + total_liabilities: string, + total_reserves: string, + anc_emission_rate: string, + }; + + const coins = await lcd_client.bank.balance(addresses.anchor_market_addr); + + let borrow_rate = await lcd_client.wasm.contractQuery(addresses.anchor_interest_model_addr, { + borrow_rate: { + market_balance: coins.get('uusd')?.amount, + total_liabilities: market_state.total_liabilities, + total_reserves: market_state.total_reserves, + }, + }) as { + rate: string, + }; + + let anc_price = await query_anchor_price(lcd_client, addresses); + + let distribution_apr = Number(market_state.anc_emission_rate) * anc_price * number_of_blocks_per_year / Number(market_state.total_liabilities); + + let interest_apr = Number(borrow_rate.rate) * number_of_blocks_per_year; + + let net_apr = distribution_apr - interest_apr; + + return net_apr; +} + +async function query_anchor_earn_apr(lcd_client: LCDClient, addresses: AddressesHolderConfig): Promise { + let epoch_state = await lcd_client.wasm.contractQuery(addresses.anchor_overseer_addr, { + epoch_state: {}, + }) as { + deposit_rate: number, + }; + + return epoch_state.deposit_rate * number_of_blocks_per_year; +} + +async function query_anchor_price(lcd_client: LCDClient, addresses: AddressesHolderConfig): Promise { + const pool: PoolResponse = await lcd_client.wasm.contractQuery(addresses.anc_stable_swap_addr, { + pool: {} + }); + const [anc_asset, ust_asset] = pool.assets; + return Number(ust_asset.amount) / Number(anc_asset.amount); +} + +async function query_basset_vault_strategy_addr(lcd_client: LCDClient, basset_vault_addr: string): Promise { + const config = await lcd_client.wasm.contractQuery(basset_vault_addr, { + config: {}, + }) as { + basset_vault_strategy_contract_addr: string, + }; + return config.basset_vault_strategy_contract_addr; +} + +async function provide_liquidity_to_nasset_psi_swap(lcd_client: LCDClient, sender: Wallet, addresses: AddressesHolderConfig, amount: string) { + const basset_config = await lcd_client.wasm.contractQuery(addresses.basset_vault_for_bluna_addr, { + config: {}, + }) as { + psi_distributor_addr: string, + psi_token_addr: string, + nasset_token_addr: string, + }; + + const psi_distributor_config = await lcd_client.wasm.contractQuery(basset_config.psi_distributor_addr, { + config: {}, + }) as { + nasset_psi_swap_contract_addr: string, + }; + + let nasset_amount = (await get_token_balance(lcd_client, sender.key.accAddress, basset_config.nasset_token_addr)).toString(); + + await execute_contract(lcd_client, sender, basset_config.psi_token_addr, { + increase_allowance: { + spender: psi_distributor_config.nasset_psi_swap_contract_addr, + amount, + } + }); + + await execute_contract(lcd_client, sender, basset_config.nasset_token_addr, { + increase_allowance: { + spender: psi_distributor_config.nasset_psi_swap_contract_addr, + amount: nasset_amount, + } + }); + + await execute_contract(lcd_client, sender, psi_distributor_config.nasset_psi_swap_contract_addr, { + provide_liquidity: { + assets: [ + { + info: { + token: { + contract_addr: basset_config.psi_token_addr, + } + }, + amount, + }, + { + info: { + token: { + contract_addr: basset_config.nasset_token_addr, + } + }, + amount: nasset_amount, + }, + ] + } + }); +} + async function register_basset_price_feeder(lcd_client: LCDClient, sender: Wallet, oracle_addr: string, basset_token_addr: string) { await execute_contract(lcd_client, sender, oracle_addr, { register_feeder: { @@ -468,7 +891,7 @@ async function feed_price(lcd_client: LCDClient, sender: Wallet, oracle_addr: st return result; } -async function bond_luna(lcd_client: LCDClient, sender: Wallet, bluna_hub_addr: string, amount: number) { +async function bond_luna(lcd_client: LCDClient, sender: Wallet, bluna_hub_addr: string, amount: number | string) { const bond_result = await execute_contract(lcd_client, sender, bluna_hub_addr, { bond: { @@ -528,7 +951,7 @@ async function rebalance(lcd_client: LCDClient, sender: Wallet, basset_vault_add } } -async function deposit_stable(lcd_client: LCDClient, sender: Wallet, anchor_market_contract: string, amount: number) { +async function deposit_stable(lcd_client: LCDClient, sender: Wallet, anchor_market_contract: string, amount: number | string) { await sleep(500); const deposit_result = await execute_contract( @@ -649,5 +1072,8 @@ async function calculate_repay_cycles_amount(result: BlockTxBroadcastResult) { function assert_numbers_with_inaccuracy(expected: number, actual: number, inaccuracy: number) { let diff = Math.abs(expected - actual); + if (diff > inaccuracy) { + console.log(`Expected: ${expected}, actual: ${actual}`); + } assert(diff <= inaccuracy); -} \ No newline at end of file +} diff --git a/src/integration_tests/basset_vault/executor.ts b/src/integration_tests/basset_vault/executor.ts index 42a77fd..68b3003 100644 --- a/src/integration_tests/basset_vault/executor.ts +++ b/src/integration_tests/basset_vault/executor.ts @@ -1,6 +1,7 @@ import {Command} from 'commander'; import {get_lcd_config_with_wallet_for_integration_tests_only} from "../utils"; import { + anchor_apr_calculation, anchor_nexus_full_init, borrow_more_on_bluna_price_increasing, borrow_zero_amount_issue, @@ -8,7 +9,9 @@ import { simple_deposit, recursive_repay_ok, repay_on_bluna_price_decreasing, + withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive, recursive_repay_fail, + bvault_deposit_and_withdraw_half, } from "./definition"; async function run_program() { @@ -16,12 +19,14 @@ async function run_program() { program .action(async () => { - const addresses_holder_addr = await deploy(); - await run_recursive_repay_ok(addresses_holder_addr); - await run_simple_deposit(addresses_holder_addr); - await run_borrow_more_on_bluna_price_increasing(addresses_holder_addr); - await run_repay_on_bluna_price_decreasing(addresses_holder_addr); - await run_expired_basset_price_rebalance(addresses_holder_addr); + // await run_recursive_repay_ok(await deploy()); + await run_simple_deposit(await deploy()); + await run_borrow_more_on_bluna_price_increasing(await deploy()); + await run_repay_on_bluna_price_decreasing(await deploy()); + await run_expired_basset_price_rebalance(await deploy()); + await run_anchor_apr_calculation(await deploy()); + await run_withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive(await deploy()); + await run_bvault_deposit_and_withdraw_half(await deploy()); }); program @@ -34,6 +39,9 @@ async function run_program() { .command('simple_deposit') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_simple_deposit(options.address); }); @@ -41,6 +49,9 @@ async function run_program() { .command('borrow_zero_amount_issue') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_borrow_zero_amount_issue(options.address); }); @@ -48,6 +59,9 @@ async function run_program() { .command('borrow_more_on_bluna_price_increasing') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_borrow_more_on_bluna_price_increasing(options.address); }); @@ -55,6 +69,9 @@ async function run_program() { .command('repay_on_bluna_price_decreasing') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_repay_on_bluna_price_decreasing(options.address); }); @@ -62,6 +79,9 @@ async function run_program() { .command('recursive_repay_ok') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_recursive_repay_ok(options.address); }); @@ -69,6 +89,9 @@ async function run_program() { .command('recursive_repay_fail') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_recursive_repay_fail(options.address); }); @@ -76,9 +99,42 @@ async function run_program() { .command('expired_basset_price_rebalance') .option('-A, --address
', `addresses holder contract address`) .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } await run_expired_basset_price_rebalance(options.address); }); + program + .command('anchor_apr_calculation') + .option('-A, --address
', 'addresses holder contract address') + .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } + await run_anchor_apr_calculation(options.address); + }); + + program + .command('withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive') + .option('-A, --address
', 'addresses holder contract address') + .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } + await run_withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive(options.address); + }); + + program + .command('bvault_deposit_and_withdraw_half') + .option('-A, --address
', 'addresses holder contract address') + .action(async (options) => { + if (options.address == undefined) { + options.address = await deploy(); + } + await run_bvault_deposit_and_withdraw_half(options.address); + }); + await program.parseAsync(process.argv); } @@ -130,4 +186,19 @@ async function run_recursive_repay_fail(addresses_holder_addr: string) { async function run_expired_basset_price_rebalance(addresses_holder_addr: string) { const [lcd_client, sender] = await get_lcd_config_with_wallet_for_integration_tests_only(); await expired_basset_price_rebalance(lcd_client, sender, addresses_holder_addr); -} \ No newline at end of file +} + +async function run_anchor_apr_calculation(addresses_holder_addr: string) { + const [lcd_client, sender] = await get_lcd_config_with_wallet_for_integration_tests_only(); + await anchor_apr_calculation(lcd_client, sender, addresses_holder_addr); +} + +async function run_withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive(addresses_holder_addr: string) { + const [lcd_client, sender] = await get_lcd_config_with_wallet_for_integration_tests_only(); + await withdraw_all_on_negative_profit_and_deposit_to_anchor_back_when_profit_becomes_positive(lcd_client, sender, addresses_holder_addr); +} + +async function run_bvault_deposit_and_withdraw_half(addresses_holder_addr: string) { + const [lcd_client, sender] = await get_lcd_config_with_wallet_for_integration_tests_only(); + await bvault_deposit_and_withdraw_half(lcd_client, sender, addresses_holder_addr); +} diff --git a/src/integration_tests/deploy_anchor/config.ts b/src/integration_tests/deploy_anchor/config.ts index d0282eb..d0315bd 100644 --- a/src/integration_tests/deploy_anchor/config.ts +++ b/src/integration_tests/deploy_anchor/config.ts @@ -86,7 +86,7 @@ export function AnchorLiquidationConfig( // ============================================================ -export interface AnchorDistrConfig { +export interface AnchorMoneyMarketDistrModelConfig { decrement_multiplier: Decimal256, emission_cap: Decimal256, emission_floor: Decimal256, @@ -94,9 +94,9 @@ export interface AnchorDistrConfig { owner: Addr, } -export function AnchorDistrConfig( +export function AnchorMoneyMarketDistrModelConfig( wallet: Wallet, - ): AnchorDistrConfig{ + ): AnchorMoneyMarketDistrModelConfig{ return { owner: wallet.key.accAddress, emission_cap: '20381363.851572310123647620', @@ -106,6 +106,28 @@ export function AnchorDistrConfig( } } +// ============================================================ + +export interface AnchorTokenDistrConfig { + gov_contract: string, + anchor_token: string, + whitelist: string[], + spend_limit: Uint256, +} + +export function AnchorTokenDistrConfig( + gov_contract: string, + anchor_token: string, + whitelist: string[], + ): AnchorTokenDistrConfig{ + return { + gov_contract, + anchor_token, + whitelist, + spend_limit: '1000000000000000' + } +} + // ============================================================ export interface AnchorOverseerConfig { @@ -147,7 +169,7 @@ export function AnchorOverseerConfig( liquidation_contract: liquidation_contract, collector_contract: wallet.key.accAddress, stable_denom: 'uusd', - epoch_period: 1681, + epoch_period: 50, threshold_deposit_rate: '0.000000030572045778', target_deposit_rate: '0.000000040762727704', buffer_distribution_factor: '0.1', @@ -359,6 +381,7 @@ export function BethTokenConfig( export interface AnchorMarketInfo { contract_addr: Addr, overseer_addr: Addr, + interest_model_addr: Addr, oracle_addr: Addr, basset_hub_addr: Addr, anchor_token_addr: Addr, @@ -368,11 +391,14 @@ export interface AnchorMarketInfo { beth_token_addr: Addr, bluna_custody_addr: Addr, beth_custody_addr: Addr, + bluna_reward_addr: Addr, + beth_reward_addr: Addr, } export function AnchorMarketInfo( contract_addr: Addr, overseer_addr: Addr, + interest_model_addr: Addr, oracle_addr: Addr, basset_hub_addr: Addr, anchor_token_addr: Addr, @@ -382,10 +408,13 @@ export function AnchorMarketInfo( beth_token_addr: Addr, bluna_custody_addr: Addr, beth_custody_addr: Addr, + bluna_reward_addr: Addr, + beth_reward_addr: Addr, ): AnchorMarketInfo { return { contract_addr: contract_addr, overseer_addr: overseer_addr, + interest_model_addr: interest_model_addr, oracle_addr: oracle_addr, basset_hub_addr: basset_hub_addr, anchor_token_addr: anchor_token_addr, @@ -395,6 +424,8 @@ export function AnchorMarketInfo( beth_token_addr: beth_token_addr, bluna_custody_addr: bluna_custody_addr, beth_custody_addr: beth_custody_addr, + bluna_reward_addr: bluna_reward_addr, + beth_reward_addr: beth_reward_addr, } } @@ -415,5 +446,4 @@ export function AnchorAndNexusDeploymentResult( basset_vault_info_for_bluna: basset_vault_info_for_bluna, basset_vault_info_for_beth: basset_vault_info_for_beth, } -} - +} \ No newline at end of file diff --git a/src/integration_tests/deploy_anchor/definition.ts b/src/integration_tests/deploy_anchor/definition.ts index af9cfa7..ee09d82 100644 --- a/src/integration_tests/deploy_anchor/definition.ts +++ b/src/integration_tests/deploy_anchor/definition.ts @@ -9,7 +9,7 @@ import { } from '../../utils'; import { AnchorCustodyBassetConfig, - AnchorDistrConfig, + AnchorMoneyMarketDistrModelConfig, AnchorHubBLunaConfig, AnchorInterestConfig, AnchorLiquidationConfig, @@ -20,7 +20,8 @@ import { BassetRewardConfig, BassetTokenConfig, BethRewardConfig, - BethTokenConfig + BethTokenConfig, + AnchorTokenDistrConfig } from './config'; import {Cw20CodeId, init_astroport_factory, TokenConfig} from '../../config'; @@ -30,6 +31,7 @@ const path_to_anchor_mm_artifacts = `${artifacts_path}/anchor/mm`; const path_to_anchor_basset_artifacts = `${artifacts_path}/anchor/basset`; const path_to_anchor_beth_artifacts = `${artifacts_path}/anchor/beth`; const path_to_anchor_mocks = `${artifacts_path}/anchor/mocks` +const path_to_anchor_token = `${artifacts_path}/anchor/token` //============================================================================= const anchor_market_wasm = `${path_to_anchor_mm_artifacts}/moneymarket_market.wasm`; const anchor_oracle_wasm = `${path_to_anchor_mm_artifacts}/moneymarket_oracle.wasm`; @@ -51,6 +53,8 @@ const anchor_basset_token_wasm = `${path_to_anchor_basset_artifacts}/anchor_bass const anchor_beth_reward_wasm = `${path_to_anchor_beth_artifacts}/anchor_beth_reward.wasm`; const anchor_beth_token_wasm = `${path_to_anchor_beth_artifacts}/anchor_beth_token.wasm`; //============================================================================= +const anchor_token_distributor_wasm = `${path_to_anchor_token}/anchor_distributor.wasm`; +//============================================================================= //STEPS: // 1. deploy cw20 tokens @@ -179,8 +183,8 @@ async function anchor_init_verbose( let anchor_liquidation_config = AnchorLiquidationConfig(sender, anchor_oracle_addr); let anchor_liquidation_addr = await create_contract(lcd_client, sender, "anchor_liquidation", anchor_liquidation_wasm, anchor_liquidation_config); console.log(`=======================`); - //instantiate distribution - let anchor_distribution_model_config = AnchorDistrConfig(sender); + //instantiate distribution model + let anchor_distribution_model_config = AnchorMoneyMarketDistrModelConfig(sender); let anchor_distribution_model_addr = await create_contract(lcd_client, sender, "anchor_distribution_model", anchor_distribution_model_wasm, anchor_distribution_model_config); console.log(`=======================`); //instantiate overseer @@ -193,6 +197,11 @@ async function anchor_init_verbose( let anchor_interest_model_addr = await create_contract(lcd_client, sender, "anchor_interest_model", anchor_interest_model_wasm, anchor_interest_model_config); console.log(`=======================`); + //instantiate distributor + let anchor_token_distributor_config = AnchorTokenDistrConfig(anchor_token_addr, anchor_token_addr, [anchor_market_addr]); + let anchor_token_distributor_addr = await create_contract(lcd_client, sender, "anchor_token_distributor", anchor_token_distributor_wasm, anchor_token_distributor_config); + console.log(`=======================`); + await execute_contract(lcd_client, sender, anchor_market_addr, { register_contracts: { @@ -200,7 +209,7 @@ async function anchor_init_verbose( interest_model: anchor_interest_model_addr, distribution_model: anchor_distribution_model_addr, collector_contract: sender.key.accAddress, - distributor_contract: anchor_distribution_model_addr, + distributor_contract: anchor_token_distributor_addr, } } ); @@ -341,6 +350,7 @@ async function anchor_init_verbose( return AnchorMarketInfo( anchor_market_addr, anchor_overseer_addr, + anchor_interest_model_addr, anchor_oracle_addr, anchor_basset_hub_bluna_addr, anchor_token_addr, @@ -349,6 +359,8 @@ async function anchor_init_verbose( basset_token_addr, beth_token_addr, anchor_custody_bluna_addr, - anchor_custody_beth_addr + anchor_custody_beth_addr, + basset_reward_addr, + beth_reward_addr, ); -} +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 99c3098..a90a556 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -20,6 +20,7 @@ import {BassetVaultConfig} from './config'; import {SecretsManager} from 'aws-sdk'; import * as prompt from 'prompt'; import {isTxSuccess} from './transaction'; +import {is_localterra} from './config'; export async function create_contract(lcd_client: LCDClient, sender: Wallet, contract_name: string, wasm_path: string, init_msg: object, init_funds?: Coin[]): Promise { let code_id = await store_contract(lcd_client, sender, wasm_path); @@ -279,7 +280,15 @@ export async function init_basset_vault(lcd_client: LCDClient, sender: Wallet, c // ============================================================ export async function calc_fee_and_send_tx(lcd_client: LCDClient, sender: Wallet, messages: Msg[], tax?: Coin[]): Promise { try { - const estimated_tx_fee = await get_tx_fee(lcd_client, sender, messages, tax); + let estimated_tx_fee = await get_tx_fee(lcd_client, sender, messages, tax); + + let estimation_failed = estimated_tx_fee === undefined; + let is_local = is_localterra(lcd_client); + + if (is_local && estimation_failed) { + estimated_tx_fee = new StdFee(20_000_000/0.15, [new Coin("uusd", 20_000_000)]); + } + if (estimated_tx_fee === undefined) { return undefined; } @@ -290,6 +299,12 @@ export async function calc_fee_and_send_tx(lcd_client: LCDClient, sender: Wallet }); const tx_result = await lcd_client.tx.broadcast(signed_tx); + + if (is_local && estimation_failed) { + console.error("FAILED TRANSACTION", tx_result); + return undefined; + } + return tx_result; } catch (err) { console.error(`calc_fee_and_send_tx return err: ${err}`) @@ -299,9 +314,17 @@ export async function calc_fee_and_send_tx(lcd_client: LCDClient, sender: Wallet async function get_tx_fee(lcd_client: LCDClient, sender: Wallet, msgs: Msg[], tax?: Coin[]): Promise { try { + let gasAdjustment; + + if (is_localterra(lcd_client)) { + gasAdjustment = 2.0; + } else { + gasAdjustment = 1.2; + } + const estimated_fee_res = await lcd_client.tx.estimateFee(sender.key.accAddress, msgs, { gasPrices: new Coins([new Coin("uusd", 0.15)]), - gasAdjustment: 1.2, + gasAdjustment, feeDenoms: ["uusd"], }); diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault.wasm index f903b22..94e21af 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault_strategy.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault_strategy.wasm index 1969f59..dd5d0e1 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault_strategy.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_basset_vault_strategy.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_config_holder.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_config_holder.wasm index fe21a33..73a62e8 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_config_holder.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_config_holder.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_rewards.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_rewards.wasm index 650c610..1a39804 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_rewards.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_rewards.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_token.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_token.wasm index a49a08f..ae00955 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_token.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_nasset_token.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/basset_vault_psi_distributor.wasm b/wasm_artifacts/nexus/basset_vaults/basset_vault_psi_distributor.wasm index 59c27b2..8775aca 100644 Binary files a/wasm_artifacts/nexus/basset_vaults/basset_vault_psi_distributor.wasm and b/wasm_artifacts/nexus/basset_vaults/basset_vault_psi_distributor.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults/checksums.txt b/wasm_artifacts/nexus/basset_vaults/checksums.txt index 233ba55..5f22251 100644 --- a/wasm_artifacts/nexus/basset_vaults/checksums.txt +++ b/wasm_artifacts/nexus/basset_vaults/checksums.txt @@ -1,6 +1,6 @@ -7a41451f7017ce87da842012e4d49ad732d7ff455dd014946f06a8ed29eae70b basset_vault_basset_vault.wasm -97e7144478fc6c17b45a2f24f3b8a5d79937b40ff6a36d5fb256d980175de0c4 basset_vault_basset_vault_strategy.wasm -5b24d8945b6884c49196cf7626e82a5f25f71f4b722594349774d8998f4252c5 basset_vault_nasset_config_holder.wasm -5b6ba6875a09342fc2f8c4bcb3095197e30d0f5b200743c4dad8e5bcb99f622f basset_vault_nasset_rewards.wasm -8dcbc69b2acaae00d63454c961fa324188d0113c9cb79f8743ed525f4170bdc0 basset_vault_nasset_token.wasm -0af6c8d72760c62788519575a5d923a7fee63bfcebd9c49a2a46ece349fa2cc9 basset_vault_psi_distributor.wasm +2d242ef9602e14bb6c8f0e36deca0c4c93e17624b4b293a474054851d6dcdee9 basset_vault_basset_vault_strategy.wasm +5408e45e0f9054dc4e14d9783631f969a6ba056b452caaa4deed7bd36c5f94dc basset_vault_nasset_config_holder.wasm +ec414e7ff40d26381817cfa3d7d5c3b6a6ca91416356261319c7482a17e6783b basset_vault_nasset_rewards.wasm +4facff1cf936b414d3228b8386dcd4369484d14d5379d5fa90cdf5e32fd3a239 basset_vault_nasset_token.wasm +3da6d748f7c0cb5c3f90dac010e0734ac1b711eeff29d6565991f03fed2fda32 basset_vault_psi_distributor.wasm +2aff9ac169653e3e55dcf6ea599059bfc656cf056772d406fdc2532abc212dfc basset_vault_basset_vault.wasm diff --git a/wasm_artifacts/nexus/basset_vaults/checksums_intermediate.txt b/wasm_artifacts/nexus/basset_vaults/checksums_intermediate.txt new file mode 100644 index 0000000..32b30e1 --- /dev/null +++ b/wasm_artifacts/nexus/basset_vaults/checksums_intermediate.txt @@ -0,0 +1,6 @@ +9a4ef2e80d4e8913ca8ffc325923bfea4284e00fbc579dc899b70c5c0d8550aa target/wasm32-unknown-unknown/release/basset_vault_basset_vault_strategy.wasm +fccab070014030785668e931b5505e387c7933216ae1eecd68cd279047616c7a target/wasm32-unknown-unknown/release/basset_vault_nasset_config_holder.wasm +03742fb3dd53130ebae26b3d6128ca60a0ae20243d8c68f1e632a381a2a98d00 target/wasm32-unknown-unknown/release/basset_vault_nasset_rewards.wasm +9492187bdc6dd3e463d9b7e02b5d7b996211679c27e1ed30b3d90dbe18e8eeaa target/wasm32-unknown-unknown/release/basset_vault_nasset_token.wasm +41203a932c302976f2cedde5c3554802a44d2a7e6bc4cbba66df7edb83f3ac7e target/wasm32-unknown-unknown/release/basset_vault_psi_distributor.wasm +2aff9ac169653e3e55dcf6ea599059bfc656cf056772d406fdc2532abc212dfc target/wasm32-unknown-unknown/release/basset_vault_basset_vault.wasm diff --git a/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault.wasm b/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault.wasm new file mode 100755 index 0000000..aa9c9bb Binary files /dev/null and b/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault.wasm differ diff --git a/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault_strategy.wasm b/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault_strategy.wasm new file mode 100755 index 0000000..2aaf6c7 Binary files /dev/null and b/wasm_artifacts/nexus/basset_vaults_integration_tests/basset_vault_basset_vault_strategy.wasm differ diff --git a/wasm_artifacts/utils/addr_holder.wasm b/wasm_artifacts/utils/addr_holder.wasm index e9c6e38..1f9a564 100644 Binary files a/wasm_artifacts/utils/addr_holder.wasm and b/wasm_artifacts/utils/addr_holder.wasm differ