diff --git a/Cargo.lock b/Cargo.lock index 67563f3e..c69ea9b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,16 +19,6 @@ version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" -[[package]] -name = "ap-native-coin-registry" -version = "1.0.0" -source = "git+https://github.com/astroport-fi/astroport-core.git?branch=main#75263a4f045cfad92d979f5d15fefb3e3e93a282" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 0.15.1", -] - [[package]] name = "astroport" version = "2.0.0" @@ -43,10 +33,9 @@ dependencies = [ [[package]] name = "astroport" -version = "2.4.0" -source = "git+https://github.com/astroport-fi/astroport-core.git?branch=main#75263a4f045cfad92d979f5d15fefb3e3e93a282" +version = "2.5.0" +source = "git+https://github.com/astroport-fi/astroport-core.git?branch=main#65ce7d1879cc5d95b09fa14202f0423bba52ae0e" dependencies = [ - "ap-native-coin-registry", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -140,7 +129,7 @@ dependencies = [ name = "astroport-periphery" version = "1.1.0" dependencies = [ - "astroport 2.4.0", + "astroport 2.5.0", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 0.15.1", @@ -290,9 +279,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8263ce52392898aa17c2a0984b7c542df416e434f6e0cb1c1a11771054d159" +checksum = "f22add0f9b2a5416df98c1d0248a8d8eedb882c38fbf0c5052b64eebe865df6d" dependencies = [ "digest 0.10.6", "ed25519-zebra", @@ -303,18 +292,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1895f6d7a191bb044e3c555190d1da555c2571a3af41f849f60c855580e392f" +checksum = "c2e64f710a18ef90d0a632cf27842e98ffc2d005a38a6f76c12fd0bc03bc1a2d" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1b99f612ccf162940ae2eef9f370ee37cf2ddcf4a9a8f5ee15ec6b46a5ecd2e" +checksum = "fe5ad2e23a971b9e4cd57b20cee3e2e79c33799bed4b128e473aca3702bfe5dd" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -325,9 +314,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ceea61033cb69c336abf673da017ddf251fc4e26e0cdd387eaf8bedb14e49" +checksum = "2926d159a9bb1a716a592b40280f1663f2491a9de3b6da77c0933cee2a2655b8" dependencies = [ "proc-macro2", "quote 1.0.26", @@ -336,9 +325,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc01051aab3bb88d5efe0b90f24a6df1ca96a873b12fc21b862b17539c84ee9" +checksum = "76fee88ff5bf7bef55bd37ac0619974701b99bf6bd4b16cf56ee8810718abd71" dependencies = [ "base64 0.13.1", "cosmwasm-crypto", @@ -356,9 +345,9 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719b9895ef880f172bfe698c975aa6ce5712abb2d0162148d51f346706df80" +checksum = "639bc36408bc1ac45e3323166ceeb8f0b91b55a941c4ad59d389829002fbbd94" dependencies = [ "cosmwasm-std", "serde", @@ -366,9 +355,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" dependencies = [ "libc", ] @@ -886,13 +875,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -947,9 +936,9 @@ checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -974,7 +963,7 @@ checksum = "e77ac7b51b8e6313251737fcef4b1c01a2ea102bde68415b62c0ee9268fec357" dependencies = [ "proc-macro2", "quote 1.0.26", - "syn 2.0.2", + "syn 2.0.11", ] [[package]] @@ -1095,7 +1084,7 @@ checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -1145,9 +1134,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" [[package]] name = "lock_api" @@ -1163,7 +1152,7 @@ dependencies = [ name = "neutron-auction" version = "1.0.0" dependencies = [ - "astroport 2.4.0", + "astroport 2.5.0", "astroport-periphery", "cosmwasm-schema", "cosmwasm-std", @@ -1180,7 +1169,7 @@ dependencies = [ name = "neutron-lockdrop" version = "1.2.0" dependencies = [ - "astroport 2.4.0", + "astroport 2.5.0", "astroport-periphery", "cosmwasm-schema", "cosmwasm-std", @@ -1225,7 +1214,7 @@ dependencies = [ [[package]] name = "neutron-sdk" version = "0.1.0" -source = "git+https://github.com/neutron-org/neutron-sdk#c19b40c024eeaa8733af9ddee94a52798d78f469" +source = "git+https://github.com/neutron-org/neutron-sdk#f6a9a6953443a7a3f33dafb5b3aacf92ddbe1b45" dependencies = [ "base64 0.20.0", "bech32", @@ -1402,7 +1391,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -1456,9 +1445,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] @@ -1688,6 +1677,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -1716,16 +1714,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.11" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -1804,9 +1802,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.157" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] @@ -1840,13 +1838,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.157" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote 1.0.26", - "syn 2.0.2", + "syn 2.0.11", ] [[package]] @@ -1862,9 +1860,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -2003,9 +2001,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.2" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" +checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" dependencies = [ "proc-macro2", "quote 1.0.26", @@ -2014,15 +2012,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -2074,7 +2072,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote 1.0.26", - "syn 2.0.2", + "syn 2.0.11", ] [[package]] @@ -2225,21 +2223,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -2308,6 +2291,6 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/contracts/auction/schema/config.json b/contracts/auction/schema/config.json index f1b82dd7..9d61da65 100644 --- a/contracts/auction/schema/config.json +++ b/contracts/auction/schema/config.json @@ -3,7 +3,7 @@ "title": "Config", "type": "object", "required": [ - "atom_denom", + "denom_manager", "deposit_window", "init_timestamp", "lp_tokens_lock_window", @@ -13,8 +13,8 @@ "owner", "price_feed_contract", "reserve_contract_address", - "usdc_denom", "vesting_atom_contract_address", + "vesting_lp_duration", "vesting_migration_pack_size", "vesting_usdc_contract_address", "withdrawal_window" @@ -22,7 +22,18 @@ "properties": { "atom_denom": { "description": "ATOM denom", - "type": "string" + "type": [ + "string", + "null" + ] + }, + "denom_manager": { + "description": "Account who can update denoms", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] }, "deposit_window": { "description": "Number of seconds post init_timestamp during which deposits / withdrawals will be allowed", @@ -108,7 +119,10 @@ }, "usdc_denom": { "description": "USDC denom", - "type": "string" + "type": [ + "string", + "null" + ] }, "vesting_atom_contract_address": { "description": "Vesting LP-ATOM Contract address", @@ -118,6 +132,12 @@ } ] }, + "vesting_lp_duration": { + "description": "vesting for lp duration", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "vesting_migration_pack_size": { "description": "vesting migration users pack size", "type": "integer", diff --git a/contracts/auction/schema/execute_msg.json b/contracts/auction/schema/execute_msg.json index ec8812c1..5b9d4955 100644 --- a/contracts/auction/schema/execute_msg.json +++ b/contracts/auction/schema/execute_msg.json @@ -22,6 +22,30 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "set_denoms" + ], + "properties": { + "set_denoms": { + "type": "object", + "required": [ + "atom_denom", + "usdc_denom" + ], + "properties": { + "atom_denom": { + "type": "string" + }, + "usdc_denom": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -93,7 +117,7 @@ "required": [ "amount", "asset", - "period" + "duration" ], "properties": { "amount": { @@ -102,7 +126,7 @@ "asset": { "$ref": "#/definitions/PoolType" }, - "period": { + "duration": { "type": "integer", "format": "uint64", "minimum": 0.0 @@ -123,7 +147,7 @@ "required": [ "amount", "asset", - "period" + "duration" ], "properties": { "amount": { @@ -132,7 +156,7 @@ "asset": { "$ref": "#/definitions/PoolType" }, - "period": { + "duration": { "type": "integer", "format": "uint64", "minimum": 0.0 diff --git a/contracts/auction/schema/instantiate_msg.json b/contracts/auction/schema/instantiate_msg.json index e88b1ba3..ae352be9 100644 --- a/contracts/auction/schema/instantiate_msg.json +++ b/contracts/auction/schema/instantiate_msg.json @@ -3,24 +3,22 @@ "title": "InstantiateMsg", "type": "object", "required": [ - "atom_denom", + "denom_manager", "deposit_window", "init_timestamp", "lp_tokens_lock_window", "max_exchange_rate_age", - "max_lock_period", - "min_lock_period", "min_ntrn_amount", "price_feed_contract", "reserve_contract_address", - "usdc_denom", "vesting_atom_contract_address", + "vesting_lp_duration", "vesting_migration_pack_size", "vesting_usdc_contract_address", "withdrawal_window" ], "properties": { - "atom_denom": { + "denom_manager": { "type": "string" }, "deposit_window": { @@ -49,16 +47,6 @@ "format": "uint64", "minimum": 0.0 }, - "max_lock_period": { - "type": "integer", - "format": "uint16", - "minimum": 0.0 - }, - "min_lock_period": { - "type": "integer", - "format": "uint16", - "minimum": 0.0 - }, "min_ntrn_amount": { "$ref": "#/definitions/Uint128" }, @@ -74,12 +62,14 @@ "reserve_contract_address": { "type": "string" }, - "usdc_denom": { - "type": "string" - }, "vesting_atom_contract_address": { "type": "string" }, + "vesting_lp_duration": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "vesting_migration_pack_size": { "type": "integer", "format": "uint16", diff --git a/contracts/auction/src/contract.rs b/contracts/auction/src/contract.rs index ec9ebde4..94ec2283 100644 --- a/contracts/auction/src/contract.rs +++ b/contracts/auction/src/contract.rs @@ -7,11 +7,17 @@ use cosmwasm_std::{ }; use std::str::FromStr; +use astroport::vesting::{ + ExecuteMsg as VestingExecuteMsg, VestingAccount, VestingSchedule, VestingSchedulePoint, +}; use astroport_periphery::auction::{ CallbackMsg, Config, ExecuteMsg, InstantiateMsg, MigrateMsg, PoolBalance, PoolInfo, QueryMsg, - State, UpdateConfigMsg, UserInfoResponse, UserLpInfo, VestingExecuteMsg, VestingMigrationUser, + State, UpdateConfigMsg, UserInfoResponse, UserLpInfo, +}; +use astroport_periphery::lockdrop::{ + Cw20HookMsg as LockDropCw20HookMsg, ExecuteMsg as LockDropExecuteMsg, + PoolType as LockDropPoolType, }; -use astroport_periphery::lockdrop::{ExecuteMsg as LockDropExecuteMsg, PoolType}; use crate::state::{get_users_store, CONFIG, STATE}; use astroport::querier::query_token_balance; @@ -66,6 +72,7 @@ pub fn instantiate( .map(|v| deps.api.addr_validate(&v)) .transpose()? .unwrap_or(info.sender), + denom_manager: deps.api.addr_validate(&msg.denom_manager)?, lockdrop_contract_address, price_feed_contract: deps.api.addr_validate(msg.price_feed_contract.as_str())?, reserve_contract_address: deps.api.addr_validate(&msg.reserve_contract_address)?, @@ -80,12 +87,13 @@ pub fn instantiate( init_timestamp: msg.init_timestamp, deposit_window: msg.deposit_window, withdrawal_window: msg.withdrawal_window, - usdc_denom: msg.usdc_denom, - atom_denom: msg.atom_denom, + usdc_denom: None, + atom_denom: None, ntrn_denom: UNTRN_DENOM.to_string(), max_exchange_rate_age: msg.max_exchange_rate_age, min_ntrn_amount: msg.min_ntrn_amount, vesting_migration_pack_size: msg.vesting_migration_pack_size, + vesting_lp_duration: msg.vesting_lp_duration, }; CONFIG.save(deps.storage, &config)?; @@ -118,6 +126,10 @@ pub fn execute( ) -> Result { match msg { ExecuteMsg::UpdateConfig { new_config } => execute_update_config(deps, info, new_config), + ExecuteMsg::SetDenoms { + usdc_denom, + atom_denom, + } => execute_set_denoms(deps, info, usdc_denom, atom_denom), ExecuteMsg::Deposit {} => execute_deposit(deps, env, info), ExecuteMsg::Withdraw { amount_usdc, @@ -128,13 +140,13 @@ pub fn execute( ExecuteMsg::LockLp { asset, amount, - period, - } => execute_lock_lp_tokens(deps, env, info, asset, amount, period), + duration, + } => execute_lock_lp_tokens(deps, env, info, asset, amount, duration), ExecuteMsg::WithdrawLp { asset, amount, - period, - } => execute_withdraw_lp_tokens(deps, env, info, asset, amount, period), + duration, + } => execute_withdraw_lp_tokens(deps, env, info, asset, amount, duration), ExecuteMsg::MigrateToVesting {} => execute_migrate_to_vesting(deps, env, info), ExecuteMsg::Callback(msg) => execute_callback(deps, env, info, msg), } @@ -155,6 +167,7 @@ fn execute_callback( pub fn execute_deposit(deps: DepsMut, env: Env, info: MessageInfo) -> Result { let config = CONFIG.load(deps.storage)?; + let (usdc_denom, atom_denom) = get_denoms(&config)?; let users_store = get_users_store(); // CHECK :: Auction deposit window open @@ -166,21 +179,21 @@ pub fn execute_deposit(deps: DepsMut, env: Env, info: MessageInfo) -> Result bool { && current_timestamp < config.init_timestamp + config.deposit_window } +pub fn execute_set_denoms( + deps: DepsMut, + info: MessageInfo, + usdc_denom: String, + atom_denom: String, +) -> StdResult { + let mut config = CONFIG.load(deps.storage)?; + let mut attributes = vec![attr("action", "set_denoms")]; + + if info.sender != config.denom_manager && info.sender != config.owner { + return Err(StdError::generic_err( + "Only owner and denom_manager can update denoms", + )); + } + + config.usdc_denom = Some(usdc_denom.clone()); + config.atom_denom = Some(atom_denom.clone()); + CONFIG.save(deps.storage, &config)?; + + attributes.push(attr("new_usdc_denom", usdc_denom)); + attributes.push(attr("new_atom_denom", atom_denom)); + + Ok(Response::new().add_attributes(attributes)) +} + /// Facilitates Opposite (native) token withdrawals by users. Returns a default object of type [`Response`]. /// ## Params /// * **deps** is an object of type [`DepsMut`]. @@ -322,6 +360,7 @@ pub fn execute_withdraw( amount_atom: Uint128, ) -> Result { let config = CONFIG.load(deps.storage)?; + let (usdc_denom, atom_denom) = get_denoms(&config)?; let mut state = STATE.load(deps.storage)?; let user_address = info.sender; let users_store = get_users_store(); @@ -362,7 +401,7 @@ pub fn execute_withdraw( let transfer_msg = CosmosMsg::Bank(BankMsg::Send { to_address: user_address.to_string(), amount: vec![Coin { - denom: config.usdc_denom, + denom: usdc_denom, amount: amount_usdc, }], }); @@ -374,7 +413,7 @@ pub fn execute_withdraw( let transfer_msg = CosmosMsg::Bank(BankMsg::Send { to_address: user_address.to_string(), amount: vec![Coin { - denom: config.atom_denom, + denom: atom_denom, amount: amount_atom, }], }); @@ -485,6 +524,7 @@ pub fn execute_set_pool_size( _info: MessageInfo, ) -> Result { let config = CONFIG.load(deps.storage)?; + let (usdc_denom, atom_denom) = get_denoms(&config)?; let mut state = STATE.load(deps.storage)?; // CHECK :: Can be executed once if state.lp_usdc_shares_minted.is_some() || state.lp_atom_shares_minted.is_some() { @@ -505,8 +545,8 @@ pub fn execute_set_pool_size( let (usdc_amount, atom_amount, ntrn_amount) = get_contract_balances( deps.as_ref(), &env.contract.address, - &config.usdc_denom, - &config.atom_denom, + &usdc_denom, + &atom_denom, &config.ntrn_denom, )?; @@ -537,7 +577,7 @@ pub fn execute_set_pool_size( let usdc_ntrn_size = ntrn_amount * div_ratio; let atom_ntrn_size = ntrn_amount - usdc_ntrn_size; let atom_lp_size = get_lp_size(atom_ntrn_size, atom_amount); - let usdc_lp_size = get_lp_size(usdc_ntrn_size, atom_amount); + let usdc_lp_size = get_lp_size(usdc_ntrn_size, usdc_amount); // UPDATE STATE state.usdc_ntrn_size = usdc_ntrn_size; @@ -575,28 +615,21 @@ pub fn execute_set_pool_size( /// * **env** is an object of type [`Env`]. /// /// * **info** is an object of type [`MessageInfo`]. -pub fn execute_init_pool(deps: DepsMut, env: Env, info: MessageInfo) -> Result { +pub fn execute_init_pool( + deps: DepsMut, + env: Env, + _info: MessageInfo, +) -> Result { let config = CONFIG.load(deps.storage)?; + let (usdc_denom, atom_denom) = get_denoms(&config)?; let state = STATE.load(deps.storage)?; - // CHECK :: Only admin can call this function - if info.sender != config.owner { - return Err(StdError::generic_err("Unauthorized")); - } - // CHECK :: Can be executed once if state.lp_usdc_shares_minted.is_some() || state.lp_atom_shares_minted.is_some() { return Err(StdError::generic_err("Liquidity already added")); } - // CHECK :: Deposit / withdrawal windows need to be over - if !are_windows_closed(env.block.time.seconds(), &config) { - return Err(StdError::generic_err( - "Deposit/withdrawal windows are still open", - )); - } - - if state.usdc_lp_size.is_zero() || state.atom_lp_size.is_zero() { + if state.usdc_lp_size.is_zero() && state.atom_lp_size.is_zero() { return Err(StdError::generic_err("Pool size has not been set")); } @@ -612,14 +645,6 @@ pub fn execute_init_pool(deps: DepsMut, env: Env, info: MessageInfo) -> Result Result Result { let config = CONFIG.load(deps.storage)?; @@ -758,9 +791,13 @@ fn execute_migrate_to_vesting( let users = users_store .idx .vested + .prefix(0u8) .range(deps.storage, None, None, Order::Ascending) .take(config.vesting_migration_pack_size.into()) .collect::>>()?; + let pool_info = config + .pool_info + .ok_or_else(|| StdError::generic_err("Pool info isn't set yet. Please set it first."))?; if state.pool_init_timestamp == 0 { return Err(StdError::generic_err("Pool isn't initialized yet!")); @@ -768,8 +805,8 @@ fn execute_migrate_to_vesting( if users.is_empty() { return Err(StdError::generic_err("No users to migrate!")); } - let mut atom_users: Vec = vec![]; - let mut usdc_users: Vec = vec![]; + let mut atom_users: Vec<_> = vec![]; + let mut usdc_users: Vec<_> = vec![]; let mut atom_lp_amount = Uint128::zero(); let mut usdc_lp_amount = Uint128::zero(); @@ -787,42 +824,65 @@ fn execute_migrate_to_vesting( let vest_usdc_lp_amount = user_lp_balance.usdc_lp_amount - user.usdc_lp_locked; if !vest_atom_lp_amount.is_zero() { - atom_users.push(VestingMigrationUser { + atom_users.push(VestingAccount { address: user_addr.to_string(), - amount: vest_atom_lp_amount, + schedules: vec![VestingSchedule { + start_point: VestingSchedulePoint { + time: env.block.time.seconds(), + amount: Uint128::zero(), + }, + end_point: Some(VestingSchedulePoint { + time: env.block.time.seconds() + config.vesting_lp_duration, + amount: vest_atom_lp_amount, + }), + }], }); atom_lp_amount += vest_atom_lp_amount; } if !vest_usdc_lp_amount.is_zero() { - usdc_users.push(VestingMigrationUser { + usdc_users.push(VestingAccount { address: user_addr.to_string(), - amount: vest_usdc_lp_amount, + schedules: vec![VestingSchedule { + start_point: VestingSchedulePoint { + time: env.block.time.seconds(), + amount: Uint128::zero(), + }, + end_point: Some(VestingSchedulePoint { + time: env.block.time.seconds() + config.vesting_lp_duration, + amount: vest_usdc_lp_amount, + }), + }], }); usdc_lp_amount += vest_usdc_lp_amount; } user.is_vested = true; users_store.save(deps.storage, &user_addr, &user)?; } + let mut msgs = vec![]; if !atom_lp_amount.is_zero() { msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.vesting_atom_contract_address.to_string(), + contract_addr: pool_info.ntrn_atom_lp_token_address.to_string(), funds: vec![], msg: to_binary(&Cw20ExecuteMsg::Send { - contract: config.vesting_usdc_contract_address.to_string(), + contract: config.vesting_atom_contract_address.to_string(), amount: atom_lp_amount, - msg: to_binary(&VestingExecuteMsg::MigrateVestingUsers { users: atom_users })?, + msg: to_binary(&VestingExecuteMsg::RegisterVestingAccounts { + vesting_accounts: atom_users, + })?, })?, })); } if !usdc_lp_amount.is_zero() { msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.vesting_usdc_contract_address.to_string(), + contract_addr: pool_info.ntrn_usdc_lp_token_address.to_string(), funds: vec![], msg: to_binary(&Cw20ExecuteMsg::Send { contract: config.vesting_usdc_contract_address.to_string(), amount: usdc_lp_amount, - msg: to_binary(&VestingExecuteMsg::MigrateVestingUsers { users: usdc_users })?, + msg: to_binary(&VestingExecuteMsg::RegisterVestingAccounts { + vesting_accounts: usdc_users, + })?, })?, })); } @@ -863,19 +923,20 @@ fn build_provide_liquidity_to_lp_pool_msg( denom: other_denom.clone(), }, }; - + let mut funds = vec![ + Coin { + denom: base_denom, + amount: base_amount, + }, + Coin { + denom: other_denom, + amount: other_amount, + }, + ]; + funds.sort_by(|a, b| a.denom.cmp(&b.denom)); Ok(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: pool_address.to_string(), - funds: vec![ - Coin { - denom: base_denom, - amount: base_amount, - }, - Coin { - denom: other_denom, - amount: other_amount, - }, - ], + funds, msg: to_binary(&astroport::pair::ExecuteMsg::ProvideLiquidity { assets: vec![base, other], slippage_tolerance: None, @@ -921,7 +982,7 @@ pub fn execute_lock_lp_tokens( deps: DepsMut, env: Env, info: MessageInfo, - asset: PoolType, + asset: LockDropPoolType, amount: Uint128, duration: u64, ) -> Result { @@ -952,7 +1013,7 @@ pub fn execute_lock_lp_tokens( ); match asset { - PoolType::USDC => { + LockDropPoolType::USDC => { if user_info.usdc_deposited.is_zero() { return Err(StdError::generic_err("No USDC deposited!")); } @@ -962,14 +1023,14 @@ pub fn execute_lock_lp_tokens( user_info.usdc_lp_locked = user_info.usdc_lp_locked.checked_add(amount)?; state.usdc_lp_locked = state.usdc_lp_locked.checked_add(amount)?; } - PoolType::ATOM => { + LockDropPoolType::ATOM => { if user_info.atom_deposited.is_zero() { return Err(StdError::generic_err("No ATOM deposited!")); } if amount > user_lp_info.atom_lp_amount - user_info.atom_lp_locked { return Err(StdError::generic_err("Not enough ATOM LP!")); } - user_info.atom_lp_locked += user_info.atom_lp_locked.checked_add(amount)?; + user_info.atom_lp_locked = user_info.atom_lp_locked.checked_add(amount)?; state.atom_lp_locked = state.atom_lp_locked.checked_add(amount)?; } } @@ -992,7 +1053,7 @@ pub fn execute_lock_lp_tokens( attr("action", "lock_lp_tokens"), attr("asset", asset), attr("amount", amount), - attr("period", duration.to_string()), + attr("duration", duration.to_string()), ])) } @@ -1007,7 +1068,7 @@ pub fn execute_withdraw_lp_tokens( deps: DepsMut, env: Env, info: MessageInfo, - asset: PoolType, + asset: LockDropPoolType, amount: Uint128, duration: u64, ) -> Result { @@ -1029,12 +1090,12 @@ pub fn execute_withdraw_lp_tokens( })?; match asset { - PoolType::USDC => { + LockDropPoolType::USDC => { user_info.usdc_lp_locked = user_info.usdc_lp_locked.checked_sub(amount)?; state.usdc_lp_locked = state.usdc_lp_locked.checked_sub(amount)?; } - PoolType::ATOM => { - user_info.atom_lp_locked += user_info.atom_lp_locked.checked_sub(amount)?; + LockDropPoolType::ATOM => { + user_info.atom_lp_locked = user_info.atom_lp_locked.checked_sub(amount)?; state.atom_lp_locked = state.atom_lp_locked.checked_sub(amount)?; } } @@ -1043,6 +1104,7 @@ pub fn execute_withdraw_lp_tokens( contract_addr: lockdrop_address.to_string(), funds: vec![], msg: to_binary(&LockDropExecuteMsg::WithdrawFromLockup { + user_address: info.sender.to_string(), pool_type: asset, amount, duration, @@ -1056,7 +1118,7 @@ pub fn execute_withdraw_lp_tokens( attr("action", "withdraw_lp_tokens"), attr("asset", asset), attr("amount", amount), - attr("period", duration.to_string()), + attr("duration", duration.to_string()), ])) } @@ -1096,8 +1158,8 @@ fn query_user_info(deps: Deps, _env: Env, user_address: String) -> StdResult StdResult StdResult<(String, String)> { + let usdc_denom = config + .usdc_denom + .as_ref() + .ok_or_else(|| StdError::generic_err("USDC Denom is not set yet. Please set it first."))?; + let atom_denom = config + .atom_denom + .as_ref() + .ok_or_else(|| StdError::generic_err("ATOM Denom is not set yet. Please set it first."))?; + + Ok((usdc_denom.to_string(), atom_denom.to_string())) +} diff --git a/contracts/lockdrop/schema/config.json b/contracts/lockdrop/schema/config.json index 05320f89..946da11d 100644 --- a/contracts/lockdrop/schema/config.json +++ b/contracts/lockdrop/schema/config.json @@ -13,6 +13,7 @@ "max_positions_per_user", "min_lock_duration", "owner", + "token_info_manager", "withdrawal_window" ], "properties": { @@ -96,6 +97,14 @@ } ] }, + "token_info_manager": { + "description": "Account which can update the generator and token addresses", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, "withdrawal_window": { "description": "Withdrawal Window Length :: Post the deposit window", "type": "integer", diff --git a/contracts/lockdrop/schema/execute_msg.json b/contracts/lockdrop/schema/execute_msg.json index 71cc1b69..9d5d587d 100644 --- a/contracts/lockdrop/schema/execute_msg.json +++ b/contracts/lockdrop/schema/execute_msg.json @@ -80,6 +80,34 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "set_token_info" + ], + "properties": { + "set_token_info": { + "type": "object", + "required": [ + "atom_token", + "generator", + "usdc_token" + ], + "properties": { + "atom_token": { + "type": "string" + }, + "generator": { + "type": "string" + }, + "usdc_token": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, { "type": "object", "required": [ @@ -91,7 +119,8 @@ "required": [ "amount", "duration", - "pool_type" + "pool_type", + "user_address" ], "properties": { "amount": { @@ -104,6 +133,9 @@ }, "pool_type": { "$ref": "#/definitions/PoolType" + }, + "user_address": { + "type": "string" } } } @@ -207,31 +239,6 @@ } }, "additionalProperties": false - }, - { - "description": "Sets pool info", - "type": "object", - "required": [ - "set_pool_info" - ], - "properties": { - "set_pool_info": { - "type": "object", - "required": [ - "pool_info", - "pool_type" - ], - "properties": { - "pool_info": { - "$ref": "#/definitions/PoolInfo" - }, - "pool_type": { - "$ref": "#/definitions/PoolType" - } - } - } - }, - "additionalProperties": false } ], "definitions": { @@ -408,64 +415,6 @@ } } }, - "Decimal": { - "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", - "type": "string" - }, - "PoolInfo": { - "type": "object", - "required": [ - "amount_in_lockups", - "generator_ntrn_per_share", - "generator_proxy_per_share", - "incentives_share", - "is_staked", - "lp_token", - "weighted_amount" - ], - "properties": { - "amount_in_lockups": { - "$ref": "#/definitions/Uint128" - }, - "generator_ntrn_per_share": { - "description": "Ratio of Generator NTRN rewards accured to astroport pool share", - "allOf": [ - { - "$ref": "#/definitions/Decimal" - } - ] - }, - "generator_proxy_per_share": { - "description": "Ratio of Generator Proxy rewards accured to astroport pool share", - "allOf": [ - { - "$ref": "#/definitions/RestrictedVector_for_AssetInfo_and_Decimal" - } - ] - }, - "incentives_share": { - "description": "Share of total NTRN incentives allocated to this pool", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "is_staked": { - "description": "Boolean value indicating if the LP Tokens are staked with the Generator contract or not", - "type": "boolean" - }, - "lp_token": { - "$ref": "#/definitions/Addr" - }, - "weighted_amount": { - "description": "Weighted LP Token balance used to calculate NTRN rewards a particular user can claim", - "allOf": [ - { - "$ref": "#/definitions/Uint256" - } - ] - } - } - }, "PoolType": { "type": "string", "enum": [ @@ -473,31 +422,10 @@ "ATOM" ] }, - "RestrictedVector_for_AssetInfo_and_Decimal": { - "description": "Vec wrapper for internal use. Some business logic relies on an order of this vector, thus it is forbidden to sort it or remove elements. New values can be added using .update() ONLY.", - "type": "array", - "items": { - "type": "array", - "items": [ - { - "$ref": "#/definitions/AssetInfo" - }, - { - "$ref": "#/definitions/Decimal" - } - ], - "maxItems": 2, - "minItems": 2 - } - }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, - "Uint256": { - "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", - "type": "string" - }, "UpdateConfigMsg": { "type": "object", "properties": { diff --git a/contracts/lockdrop/schema/instantiate_msg.json b/contracts/lockdrop/schema/instantiate_msg.json index 1ffe02ce..f91cea0f 100644 --- a/contracts/lockdrop/schema/instantiate_msg.json +++ b/contracts/lockdrop/schema/instantiate_msg.json @@ -11,6 +11,7 @@ "max_lock_duration", "max_positions_per_user", "min_lock_duration", + "token_info_manager", "withdrawal_window" ], "properties": { @@ -66,6 +67,10 @@ "null" ] }, + "token_info_manager": { + "description": "Account which can update token addresses and generator", + "type": "string" + }, "withdrawal_window": { "description": "Withdrawal Window Length :: Post the deposit window", "type": "integer", diff --git a/contracts/lockdrop/schema/pool_info.json b/contracts/lockdrop/schema/pool_info.json index a2a6783b..865a4fe2 100644 --- a/contracts/lockdrop/schema/pool_info.json +++ b/contracts/lockdrop/schema/pool_info.json @@ -33,9 +33,11 @@ }, "incentives_share": { "description": "Share of total NTRN incentives allocated to this pool", - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "is_staked": { "description": "Boolean value indicating if the LP Tokens are staked with the Generator contract or not", diff --git a/contracts/lockdrop/schema/state_response.json b/contracts/lockdrop/schema/state_response.json index c9d915cd..cdb65ce0 100644 --- a/contracts/lockdrop/schema/state_response.json +++ b/contracts/lockdrop/schema/state_response.json @@ -16,9 +16,11 @@ }, "total_incentives_share": { "description": "Total NTRN incentives share", - "type": "integer", - "format": "uint64", - "minimum": 0.0 + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "definitions": { @@ -28,6 +30,10 @@ "USDC", "ATOM" ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } } diff --git a/contracts/lockdrop/src/contract.rs b/contracts/lockdrop/src/contract.rs index aeab0b26..6b0a8888 100644 --- a/contracts/lockdrop/src/contract.rs +++ b/contracts/lockdrop/src/contract.rs @@ -96,6 +96,7 @@ pub fn instantiate( .map(|v| deps.api.addr_validate(&v)) .transpose()? .unwrap_or(info.sender), + token_info_manager: deps.api.addr_validate(&msg.token_info_manager)?, credits_contract: deps.api.addr_validate(&msg.credits_contract)?, auction_contract: deps.api.addr_validate(&msg.auction_contract)?, generator: None, @@ -197,48 +198,22 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S duration, } => handle_increase_lockup(deps, env, info, user_address, pool_type, duration, amount), ExecuteMsg::WithdrawFromLockup { + user_address, pool_type, duration, amount, - } => handle_withdraw_from_lockup(deps, env, info, pool_type, duration, amount), + } => { + handle_withdraw_from_lockup(deps, env, info, user_address, pool_type, duration, amount) + } ExecuteMsg::UpdateConfig { new_config } => handle_update_config(deps, info, new_config), - ExecuteMsg::SetPoolInfo { - pool_type, - pool_info, - } => handle_set_pool(deps, env, info, pool_type, pool_info), + ExecuteMsg::SetTokenInfo { + usdc_token, + atom_token, + generator, + } => handle_set_token_info(deps, env, info, usdc_token, atom_token, generator), } } -/// Admin function to set info about pools. Returns a default object of type [`Response`]. -/// ## Params -/// * **deps** is an object of type [`DepsMut`]. -/// -/// * **env** is an object of type [`Env`]. -/// -/// * **info** is an object of type [`MessageInfo`]. -/// -/// * **pool_type** is an object of type [`PoolType`]. -/// -/// * **pool_info** is an object of type [`PoolInfo`]. -pub fn handle_set_pool( - deps: DepsMut, - env: Env, - info: MessageInfo, - pool_type: PoolType, - pool_info: PoolInfo, -) -> StdResult { - let config = CONFIG.load(deps.storage)?; - let attributes = vec![attr("action", "set_pool"), attr("pool_type", pool_type)]; - - // CHECK :: Only owner can call this function - if info.sender != config.owner { - return Err(StdError::generic_err("Unauthorized")); - } - - ASSET_POOLS.save(deps.storage, pool_type, &pool_info, env.block.height)?; - - Ok(Response::new().add_attributes(attributes)) -} /// Receives a message of type [`Cw20ReceiveMsg`] and processes it depending on the received template. /// If the template is not found in the received message, then an [`StdError`] is returned, /// otherwise it returns the [`Response`] with the specified attributes if the operation was successful. @@ -470,6 +445,58 @@ pub fn handle_update_config( Ok(Response::new().add_attributes(attributes)) } +pub fn handle_set_token_info( + deps: DepsMut, + env: Env, + info: MessageInfo, + usdc_token: String, + atom_token: String, + generator: String, +) -> Result { + let mut config = CONFIG.load(deps.storage)?; + + // CHECK :: Only owner and token info manager can call this function + if info.sender != config.owner && info.sender != config.token_info_manager { + return Err(StdError::generic_err("Unauthorized")); + } + + // POOL INFO :: Initialize new pool + let pool_info = PoolInfo { + lp_token: deps.api.addr_validate(&atom_token)?, + amount_in_lockups: Default::default(), + incentives_share: Uint128::zero(), + weighted_amount: Default::default(), + generator_ntrn_per_share: Default::default(), + generator_proxy_per_share: RestrictedVector::default(), + is_staked: false, + }; + ASSET_POOLS.save(deps.storage, PoolType::ATOM, &pool_info, env.block.height)?; + + // POOL INFO :: Initialize new pool + let pool_info = PoolInfo { + lp_token: deps.api.addr_validate(&usdc_token)?, + amount_in_lockups: Default::default(), + incentives_share: Uint128::zero(), + weighted_amount: Default::default(), + generator_ntrn_per_share: Default::default(), + generator_proxy_per_share: RestrictedVector::default(), + is_staked: false, + }; + ASSET_POOLS.save(deps.storage, PoolType::USDC, &pool_info, env.block.height)?; + + config.generator = Some(deps.api.addr_validate(&generator)?); + CONFIG.save(deps.storage, &config)?; + + let attributes = vec![ + attr("action", "update_config"), + attr("usdc_token", usdc_token), + attr("atom_token", atom_token), + attr("generator", generator), + ]; + + Ok(Response::new().add_attributes(attributes)) +} + /// Facilitates increasing NTRN incentives that are to be distributed as Lockdrop participation reward. Returns a default object of type [`Response`]. /// ## Params /// * **deps** is an object of type [`DepsMut`]. @@ -529,7 +556,7 @@ pub fn handle_initialize_pool( info: MessageInfo, pool_type: PoolType, cw20_sender_addr: Addr, - incentives_share: u64, + incentives_share: Uint128, amount: Uint128, ) -> StdResult { let config = CONFIG.load(deps.storage)?; @@ -750,6 +777,7 @@ pub fn handle_withdraw_from_lockup( deps: DepsMut, env: Env, info: MessageInfo, + user_address: String, pool_type: PoolType, duration: u64, amount: Uint128, @@ -767,8 +795,9 @@ pub fn handle_withdraw_from_lockup( let mut pool_info = ASSET_POOLS.load(deps.storage, pool_type)?; + let user_address = deps.api.addr_validate(&user_address)?; + // Retrieve Lockup position - let user_address = info.sender; let lockup_key = (pool_type, &user_address, duration); let mut lockup_info = LOCKUP_INFO.compatible_load(deps.as_ref(), lockup_key, &config.generator)?; @@ -1687,11 +1716,11 @@ pub fn query_lockup_info( pub fn calculate_astro_incentives_for_lockup( lockup_weighted_balance: Uint256, total_weighted_amount: Uint256, - pool_incentives_share: u64, - total_incentives_share: u64, + pool_incentives_share: Uint128, + total_incentives_share: Uint128, total_lockdrop_incentives: Uint128, ) -> StdResult { - if total_incentives_share == 0u64 || total_weighted_amount == Uint256::zero() { + if total_incentives_share.is_zero() || total_weighted_amount.is_zero() { Ok(Uint128::zero()) } else { Ok(Decimal256::from_ratio( diff --git a/contracts/lockdrop/src/testing.rs b/contracts/lockdrop/src/testing.rs index 6f0a3888..526c0362 100644 --- a/contracts/lockdrop/src/testing.rs +++ b/contracts/lockdrop/src/testing.rs @@ -11,11 +11,13 @@ fn update_owner() { let info = mock_info("addr0000", &[]); let owner = Addr::unchecked("owner"); + let token_info_manager = Addr::unchecked("token_info_manager"); let env = mock_env(); let msg = InstantiateMsg { owner: Some(owner.to_string()), + token_info_manager: token_info_manager.to_string(), init_timestamp: env.block.time.seconds(), lock_window: 10_000_000, withdrawal_window: 500_000, @@ -97,11 +99,13 @@ fn increase_ntrn_incentives() { let info = mock_info("addr0000", &[]); let owner = Addr::unchecked("owner"); + let token_info_manager = Addr::unchecked("token_info_manager"); let env = mock_env(); let msg = InstantiateMsg { owner: Some(owner.to_string()), + token_info_manager: token_info_manager.to_string(), init_timestamp: env.block.time.seconds(), lock_window: 10_000_000, withdrawal_window: 500_000, diff --git a/contracts/vesting-lp/schema/raw/execute.json b/contracts/vesting-lp/schema/raw/execute.json index e5971e64..19fba561 100644 --- a/contracts/vesting-lp/schema/raw/execute.json +++ b/contracts/vesting-lp/schema/raw/execute.json @@ -182,9 +182,88 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "set_vesting_token" + ], + "properties": { + "set_vesting_token": { + "type": "object", + "required": [ + "vesting_token" + ], + "properties": { + "vesting_token": { + "description": "[`AssetInfo`] of the token that's being vested", + "allOf": [ + { + "$ref": "#/definitions/AssetInfo" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "AssetInfo": { + "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", + "oneOf": [ + { + "description": "Non-native Token", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Native token", + "type": "object", + "required": [ + "native_token" + ], + "properties": { + "native_token": { + "type": "object", + "required": [ + "denom" + ], + "properties": { + "denom": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "Binary": { "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", "type": "string" diff --git a/contracts/vesting-lp/schema/raw/instantiate.json b/contracts/vesting-lp/schema/raw/instantiate.json index 41008292..081844ef 100644 --- a/contracts/vesting-lp/schema/raw/instantiate.json +++ b/contracts/vesting-lp/schema/raw/instantiate.json @@ -5,84 +5,25 @@ "type": "object", "required": [ "owner", - "vesting_managers", - "vesting_token" + "token_info_manager", + "vesting_managers" ], "properties": { "owner": { "description": "Address allowed to change contract parameters", "type": "string" }, + "token_info_manager": { + "description": "Initial list of whitelisted vesting managers", + "type": "string" + }, "vesting_managers": { "description": "Initial list of whitelisted vesting managers", "type": "array", "items": { "type": "string" } - }, - "vesting_token": { - "description": "[`AssetInfo`] of the token that's being vested", - "allOf": [ - { - "$ref": "#/definitions/AssetInfo" - } - ] } }, - "additionalProperties": false, - "definitions": { - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - }, - "AssetInfo": { - "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", - "oneOf": [ - { - "description": "Non-native Token", - "type": "object", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Native token", - "type": "object", - "required": [ - "native_token" - ], - "properties": { - "native_token": { - "type": "object", - "required": [ - "denom" - ], - "properties": { - "denom": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - } - } + "additionalProperties": false } diff --git a/contracts/vesting-lp/schema/raw/response_to_config.json b/contracts/vesting-lp/schema/raw/response_to_config.json index 9ab74329..aee14d00 100644 --- a/contracts/vesting-lp/schema/raw/response_to_config.json +++ b/contracts/vesting-lp/schema/raw/response_to_config.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "owner", + "token_info_manager", "vesting_token" ], "properties": { @@ -16,6 +17,14 @@ } ] }, + "token_info_manager": { + "description": "Token info manager", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, "vesting_token": { "description": "[`AssetInfo`] of the token that's being vested", "allOf": [ diff --git a/contracts/vesting-lp/schema/raw/response_to_vesting_account.json b/contracts/vesting-lp/schema/raw/response_to_vesting_account.json index 499ca4de..b85fc3d3 100644 --- a/contracts/vesting-lp/schema/raw/response_to_vesting_account.json +++ b/contracts/vesting-lp/schema/raw/response_to_vesting_account.json @@ -44,7 +44,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/vesting-lp/schema/raw/response_to_vesting_accounts.json b/contracts/vesting-lp/schema/raw/response_to_vesting_accounts.json index 5a0dfaf7..6d2af531 100644 --- a/contracts/vesting-lp/schema/raw/response_to_vesting_accounts.json +++ b/contracts/vesting-lp/schema/raw/response_to_vesting_accounts.json @@ -61,7 +61,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/vesting-lp/schema/raw/response_to_vesting_state.json b/contracts/vesting-lp/schema/raw/response_to_vesting_state.json new file mode 100644 index 00000000..b38701e4 --- /dev/null +++ b/contracts/vesting-lp/schema/raw/response_to_vesting_state.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VestingState", + "description": "This structure stores the accumulated vesting information for all addresses.", + "type": "object", + "required": [ + "total_granted", + "total_released" + ], + "properties": { + "total_granted": { + "description": "The total amount of tokens granted to the users", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "total_released": { + "description": "The total amount of tokens already claimed", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/vesting-lp/schema/vesting-lp.json b/contracts/vesting-lp/schema/vesting-lp.json index 493f9af4..70d23f1e 100644 --- a/contracts/vesting-lp/schema/vesting-lp.json +++ b/contracts/vesting-lp/schema/vesting-lp.json @@ -9,86 +9,27 @@ "type": "object", "required": [ "owner", - "vesting_managers", - "vesting_token" + "token_info_manager", + "vesting_managers" ], "properties": { "owner": { "description": "Address allowed to change contract parameters", "type": "string" }, + "token_info_manager": { + "description": "Initial list of whitelisted vesting managers", + "type": "string" + }, "vesting_managers": { "description": "Initial list of whitelisted vesting managers", "type": "array", "items": { "type": "string" } - }, - "vesting_token": { - "description": "[`AssetInfo`] of the token that's being vested", - "allOf": [ - { - "$ref": "#/definitions/AssetInfo" - } - ] } }, - "additionalProperties": false, - "definitions": { - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - }, - "AssetInfo": { - "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", - "oneOf": [ - { - "description": "Non-native Token", - "type": "object", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Native token", - "type": "object", - "required": [ - "native_token" - ], - "properties": { - "native_token": { - "type": "object", - "required": [ - "denom" - ], - "properties": { - "denom": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - } - } + "additionalProperties": false }, "execute": { "$schema": "http://json-schema.org/draft-07/schema#", @@ -274,9 +215,88 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "set_vesting_token" + ], + "properties": { + "set_vesting_token": { + "type": "object", + "required": [ + "vesting_token" + ], + "properties": { + "vesting_token": { + "description": "[`AssetInfo`] of the token that's being vested", + "allOf": [ + { + "$ref": "#/definitions/AssetInfo" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "AssetInfo": { + "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", + "oneOf": [ + { + "description": "Non-native Token", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Native token", + "type": "object", + "required": [ + "native_token" + ], + "properties": { + "native_token": { + "type": "object", + "required": [ + "denom" + ], + "properties": { + "denom": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "Binary": { "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", "type": "string" @@ -563,6 +583,7 @@ "type": "object", "required": [ "owner", + "token_info_manager", "vesting_token" ], "properties": { @@ -574,6 +595,14 @@ } ] }, + "token_info_manager": { + "description": "Token info manager", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, "vesting_token": { "description": "[`AssetInfo`] of the token that's being vested", "allOf": [ @@ -693,7 +722,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" @@ -829,7 +858,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/vesting-lp/src/tests/integration.rs b/contracts/vesting-lp/src/tests/integration.rs index 6724c8a4..85adb047 100644 --- a/contracts/vesting-lp/src/tests/integration.rs +++ b/contracts/vesting-lp/src/tests/integration.rs @@ -17,6 +17,7 @@ use vesting_base::error::ContractError; use vesting_base::state::Config; const OWNER1: &str = "owner1"; +const TOKEN_MANAGER: &str = "token_manager"; const USER1: &str = "user1"; const USER2: &str = "user2"; const TOKEN_INITIAL_AMOUNT: u128 = 1_000_000_000_000_000; @@ -1175,11 +1176,12 @@ fn instantiate_vesting(app: &mut App, cw20_token_instance: &Addr) -> Addr { crate::contract::query, )); let owner = Addr::unchecked(OWNER1); + let token_manager = Addr::unchecked(TOKEN_MANAGER); let vesting_code_id = app.store_code(vesting_contract); let init_msg = InstantiateMsg { owner: OWNER1.to_string(), - vesting_token: token_asset_info(cw20_token_instance.clone()), + token_info_manager: TOKEN_MANAGER.to_string(), vesting_managers: vec![], }; @@ -1193,6 +1195,16 @@ fn instantiate_vesting(app: &mut App, cw20_token_instance: &Addr) -> Addr { None, ) .unwrap(); + let set_vesting_token_msg = ExecuteMsg::SetVestingToken { + vesting_token: token_asset_info(cw20_token_instance.clone()), + }; + app.execute_contract( + token_manager, + vesting_instance.clone(), + &set_vesting_token_msg, + &[], + ) + .unwrap(); let res: Config = app .wrap() @@ -1200,7 +1212,7 @@ fn instantiate_vesting(app: &mut App, cw20_token_instance: &Addr) -> Addr { .unwrap(); assert_eq!( cw20_token_instance.to_string(), - res.vesting_token.to_string() + res.vesting_token.unwrap().to_string() ); mint_tokens(app, cw20_token_instance, &owner, TOKEN_INITIAL_AMOUNT); @@ -1217,16 +1229,24 @@ fn instantiate_vesting_remote_chain(app: &mut App) -> Addr { crate::contract::query, )); let owner = Addr::unchecked(OWNER1); + let token_manager = Addr::unchecked(TOKEN_MANAGER); let vesting_code_id = app.store_code(vesting_contract); let init_msg = InstantiateMsg { owner: OWNER1.to_string(), - vesting_token: native_asset_info(VESTING_TOKEN.to_string()), + token_info_manager: TOKEN_MANAGER.to_string(), vesting_managers: vec![], }; - app.instantiate_contract(vesting_code_id, owner, &init_msg, &[], "Vesting", None) - .unwrap() + let res = app + .instantiate_contract(vesting_code_id, owner, &init_msg, &[], "Vesting", None) + .unwrap(); + let msg = ExecuteMsg::SetVestingToken { + vesting_token: native_asset_info(VESTING_TOKEN.to_string()), + }; + app.execute_contract(token_manager, res.clone(), &msg, &[]) + .unwrap(); + res } fn mint_tokens(app: &mut App, token: &Addr, recipient: &Addr, amount: u128) { diff --git a/contracts/vesting-managed/schema/raw/execute.json b/contracts/vesting-managed/schema/raw/execute.json index e5971e64..19fba561 100644 --- a/contracts/vesting-managed/schema/raw/execute.json +++ b/contracts/vesting-managed/schema/raw/execute.json @@ -182,9 +182,88 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "set_vesting_token" + ], + "properties": { + "set_vesting_token": { + "type": "object", + "required": [ + "vesting_token" + ], + "properties": { + "vesting_token": { + "description": "[`AssetInfo`] of the token that's being vested", + "allOf": [ + { + "$ref": "#/definitions/AssetInfo" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ], "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "AssetInfo": { + "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", + "oneOf": [ + { + "description": "Non-native Token", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Native token", + "type": "object", + "required": [ + "native_token" + ], + "properties": { + "native_token": { + "type": "object", + "required": [ + "denom" + ], + "properties": { + "denom": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "Binary": { "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", "type": "string" diff --git a/contracts/vesting-managed/schema/raw/instantiate.json b/contracts/vesting-managed/schema/raw/instantiate.json index 41008292..081844ef 100644 --- a/contracts/vesting-managed/schema/raw/instantiate.json +++ b/contracts/vesting-managed/schema/raw/instantiate.json @@ -5,84 +5,25 @@ "type": "object", "required": [ "owner", - "vesting_managers", - "vesting_token" + "token_info_manager", + "vesting_managers" ], "properties": { "owner": { "description": "Address allowed to change contract parameters", "type": "string" }, + "token_info_manager": { + "description": "Initial list of whitelisted vesting managers", + "type": "string" + }, "vesting_managers": { "description": "Initial list of whitelisted vesting managers", "type": "array", "items": { "type": "string" } - }, - "vesting_token": { - "description": "[`AssetInfo`] of the token that's being vested", - "allOf": [ - { - "$ref": "#/definitions/AssetInfo" - } - ] } }, - "additionalProperties": false, - "definitions": { - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - }, - "AssetInfo": { - "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", - "oneOf": [ - { - "description": "Non-native Token", - "type": "object", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Native token", - "type": "object", - "required": [ - "native_token" - ], - "properties": { - "native_token": { - "type": "object", - "required": [ - "denom" - ], - "properties": { - "denom": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - } - } + "additionalProperties": false } diff --git a/contracts/vesting-managed/schema/raw/response_to_config.json b/contracts/vesting-managed/schema/raw/response_to_config.json index 9ab74329..aee14d00 100644 --- a/contracts/vesting-managed/schema/raw/response_to_config.json +++ b/contracts/vesting-managed/schema/raw/response_to_config.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "owner", + "token_info_manager", "vesting_token" ], "properties": { @@ -16,6 +17,14 @@ } ] }, + "token_info_manager": { + "description": "Token info manager", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, "vesting_token": { "description": "[`AssetInfo`] of the token that's being vested", "allOf": [ diff --git a/contracts/vesting-managed/schema/raw/response_to_vesting_account.json b/contracts/vesting-managed/schema/raw/response_to_vesting_account.json index 499ca4de..b85fc3d3 100644 --- a/contracts/vesting-managed/schema/raw/response_to_vesting_account.json +++ b/contracts/vesting-managed/schema/raw/response_to_vesting_account.json @@ -44,7 +44,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/vesting-managed/schema/raw/response_to_vesting_accounts.json b/contracts/vesting-managed/schema/raw/response_to_vesting_accounts.json index 5a0dfaf7..6d2af531 100644 --- a/contracts/vesting-managed/schema/raw/response_to_vesting_accounts.json +++ b/contracts/vesting-managed/schema/raw/response_to_vesting_accounts.json @@ -61,7 +61,7 @@ ], "properties": { "released_amount": { - "description": "The total amount of vested already claimed", + "description": "The total amount of vested tokens already claimed", "allOf": [ { "$ref": "#/definitions/Uint128" diff --git a/contracts/vesting-managed/schema/raw/response_to_vesting_managers.json b/contracts/vesting-managed/schema/raw/response_to_vesting_managers.json new file mode 100644 index 00000000..bf06b01c --- /dev/null +++ b/contracts/vesting-managed/schema/raw/response_to_vesting_managers.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_Addr", + "type": "array", + "items": { + "$ref": "#/definitions/Addr" + }, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + } + } +} diff --git a/contracts/vesting-managed/schema/raw/response_to_vesting_state.json b/contracts/vesting-managed/schema/raw/response_to_vesting_state.json new file mode 100644 index 00000000..b38701e4 --- /dev/null +++ b/contracts/vesting-managed/schema/raw/response_to_vesting_state.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VestingState", + "description": "This structure stores the accumulated vesting information for all addresses.", + "type": "object", + "required": [ + "total_granted", + "total_released" + ], + "properties": { + "total_granted": { + "description": "The total amount of tokens granted to the users", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "total_released": { + "description": "The total amount of tokens already claimed", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/vesting-managed/schema/vesting-managed.json b/contracts/vesting-managed/schema/vesting-managed.json new file mode 100644 index 00000000..0378039a --- /dev/null +++ b/contracts/vesting-managed/schema/vesting-managed.json @@ -0,0 +1,984 @@ +{ + "contract_name": "vesting-managed", + "contract_version": "1.1.0", + "idl_version": "1.0.0", + "instantiate": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "This structure describes the parameters used for creating a contract.", + "type": "object", + "required": [ + "owner", + "token_info_manager", + "vesting_managers" + ], + "properties": { + "owner": { + "description": "Address allowed to change contract parameters", + "type": "string" + }, + "token_info_manager": { + "description": "Initial list of whitelisted vesting managers", + "type": "string" + }, + "vesting_managers": { + "description": "Initial list of whitelisted vesting managers", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "execute": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "description": "This structure describes the execute messages available in the contract.", + "oneOf": [ + { + "description": "Claim claims vested tokens and sends them to a recipient", + "type": "object", + "required": [ + "claim" + ], + "properties": { + "claim": { + "type": "object", + "properties": { + "amount": { + "description": "The amount of tokens to claim", + "anyOf": [ + { + "$ref": "#/definitions/Uint128" + }, + { + "type": "null" + } + ] + }, + "recipient": { + "description": "The address that receives the vested tokens", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Receives a message of type [`Cw20ReceiveMsg`] and processes it depending on the received template", + "type": "object", + "required": [ + "receive" + ], + "properties": { + "receive": { + "$ref": "#/definitions/Cw20ReceiveMsg" + } + }, + "additionalProperties": false + }, + { + "description": "RegisterVestingAccounts registers vesting targets/accounts", + "type": "object", + "required": [ + "register_vesting_accounts" + ], + "properties": { + "register_vesting_accounts": { + "type": "object", + "required": [ + "vesting_accounts" + ], + "properties": { + "vesting_accounts": { + "type": "array", + "items": { + "$ref": "#/definitions/VestingAccount" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Creates a request to change contract ownership ## Executor Only the current owner can execute this", + "type": "object", + "required": [ + "propose_new_owner" + ], + "properties": { + "propose_new_owner": { + "type": "object", + "required": [ + "expires_in", + "owner" + ], + "properties": { + "expires_in": { + "description": "The validity period of the offer to change the owner", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "owner": { + "description": "The newly proposed owner", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Removes a request to change contract ownership ## Executor Only the current owner can execute this", + "type": "object", + "required": [ + "drop_ownership_proposal" + ], + "properties": { + "drop_ownership_proposal": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Claims contract ownership ## Executor Only the newly proposed owner can execute this", + "type": "object", + "required": [ + "claim_ownership" + ], + "properties": { + "claim_ownership": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Adds vesting managers ## Executor Only the current owner can execute this", + "type": "object", + "required": [ + "add_vesting_managers" + ], + "properties": { + "add_vesting_managers": { + "type": "object", + "required": [ + "managers" + ], + "properties": { + "managers": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Removes vesting managers ## Executor Only the current owner can execute this", + "type": "object", + "required": [ + "remove_vesting_managers" + ], + "properties": { + "remove_vesting_managers": { + "type": "object", + "required": [ + "managers" + ], + "properties": { + "managers": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "set_vesting_token" + ], + "properties": { + "set_vesting_token": { + "type": "object", + "required": [ + "vesting_token" + ], + "properties": { + "vesting_token": { + "description": "[`AssetInfo`] of the token that's being vested", + "allOf": [ + { + "$ref": "#/definitions/AssetInfo" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "AssetInfo": { + "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", + "oneOf": [ + { + "description": "Non-native Token", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Native token", + "type": "object", + "required": [ + "native_token" + ], + "properties": { + "native_token": { + "type": "object", + "required": [ + "denom" + ], + "properties": { + "denom": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Cw20ReceiveMsg": { + "description": "Cw20ReceiveMsg should be de/serialized under `Receive()` variant in a ExecuteMsg", + "type": "object", + "required": [ + "amount", + "msg", + "sender" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "sender": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "VestingAccount": { + "description": "This structure stores vesting information for a specific address that is getting tokens.", + "type": "object", + "required": [ + "address", + "schedules" + ], + "properties": { + "address": { + "description": "The address that is getting tokens", + "type": "string" + }, + "schedules": { + "description": "The vesting schedules targeted at the `address`", + "type": "array", + "items": { + "$ref": "#/definitions/VestingSchedule" + } + } + }, + "additionalProperties": false + }, + "VestingSchedule": { + "description": "This structure stores parameters for a specific vesting schedule", + "type": "object", + "required": [ + "start_point" + ], + "properties": { + "end_point": { + "description": "The end point for the vesting schedule", + "anyOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + }, + { + "type": "null" + } + ] + }, + "start_point": { + "description": "The start date for the vesting schedule", + "allOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + } + ] + } + }, + "additionalProperties": false + }, + "VestingSchedulePoint": { + "description": "This structure stores the parameters used to create a vesting schedule.", + "type": "object", + "required": [ + "amount", + "time" + ], + "properties": { + "amount": { + "description": "The amount of tokens being vested", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "time": { + "description": "The start time for the vesting schedule", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + } + }, + "query": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "description": "This structure describes the query messages available in the contract.", + "oneOf": [ + { + "description": "Returns the configuration for the contract using a [`ConfigResponse`] object.", + "type": "object", + "required": [ + "config" + ], + "properties": { + "config": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns information about an address vesting tokens using a [`VestingAccountResponse`] object.", + "type": "object", + "required": [ + "vesting_account" + ], + "properties": { + "vesting_account": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns a list of addresses that are vesting tokens using a [`VestingAccountsResponse`] object.", + "type": "object", + "required": [ + "vesting_accounts" + ], + "properties": { + "vesting_accounts": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "order_by": { + "anyOf": [ + { + "$ref": "#/definitions/OrderBy" + }, + { + "type": "null" + } + ] + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns the total unvested amount of tokens for a specific address.", + "type": "object", + "required": [ + "available_amount" + ], + "properties": { + "available_amount": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Timestamp returns the current timestamp", + "type": "object", + "required": [ + "timestamp" + ], + "properties": { + "timestamp": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "VestingState returns the current vesting state.", + "type": "object", + "required": [ + "vesting_state" + ], + "properties": { + "vesting_state": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns list of vesting managers (the persons who are able to add/remove vesting schedules)", + "type": "object", + "required": [ + "vesting_managers" + ], + "properties": { + "vesting_managers": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "OrderBy": { + "description": "This enum describes the types of sorting that can be applied to some piece of data", + "type": "string", + "enum": [ + "asc", + "desc" + ] + } + } + }, + "migrate": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MigrateMsg", + "description": "This structure describes a migration message. We currently take no arguments for migrations.", + "type": "object", + "additionalProperties": false + }, + "sudo": null, + "responses": { + "available_amount": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Uint128", + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "config": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ConfigResponse", + "description": "This structure describes a custom struct used to return the contract configuration.", + "type": "object", + "required": [ + "owner", + "token_info_manager", + "vesting_token" + ], + "properties": { + "owner": { + "description": "Address allowed to set contract parameters", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, + "token_info_manager": { + "description": "Token info manager", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, + "vesting_token": { + "description": "[`AssetInfo`] of the token that's being vested", + "allOf": [ + { + "$ref": "#/definitions/AssetInfo" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "AssetInfo": { + "description": "This enum describes available Token types. ## Examples ``` # use cosmwasm_std::Addr; # use astroport::asset::AssetInfo::{NativeToken, Token}; Token { contract_addr: Addr::unchecked(\"stake...\") }; NativeToken { denom: String::from(\"uluna\") }; ```", + "oneOf": [ + { + "description": "Non-native Token", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "$ref": "#/definitions/Addr" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Native token", + "type": "object", + "required": [ + "native_token" + ], + "properties": { + "native_token": { + "type": "object", + "required": [ + "denom" + ], + "properties": { + "denom": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + } + } + }, + "timestamp": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "uint64", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vesting_account": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VestingAccountResponse", + "description": "This structure describes a custom struct used to return vesting data about a specific vesting target.", + "type": "object", + "required": [ + "address", + "info" + ], + "properties": { + "address": { + "description": "The address that's vesting tokens", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, + "info": { + "description": "Vesting information", + "allOf": [ + { + "$ref": "#/definitions/VestingInfo" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "VestingInfo": { + "description": "This structure stores parameters for a batch of vesting schedules.", + "type": "object", + "required": [ + "released_amount", + "schedules" + ], + "properties": { + "released_amount": { + "description": "The total amount of vested tokens already claimed", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "schedules": { + "description": "The vesting schedules", + "type": "array", + "items": { + "$ref": "#/definitions/VestingSchedule" + } + } + }, + "additionalProperties": false + }, + "VestingSchedule": { + "description": "This structure stores parameters for a specific vesting schedule", + "type": "object", + "required": [ + "start_point" + ], + "properties": { + "end_point": { + "description": "The end point for the vesting schedule", + "anyOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + }, + { + "type": "null" + } + ] + }, + "start_point": { + "description": "The start date for the vesting schedule", + "allOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + } + ] + } + }, + "additionalProperties": false + }, + "VestingSchedulePoint": { + "description": "This structure stores the parameters used to create a vesting schedule.", + "type": "object", + "required": [ + "amount", + "time" + ], + "properties": { + "amount": { + "description": "The amount of tokens being vested", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "time": { + "description": "The start time for the vesting schedule", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + } + }, + "vesting_accounts": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VestingAccountsResponse", + "description": "This structure describes a custom struct used to return vesting data for multiple vesting targets.", + "type": "object", + "required": [ + "vesting_accounts" + ], + "properties": { + "vesting_accounts": { + "description": "A list of accounts that are vesting tokens", + "type": "array", + "items": { + "$ref": "#/definitions/VestingAccountResponse" + } + } + }, + "additionalProperties": false, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "VestingAccountResponse": { + "description": "This structure describes a custom struct used to return vesting data about a specific vesting target.", + "type": "object", + "required": [ + "address", + "info" + ], + "properties": { + "address": { + "description": "The address that's vesting tokens", + "allOf": [ + { + "$ref": "#/definitions/Addr" + } + ] + }, + "info": { + "description": "Vesting information", + "allOf": [ + { + "$ref": "#/definitions/VestingInfo" + } + ] + } + }, + "additionalProperties": false + }, + "VestingInfo": { + "description": "This structure stores parameters for a batch of vesting schedules.", + "type": "object", + "required": [ + "released_amount", + "schedules" + ], + "properties": { + "released_amount": { + "description": "The total amount of vested tokens already claimed", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "schedules": { + "description": "The vesting schedules", + "type": "array", + "items": { + "$ref": "#/definitions/VestingSchedule" + } + } + }, + "additionalProperties": false + }, + "VestingSchedule": { + "description": "This structure stores parameters for a specific vesting schedule", + "type": "object", + "required": [ + "start_point" + ], + "properties": { + "end_point": { + "description": "The end point for the vesting schedule", + "anyOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + }, + { + "type": "null" + } + ] + }, + "start_point": { + "description": "The start date for the vesting schedule", + "allOf": [ + { + "$ref": "#/definitions/VestingSchedulePoint" + } + ] + } + }, + "additionalProperties": false + }, + "VestingSchedulePoint": { + "description": "This structure stores the parameters used to create a vesting schedule.", + "type": "object", + "required": [ + "amount", + "time" + ], + "properties": { + "amount": { + "description": "The amount of tokens being vested", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "time": { + "description": "The start time for the vesting schedule", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + } + }, + "vesting_managers": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_Addr", + "type": "array", + "items": { + "$ref": "#/definitions/Addr" + }, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + } + } + }, + "vesting_state": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VestingState", + "description": "This structure stores the accumulated vesting information for all addresses.", + "type": "object", + "required": [ + "total_granted", + "total_released" + ], + "properties": { + "total_granted": { + "description": "The total amount of tokens granted to the users", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "total_released": { + "description": "The total amount of tokens already claimed", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } + } + } +} diff --git a/contracts/vesting-managed/src/contract.rs b/contracts/vesting-managed/src/contract.rs index 363b8392..300d7f53 100644 --- a/contracts/vesting-managed/src/contract.rs +++ b/contracts/vesting-managed/src/contract.rs @@ -54,11 +54,17 @@ pub fn execute( ExecuteMsg::Claim { recipient, amount } => { vest_app.claim(deps, env, info, recipient, amount) } + ExecuteMsg::SetVestingToken { vesting_token } => { + vest_app.set_vesting_token(deps, env, info, vesting_token) + } ExecuteMsg::Receive(msg) => vest_app.receive_cw20(deps, env, info, msg), ExecuteMsg::RegisterVestingAccounts { vesting_accounts } => { let config = vest_app.config.load(deps.storage)?; + let vesting_token = config + .vesting_token + .ok_or(ContractError::VestingTokenIsNotSet {})?; - match &config.vesting_token { + match &vesting_token { AssetInfo::NativeToken { denom } if info.sender == config.owner => { let amount = must_pay(&info, denom)?; vest_app.register_vesting_accounts( @@ -141,6 +147,9 @@ fn remove_vesting_accounts( if info.sender != config.owner { return Err(ContractError::Unauthorized {}); } + let vesting_token = config + .vesting_token + .ok_or(ContractError::VestingTokenIsNotSet {})?; let mut response = Response::new(); @@ -167,8 +176,7 @@ fn remove_vesting_accounts( let amount_to_claw_back = total_granted_for_user.checked_sub(account_info.released_amount)?; - let transfer_msg = config - .vesting_token + let transfer_msg = vesting_token .with_balance(amount_to_claw_back) .into_msg(&deps.querier, clawback_address.clone())?; response = response.add_submessage(SubMsg::new(transfer_msg)); diff --git a/contracts/vesting-managed/src/msg.rs b/contracts/vesting-managed/src/msg.rs index efbb1c5e..0afb1cbe 100644 --- a/contracts/vesting-managed/src/msg.rs +++ b/contracts/vesting-managed/src/msg.rs @@ -1,4 +1,4 @@ -use astroport::vesting::VestingAccount; +use astroport::{asset::AssetInfo, vesting::VestingAccount}; use cosmwasm_schema::cw_serde; use cosmwasm_std::Uint128; use cw20::Cw20ReceiveMsg; @@ -44,4 +44,8 @@ pub enum ExecuteMsg { /// Specifies the account that will receive the funds taken from the vesting accounts. clawback_account: String, }, + /// Sets vesting token + /// ## Executor + /// Only the current owner or token info manager can execute this + SetVestingToken { vesting_token: AssetInfo }, } diff --git a/contracts/vesting-managed/src/tests/integration.rs b/contracts/vesting-managed/src/tests/integration.rs index a84e2de0..bef352bb 100644 --- a/contracts/vesting-managed/src/tests/integration.rs +++ b/contracts/vesting-managed/src/tests/integration.rs @@ -19,6 +19,7 @@ use vesting_base::state::Config; use crate::msg::ExecuteMsg as ManagedExecuteMsg; const OWNER1: &str = "owner1"; +const TOKEN_MANAGER: &str = "token_manager"; const USER1: &str = "user1"; const USER2: &str = "user2"; const TOKEN_INITIAL_AMOUNT: u128 = 1_000_000_000_000_000; @@ -1188,11 +1189,12 @@ fn instantiate_vesting(app: &mut App, astro_token_instance: &Addr) -> Addr { crate::contract::query, )); let owner = Addr::unchecked(OWNER1); + let token_manager = Addr::unchecked(TOKEN_MANAGER); let vesting_code_id = app.store_code(vesting_contract); let init_msg = InstantiateMsg { owner: OWNER1.to_string(), - vesting_token: token_asset_info(astro_token_instance.clone()), + token_info_manager: TOKEN_MANAGER.to_string(), vesting_managers: Vec::new(), }; @@ -1207,13 +1209,19 @@ fn instantiate_vesting(app: &mut App, astro_token_instance: &Addr) -> Addr { ) .unwrap(); + let msg = ExecuteMsg::SetVestingToken { + vesting_token: token_asset_info(astro_token_instance.clone()), + }; + app.execute_contract(token_manager, vesting_instance.clone(), &msg, &[]) + .unwrap(); + let res: Config = app .wrap() .query_wasm_smart(vesting_instance.clone(), &QueryMsg::Config {}) .unwrap(); assert_eq!( astro_token_instance.to_string(), - res.vesting_token.to_string() + res.vesting_token.unwrap().to_string() ); mint_tokens(app, astro_token_instance, &owner, TOKEN_INITIAL_AMOUNT); @@ -1230,16 +1238,27 @@ fn instantiate_vesting_remote_chain(app: &mut App) -> Addr { crate::contract::query, )); let owner = Addr::unchecked(OWNER1); + let token_manager = Addr::unchecked(TOKEN_MANAGER); let vesting_code_id = app.store_code(vesting_contract); let init_msg = InstantiateMsg { owner: OWNER1.to_string(), - vesting_token: native_asset_info(IBC_ASTRO.to_string()), + token_info_manager: TOKEN_MANAGER.to_string(), vesting_managers: Vec::new(), }; - app.instantiate_contract(vesting_code_id, owner, &init_msg, &[], "Vesting", None) - .unwrap() + let res = app + .instantiate_contract(vesting_code_id, owner, &init_msg, &[], "Vesting", None) + .unwrap(); + + let msg = ExecuteMsg::SetVestingToken { + vesting_token: native_asset_info(IBC_ASTRO.to_string()), + }; + + app.execute_contract(token_manager, res.clone(), &msg, &[]) + .unwrap(); + + res } fn mint_tokens(app: &mut App, token: &Addr, recipient: &Addr, amount: u128) { diff --git a/packages/astroport/src/vesting.rs b/packages/astroport/src/vesting.rs index 84f95d0c..83419fc0 100644 --- a/packages/astroport/src/vesting.rs +++ b/packages/astroport/src/vesting.rs @@ -10,8 +10,8 @@ use crate::asset::AssetInfo; pub struct InstantiateMsg { /// Address allowed to change contract parameters pub owner: String, - /// [`AssetInfo`] of the token that's being vested - pub vesting_token: AssetInfo, + /// Token info manager address + pub token_info_manager: String, /// Initial list of whitelisted vesting managers pub vesting_managers: Vec, } @@ -57,6 +57,11 @@ pub enum ExecuteMsg { /// ## Executor /// Only the current owner can execute this RemoveVestingManagers { managers: Vec }, + /// Sets the vesting token + SetVestingToken { + /// [`AssetInfo`] of the token that's being vested + vesting_token: AssetInfo, + }, } /// This structure stores the accumulated vesting information for all addresses. @@ -144,6 +149,8 @@ pub struct ConfigResponse { pub owner: Addr, /// [`AssetInfo`] of the token that's being vested pub vesting_token: AssetInfo, + /// Token info manager + pub token_info_manager: Addr, } /// This structure describes a custom struct used to return vesting data about a specific vesting target. diff --git a/packages/astroport_periphery/src/auction.rs b/packages/astroport_periphery/src/auction.rs index 9071741f..7573c599 100644 --- a/packages/astroport_periphery/src/auction.rs +++ b/packages/astroport_periphery/src/auction.rs @@ -7,6 +7,7 @@ use crate::lockdrop::PoolType; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg { pub owner: Option, + pub denom_manager: String, pub price_feed_contract: String, pub lockdrop_contract_address: Option, pub reserve_contract_address: String, @@ -16,13 +17,10 @@ pub struct InstantiateMsg { pub init_timestamp: u64, pub deposit_window: u64, pub withdrawal_window: u64, - pub usdc_denom: String, - pub atom_denom: String, - pub max_lock_period: u16, - pub min_lock_period: u16, pub max_exchange_rate_age: u64, pub min_ntrn_amount: Uint128, pub vesting_migration_pack_size: u16, + pub vesting_lp_duration: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -53,6 +51,10 @@ pub enum ExecuteMsg { UpdateConfig { new_config: UpdateConfigMsg, }, + SetDenoms { + usdc_denom: String, + atom_denom: String, + }, Deposit {}, Withdraw { amount_atom: Uint128, @@ -63,12 +65,12 @@ pub enum ExecuteMsg { LockLp { asset: PoolType, amount: Uint128, - period: u64, + duration: u64, }, WithdrawLp { asset: PoolType, amount: Uint128, - period: u64, + duration: u64, }, MigrateToVesting {}, Callback(CallbackMsg), @@ -108,6 +110,8 @@ pub struct MigrateMsg {} pub struct Config { /// Account who can update config pub owner: Addr, + /// Account who can update denoms + pub denom_manager: Addr, /// Reserve Contract address pub reserve_contract_address: Addr, /// Vesting LP-USDC Contract address @@ -131,15 +135,17 @@ pub struct Config { /// Base denom pub ntrn_denom: String, /// USDC denom - pub usdc_denom: String, + pub usdc_denom: Option, /// ATOM denom - pub atom_denom: String, + pub atom_denom: Option, /// Min NTRN amount to be distributed as pool liquidity pub min_ntrn_amount: Uint128, /// min exchange freshness rate (seconds) pub max_exchange_rate_age: u64, /// vesting migration users pack size pub vesting_migration_pack_size: u16, + /// vesting for lp duration + pub vesting_lp_duration: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)] @@ -229,16 +235,3 @@ pub struct PoolBalance { pub atom: Uint128, pub usdc: Uint128, } - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub struct VestingMigrationUser { - pub address: String, - pub amount: Uint128, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum VestingExecuteMsg { - MigrateVestingUsers { users: Vec }, -} diff --git a/packages/astroport_periphery/src/lockdrop.rs b/packages/astroport_periphery/src/lockdrop.rs index c702a8da..65a3c2ab 100644 --- a/packages/astroport_periphery/src/lockdrop.rs +++ b/packages/astroport_periphery/src/lockdrop.rs @@ -1,7 +1,7 @@ use astroport::asset::{Asset, AssetInfo}; use astroport::restricted_vector::RestrictedVector; use cosmwasm_std::{ - from_slice, to_binary, Addr, CosmosMsg, Decimal, Decimal256, Env, StdResult, Uint128, Uint256, + to_binary, Addr, CosmosMsg, Decimal, Decimal256, Env, StdError, StdResult, Uint128, Uint256, WasmMsg, }; use cw20::Cw20ReceiveMsg; @@ -38,9 +38,12 @@ impl PoolType { impl KeyDeserialize for PoolType { type Output = PoolType; - #[inline(always)] fn from_vec(value: Vec) -> StdResult { - from_slice(&value) + match value.as_slice() { + b"usdc" => Ok(PoolType::USDC), + b"atom" => Ok(PoolType::ATOM), + _ => Err(StdError::generic_err("Invalid PoolType")), + } } } @@ -66,6 +69,8 @@ impl<'a> Prefixer<'a> for PoolType { pub struct InstantiateMsg { /// Account which can update config pub owner: Option, + /// Account which can update token addresses and generator + pub token_info_manager: String, /// Credits contract address pub credits_contract: String, /// Auction contract address @@ -111,8 +116,14 @@ pub enum ExecuteMsg { UpdateConfig { new_config: UpdateConfigMsg, }, + SetTokenInfo { + atom_token: String, + usdc_token: String, + generator: String, + }, // Function to facilitate LP Token withdrawals from lockups WithdrawFromLockup { + user_address: String, pool_type: PoolType, duration: u64, amount: Uint128, @@ -151,11 +162,6 @@ pub enum ExecuteMsg { DropOwnershipProposal {}, /// Used to claim contract ownership. ClaimOwnership {}, - /// Sets pool info - SetPoolInfo { - pool_type: PoolType, - pool_info: PoolInfo, - }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -167,7 +173,7 @@ pub enum Cw20HookMsg { // ADMIN Function ::: Add new Pool (Only Terraswap Pools) InitializePool { pool_type: PoolType, - incentives_share: u64, + incentives_share: Uint128, }, } @@ -254,6 +260,8 @@ pub struct LockupRewardsInfo { pub struct Config { /// Account which can update the config pub owner: Addr, + /// Account which can update the generator and token addresses + pub token_info_manager: Addr, /// Credits contract address pub credits_contract: Addr, /// Bootstrap Auction contract address @@ -281,7 +289,7 @@ pub struct Config { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)] pub struct State { /// Total NTRN incentives share - pub total_incentives_share: u64, + pub total_incentives_share: Uint128, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -290,7 +298,7 @@ pub struct PoolInfo { pub amount_in_lockups: Uint128, // pub migration_info: Option, /// Share of total NTRN incentives allocated to this pool - pub incentives_share: u64, + pub incentives_share: Uint128, /// Weighted LP Token balance used to calculate NTRN rewards a particular user can claim pub weighted_amount: Uint256, /// Ratio of Generator NTRN rewards accured to astroport pool share @@ -348,7 +356,7 @@ pub struct LockupInfoV2 { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct StateResponse { /// Total NTRN incentives share - pub total_incentives_share: u64, + pub total_incentives_share: Uint128, /// Vector containing LP addresses for all the supported LP Pools pub supported_pairs_list: Vec, } diff --git a/packages/vesting-base/Cargo.toml b/packages/vesting-base/Cargo.toml index 4f0a3307..e1e5273d 100644 --- a/packages/vesting-base/Cargo.toml +++ b/packages/vesting-base/Cargo.toml @@ -20,4 +20,4 @@ cw-storage-plus = "0.15" astroport = { path = "../astroport", default-features = false } thiserror = { version = "1.0" } cw-utils = "0.15" -cosmwasm-schema = { version = "1.1", default-features = false } \ No newline at end of file +cosmwasm-schema = { version = "1.1", default-features = false } diff --git a/packages/vesting-base/src/contract.rs b/packages/vesting-base/src/contract.rs index ac3c13af..dd6bd593 100644 --- a/packages/vesting-base/src/contract.rs +++ b/packages/vesting-base/src/contract.rs @@ -9,8 +9,8 @@ use crate::error::ContractError; use astroport::asset::{addr_opt_validate, token_asset_info, AssetInfo, AssetInfoExt}; use astroport::common::{claim_ownership, drop_ownership_proposal, propose_new_owner}; use astroport::vesting::{ - ConfigResponse, Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, OrderBy, QueryMsg, - VestingAccount, VestingAccountResponse, VestingAccountsResponse, VestingInfo, VestingSchedule, + Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, OrderBy, QueryMsg, VestingAccount, + VestingAccountResponse, VestingAccountsResponse, VestingInfo, VestingSchedule, }; use cw2::set_contract_version; use cw20::Cw20ReceiveMsg; @@ -32,13 +32,12 @@ impl BaseVesting { ) -> StdResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - msg.vesting_token.check(deps.api)?; - self.config.save( deps.storage, &Config { owner: deps.api.addr_validate(&msg.owner)?, - vesting_token: msg.vesting_token, + token_info_manager: deps.api.addr_validate(&msg.token_info_manager)?, + vesting_token: None, }, )?; @@ -71,8 +70,9 @@ impl BaseVesting { ExecuteMsg::Receive(msg) => self.receive_cw20(deps, env, info, msg), ExecuteMsg::RegisterVestingAccounts { vesting_accounts } => { let config = self.config.load(deps.storage)?; + let vesting_token = get_vesting_token(&config)?; - match &config.vesting_token { + match &vesting_token { AssetInfo::NativeToken { denom } if self.is_sender_whitelisted(deps.as_ref(), &config, &info.sender) => { @@ -128,6 +128,9 @@ impl BaseVesting { ExecuteMsg::RemoveVestingManagers { managers } => { self.remove_vesting_managers(deps, env, info, managers) } + ExecuteMsg::SetVestingToken { vesting_token } => { + self.set_vesting_token(deps, env, info, vesting_token) + } } } @@ -152,13 +155,14 @@ impl BaseVesting { cw20_msg: Cw20ReceiveMsg, ) -> Result { let config = self.config.load(deps.storage)?; + let vesting_token = get_vesting_token(&config)?; // Permission check if !self.is_sender_whitelisted( deps.as_ref(), &config, &deps.api.addr_validate(&cw20_msg.sender)?, - ) || token_asset_info(info.sender) != config.vesting_token + ) || token_asset_info(info.sender) != vesting_token { return Err(ContractError::Unauthorized {}); } @@ -174,6 +178,24 @@ impl BaseVesting { } } + pub fn set_vesting_token( + &self, + deps: DepsMut, + _env: Env, + info: MessageInfo, + token: AssetInfo, + ) -> Result { + let mut config = self.config.load(deps.storage)?; + if info.sender != config.owner && info.sender != config.token_info_manager { + return Err(ContractError::Unauthorized {}); + } + token.check(deps.api)?; + config.vesting_token = Some(token); + + self.config.save(deps.storage, &config)?; + Ok(Response::new()) + } + /// Adds new vesting managers, which have a permission to add/remove vesting schedule /// /// * **managers** list of accounts to be added to the whitelist. @@ -310,6 +332,7 @@ impl BaseVesting { amount: Option, ) -> Result { let config = self.config.load(deps.storage)?; + let vesting_token = get_vesting_token(&config)?; let mut vesting_info = self.vesting_info.load(deps.storage, &info.sender)?; let available_amount = compute_available_amount(env.block.time.seconds(), &vesting_info)?; @@ -326,7 +349,7 @@ impl BaseVesting { let mut response = Response::new(); if !claim_amount.is_zero() { - let transfer_msg = config.vesting_token.with_balance(claim_amount).into_msg( + let transfer_msg = vesting_token.with_balance(claim_amount).into_msg( &deps.querier, recipient.unwrap_or_else(|| info.sender.to_string()), )?; @@ -391,14 +414,10 @@ impl BaseVesting { } } - /// Returns the vesting contract configuration using a [`ConfigResponse`] object. - pub fn query_config(&self, deps: Deps) -> StdResult { + /// Returns the vesting contract configuration using a [`Config`] object. + pub fn query_config(&self, deps: Deps) -> StdResult { let config = self.config.load(deps.storage)?; - - Ok(ConfigResponse { - owner: config.owner, - vesting_token: config.vesting_token, - }) + Ok(config) } /// Return the current block timestamp (in seconds) @@ -538,3 +557,10 @@ fn compute_available_amount(current_time: u64, vesting_info: &VestingInfo) -> St .checked_sub(vesting_info.released_amount) .map_err(StdError::from) } + +fn get_vesting_token(config: &Config) -> Result { + config + .vesting_token + .clone() + .ok_or(ContractError::VestingTokenIsNotSet {}) +} diff --git a/packages/vesting-base/src/error.rs b/packages/vesting-base/src/error.rs index 30c9f4aa..96cc8ded 100644 --- a/packages/vesting-base/src/error.rs +++ b/packages/vesting-base/src/error.rs @@ -25,6 +25,9 @@ pub enum ContractError { #[error("Contract can't be migrated!")] MigrationError {}, + + #[error("Vesting token is not set!")] + VestingTokenIsNotSet {}, } impl From for ContractError { diff --git a/packages/vesting-base/src/state.rs b/packages/vesting-base/src/state.rs index f14501fe..a32c0bac 100644 --- a/packages/vesting-base/src/state.rs +++ b/packages/vesting-base/src/state.rs @@ -46,8 +46,10 @@ impl BaseVesting { pub struct Config { /// Address that's allowed to change contract parameters pub owner: Addr, + /// Address that's allowed to change vesting token + pub token_info_manager: Addr, /// [`AssetInfo`] of the vested token - pub vesting_token: AssetInfo, + pub vesting_token: Option, } const MAX_LIMIT: u32 = 30; diff --git a/packages/vesting-base/src/testing.rs b/packages/vesting-base/src/testing.rs index 8e452744..d3549f3e 100644 --- a/packages/vesting-base/src/testing.rs +++ b/packages/vesting-base/src/testing.rs @@ -1,4 +1,4 @@ -use astroport::vesting::{ConfigResponse, InstantiateMsg, QueryMsg}; +use astroport::vesting::{ConfigResponse, ExecuteMsg, InstantiateMsg, QueryMsg}; use astroport::asset::token_asset_info; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; @@ -14,14 +14,21 @@ fn proper_initialization() { let msg = InstantiateMsg { owner: "owner".to_string(), - vesting_token: token_asset_info(Addr::unchecked("ntrn_token")), + token_info_manager: "token_info_manager".to_string(), vesting_managers: vec!["manager1".to_string(), "manager2".to_string()], }; let env = mock_env(); let info = mock_info("addr0000", &[]); + let _res = vest_app.instantiate(deps.as_mut(), env, info, msg).unwrap(); + + let msg = ExecuteMsg::SetVestingToken { + vesting_token: token_asset_info(Addr::unchecked("ntrn_token")), + }; + let env = mock_env(); + let info = mock_info("token_info_manager", &[]); let _res = vest_app - .instantiate(deps.as_mut(), env.clone(), info, msg) + .execute(deps.as_mut(), env.clone(), info, msg) .unwrap(); assert_eq!( @@ -33,6 +40,7 @@ fn proper_initialization() { .unwrap(), ConfigResponse { owner: Addr::unchecked("owner"), + token_info_manager: Addr::unchecked("token_info_manager"), vesting_token: token_asset_info(Addr::unchecked("ntrn_token")), } );