Skip to content

Commit

Permalink
feat: first try
Browse files Browse the repository at this point in the history
  • Loading branch information
ratik committed Dec 18, 2023
1 parent 55b1e00 commit b4cec6f
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 45 deletions.
113 changes: 101 additions & 12 deletions contracts/core/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ use cosmwasm_std::{
};
use cw2::set_contract_version;
use lido_staking_base::helpers::answer::response;
use lido_staking_base::msg::core::{ExecuteMsg, InstantiateMsg, QueryMsg};
use lido_staking_base::msg::token::ExecuteMsg as TokenExecuteMsg;
use lido_staking_base::state::core::CONFIG;
use lido_staking_base::msg::{
core::{ExecuteMsg, InstantiateMsg, QueryMsg},
token::ExecuteMsg as TokenExecuteMsg,
voucher::ExecuteMsg as VoucherExecuteMsg,
};
use lido_staking_base::state::core::{
UnbondBatchStatus, UnbondItem, CONFIG, UNBOND_BATCHES, UNBOND_BATCH_ID,
};
use lido_staking_base::state::voucher::{Metadata, Trait};
use neutron_sdk::bindings::{msg::NeutronMsg, query::NeutronQuery};
use std::str::FromStr;
use std::vec;
Expand All @@ -22,14 +28,23 @@ pub fn instantiate(
msg: InstantiateMsg,
) -> ContractResult<Response<NeutronMsg>> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

CONFIG.save(deps.storage, &msg.clone().into())?;
let attrs: Vec<Attribute> = vec![
attr("token_contract", msg.token_contract),
attr("puppeteer_contract", msg.puppeteer_contract),
attr("strategy_contract", msg.strategy_contract),
attr("owner", msg.owner),
];
UNBOND_BATCH_ID.save(deps.storage, &0u128)?;
UNBOND_BATCHES.save(
deps.storage,
0u128,
&lido_staking_base::state::core::UnbondBatch {
total_amount: Uint128::zero(),
unbond_items: vec![],
status: UnbondBatchStatus::New,
},
)?;
Ok(response("instantiate", CONTRACT_NAME, attrs))
}

Expand All @@ -54,20 +69,21 @@ pub fn execute(
) -> ContractResult<Response<NeutronMsg>> {
match msg {
ExecuteMsg::Bond { receiver } => execute_bond(deps, env, info, receiver),
ExecuteMsg::Unbond { amount } => execute_unbond(deps, env, info, amount),
ExecuteMsg::Unbond {} => execute_unbond(deps, env, info),
ExecuteMsg::UpdateConfig {
token_contract,
puppeteer_contract,
strategy_contract,
owner,
ld_denom,
} => execute_update_config(
deps,
env,
info,
token_contract,
puppeteer_contract,
strategy_contract,
owner,
ld_denom,
),
}
}
Expand Down Expand Up @@ -131,12 +147,12 @@ fn check_denom(_denom: String) -> ContractResult<()> {

fn execute_update_config(
deps: DepsMut<NeutronQuery>,
_env: Env,
info: MessageInfo,
token_contract: Option<String>,
puppeteer_contract: Option<String>,
strategy_contract: Option<String>,
owner: Option<String>,
ld_denom: Option<String>,
) -> ContractResult<Response<NeutronMsg>> {
let mut config = CONFIG.load(deps.storage)?;
ensure_eq!(config.owner, info.sender, ContractError::Unauthorized {});
Expand All @@ -158,15 +174,88 @@ fn execute_update_config(
config.owner = owner.clone();
attrs.push(attr("owner", owner));
}
if let Some(ld_denom) = ld_denom {
config.ld_denom = Some(ld_denom.clone());
attrs.push(attr("ld_denom", ld_denom));
}
CONFIG.save(deps.storage, &config)?;
Ok(response("execute-update_config", CONTRACT_NAME, attrs))
}

fn execute_unbond(
_deps: DepsMut<NeutronQuery>,
_env: Env,
_info: MessageInfo,
_amount: Uint128,
deps: DepsMut<NeutronQuery>,
env: Env,
info: MessageInfo,
) -> ContractResult<Response<NeutronMsg>> {
unimplemented!("todo");
let mut attrs = vec![attr("action", "unbond")];
let unbond_batch_id = UNBOND_BATCH_ID.load(deps.storage)?;
if info.funds.len() != 1 {
return Err(ContractError::InvalidFunds {
reason: "Must be one token".to_string(),
});
}
let config = CONFIG.load(deps.storage)?;
let ld_denom = config.ld_denom.ok_or(ContractError::LDDenomIsNotSet {})?;
let amount = info.funds[0].amount;
let denom = info.funds[0].denom.to_string();
if denom != ld_denom {
return Err(ContractError::InvalidFunds {
reason: "Must be LD token".to_string(),
});
}
let mut unbond_batch = UNBOND_BATCHES.load(deps.storage, unbond_batch_id)?;
unbond_batch.unbond_items.push(UnbondItem {
sender: info.sender.to_string(),
amount,
});
let exchange_rate = query_exchange_rate(deps.as_ref(), env)?;
attrs.push(attr("exchange_rate", exchange_rate.to_string()));
let expected_amount = amount * exchange_rate;
attrs.push(attr("expected_amount", expected_amount.to_string()));
UNBOND_BATCHES.save(deps.storage, unbond_batch_id, &unbond_batch)?;
let extension = Some(Metadata {
description: Some("Withdrawal voucher".into()),
name: "LDV voucher".to_string(),
batch_id: unbond_batch_id.to_string(),
amount,
expected_amount,
attributes: Some(vec![
Trait {
display_type: None,
trait_type: "unbond_batch_id".to_string(),
value: unbond_batch_id.to_string(),
},
Trait {
display_type: None,
trait_type: "received_amount".to_string(),
value: amount.to_string(),
},
Trait {
display_type: None,
trait_type: "expected_amount".to_string(),
value: expected_amount.to_string(),
},
Trait {
display_type: None,
trait_type: "exchange_rate".to_string(),
value: exchange_rate.to_string(),
},
]),
});
let msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: config.voucher_contract,
msg: to_json_binary(&VoucherExecuteMsg::Mint {
owner: info.sender.to_string(),
token_id: unbond_batch_id.to_string()
+ "_"
+ info.sender.to_string().as_str()
+ "_"
+ &unbond_batch.unbond_items.len().to_string(),
token_uri: None,
extension,
})?,
funds: vec![],
});

Ok(response("execute-unbond", CONTRACT_NAME, attrs).add_message(msg))
}
3 changes: 3 additions & 0 deletions contracts/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum ContractError {

#[error("Unauthorized")]
Unauthorized {},

#[error("LD denom is not set")]
LDDenomIsNotSet {},
}

pub type ContractResult<T> = Result<T, ContractError>;
48 changes: 44 additions & 4 deletions contracts/factory/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
use crate::{
error::ContractResult,
msg::{ExecuteMsg, InstantiateMsg, QueryMsg},
msg::{CallbackMsg, ExecuteMsg, InstantiateMsg, QueryMsg},
state::{Config, State, CONFIG, STATE},
};
use cosmwasm_std::{
attr, entry_point, instantiate2_address, to_json_binary, Binary, CodeInfoResponse, CosmosMsg,
Deps, DepsMut, Env, HexBinary, MessageInfo, Response, StdResult, WasmMsg,
Deps, DepsMut, Env, HexBinary, MessageInfo, QueryRequest, Response, StdResult, WasmMsg,
WasmQuery,
};
use cw2::set_contract_version;

use lido_staking_base::{
helpers::answer::response, msg::core::InstantiateMsg as CoreInstantiateMsg,
msg::token::InstantiateMsg as TokenInstantiateMsg,
helpers::answer::response,
msg::core::{ExecuteMsg as CoreExecuteMsg, InstantiateMsg as CoreInstantiateMsg},
msg::token::{
ConfigResponse as TokenConfigResponse, InstantiateMsg as TokenInstantiateMsg,
QueryMsg as TokenQueryMsg,
},
msg::voucher::InstantiateMsg as VoucherInstantiateMsg,
};
use neutron_sdk::{
Expand Down Expand Up @@ -70,6 +75,9 @@ pub fn execute(
) -> ContractResult<Response<NeutronMsg>> {
match msg {
ExecuteMsg::Init {} => execute_init(deps, env, info),
ExecuteMsg::Callback(msg) => match msg {
CallbackMsg::PostInit {} => execute_post_init(deps, env, info),
},
}
}

Expand Down Expand Up @@ -127,6 +135,7 @@ fn execute_init(
token_contract: token_contract.to_string(),
puppeteer_contract: "".to_string(),
strategy_contract: "".to_string(),
voucher_contract: voucher_contract.to_string(),
owner: env.contract.address.to_string(),
})?,
funds: vec![],
Expand All @@ -144,11 +153,42 @@ fn execute_init(
funds: vec![],
salt: Binary::from(salt),
}),
CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: env.contract.address.to_string(),
msg: to_json_binary(&ExecuteMsg::Callback(CallbackMsg::PostInit {}))?,
funds: vec![],
}),
];

Ok(response("execute-init", CONTRACT_NAME, attrs).add_messages(msgs))
}

fn execute_post_init(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
) -> ContractResult<Response<NeutronMsg>> {
let attrs = vec![attr("action", "post_init")];
let state = STATE.load(deps.storage)?;
let token_config: TokenConfigResponse =
deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: state.token_contract,
msg: to_json_binary(&TokenQueryMsg::Config {})?,
}))?;
let core_update_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: state.core_contract,
msg: to_json_binary(&CoreExecuteMsg::UpdateConfig {
token_contract: None,
puppeteer_contract: None,
strategy_contract: None,
owner: None,
ld_denom: Some(token_config.denom),
})?,
funds: vec![],
});
Ok(response("execute-post_init", CONTRACT_NAME, attrs).add_message(core_update_msg))
}

fn get_code_checksum(deps: Deps, code_id: u64) -> NeutronResult<HexBinary> {
let CodeInfoResponse { checksum, .. } = deps.querier.query_wasm_code_info(code_id)?;
Ok(checksum)
Expand Down
6 changes: 6 additions & 0 deletions contracts/factory/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ pub struct InstantiateMsg {
pub subdenom: String,
}

#[cw_serde]
pub enum CallbackMsg {
PostInit {},
}

#[cw_serde]
pub enum ExecuteMsg {
Init {},
Callback(CallbackMsg),
}
#[cw_serde]
pub enum MigrateMsg {}
Expand Down
27 changes: 7 additions & 20 deletions integration_tests/src/generated/contractLib/lidoCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,33 @@ export interface InstantiateMsg {
puppeteer_contract: string;
strategy_contract: string;
token_contract: string;
voucher_contract: string;
}
/**
* A fixed-point decimal value with 18 fractional digits, i.e. Decimal256(1_000_000_000_000_000_000) == 1.0
*
* The greatest possible value that can be represented is 115792089237316195423570985008687907853269984665640564039457.584007913129639935 (which is (2^256 - 1) / 10^18)
*/
export type Decimal256 = string;
/**
* 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.
*
* # Examples
*
* Use `from` to create instances of this and `u128` to get the value out:
*
* ``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);
*
* let b = Uint128::from(42u64); assert_eq!(b.u128(), 42);
*
* let c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```
*/
export type Uint128 = string;

export interface LidoCoreSchema {
responses: Config | Decimal256;
execute: BondArgs | UnbondArgs | UpdateConfigArgs;
execute: BondArgs | UpdateConfigArgs;
[k: string]: unknown;
}
export interface Config {
ld_denom?: string | null;
owner: string;
puppeteer_contract: string;
strategy_contract: string;
token_contract: string;
voucher_contract: string;
}
export interface BondArgs {
receiver?: string | null;
}
export interface UnbondArgs {
amount: Uint128;
}
export interface UpdateConfigArgs {
ld_denom?: string | null;
owner?: string | null;
puppeteer_contract?: string | null;
strategy_contract?: string | null;
Expand Down Expand Up @@ -93,9 +80,9 @@ export class Client {
if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); }
return this.client.execute(sender, this.contractAddress, { bond: args }, fee || "auto", memo, funds);
}
unbond = async(sender:string, args: UnbondArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<ExecuteResult> => {
unbond = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<ExecuteResult> => {
if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); }
return this.client.execute(sender, this.contractAddress, { unbond: args }, fee || "auto", memo, funds);
return this.client.execute(sender, this.contractAddress, { unbond: {} }, fee || "auto", memo, funds);
}
updateConfig = async(sender:string, args: UpdateConfigArgs, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<ExecuteResult> => {
if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); }
Expand Down
4 changes: 4 additions & 0 deletions integration_tests/src/generated/contractLib/lidoFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ export class Client {
if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); }
return this.client.execute(sender, this.contractAddress, { init: {} }, fee || "auto", memo, funds);
}
callback = async(sender: string, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<ExecuteResult> => {
if (!isSigningCosmWasmClient(this.client)) { throw this.mustBeSigningClient(); }
return this.client.execute(sender, this.contractAddress, { callback: {} }, fee || "auto", memo, funds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ export interface Metadata {
attributes?: Trait[] | null;
batch_id: string;
description?: string | null;
expected_amount: Uint128;
name: string;
}
export interface Trait {
Expand Down
Loading

0 comments on commit b4cec6f

Please sign in to comment.