Skip to content

Commit 3509edf

Browse files
authored
Dyn liquidity sources (#52)
1 parent d78183b commit 3509edf

File tree

8 files changed

+221
-127
lines changed

8 files changed

+221
-127
lines changed

apps/mtcs/contracts/cw-tee-mtcs/src/contract.rs

+38-35
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ use cosmwasm_std::{
44
};
55
use cw2::set_contract_version;
66
use cw20_base::{
7-
contract::{execute_mint, query_balance as cw20_query_balance},
7+
contract::query_balance as cw20_query_balance,
88
state::{MinterData, TokenInfo, TOKEN_INFO},
99
};
1010
use quartz_cw::{handler::RawHandler, state::EPOCH_COUNTER};
1111

1212
use crate::{
1313
error::ContractError,
1414
msg::{
15-
execute::{SubmitObligationMsg, SubmitObligationsMsg, SubmitSetoffsMsg},
15+
execute::{
16+
Cw20Transfer, FaucetMintMsg, SubmitObligationMsg, SubmitObligationsMsg,
17+
SubmitSetoffsMsg,
18+
},
1619
ExecuteMsg, InstantiateMsg, QueryMsg,
1720
},
1821
state::{
@@ -63,35 +66,6 @@ pub fn instantiate(
6366
};
6467
TOKEN_INFO.save(deps.storage, &data)?;
6568

66-
let info = MessageInfo {
67-
sender: env.contract.address.clone(),
68-
funds: vec![],
69-
};
70-
71-
execute_mint(
72-
deps.branch(),
73-
env.clone(),
74-
info.clone(),
75-
"wasm1qv9nel6lwtrq5jmwruxfndqw7ejskn5ysz53hp".to_owned(),
76-
Uint128::new(1000),
77-
)?;
78-
79-
execute_mint(
80-
deps.branch(),
81-
env.clone(),
82-
info.clone(),
83-
"wasm1tfxrdcj5kk6rewzmmkku4d9htpjqr0kk6lcftv".to_owned(),
84-
Uint128::new(1000),
85-
)?;
86-
87-
execute_mint(
88-
deps.branch(),
89-
env.clone(),
90-
info.clone(),
91-
"wasm1gjg72awjl7jvtmq4kjqp3al9p6crstpar8wgn5".to_owned(),
92-
Uint128::new(1000),
93-
)?;
94-
9569
Ok(Response::new()
9670
.add_attribute("method", "instantiate")
9771
.add_attribute("owner", info.sender))
@@ -106,6 +80,12 @@ pub fn execute(
10680
) -> Result<Response, ContractError> {
10781
match msg {
10882
ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into),
83+
ExecuteMsg::FaucetMint(FaucetMintMsg { recipient, amount }) => {
84+
execute::faucet_mint(deps, env, recipient, amount)
85+
}
86+
ExecuteMsg::Transfer(Cw20Transfer { recipient, amount }) => Ok(
87+
cw20_base::contract::execute_transfer(deps, env, info, recipient, amount.into())?,
88+
),
10989
ExecuteMsg::SubmitObligation(SubmitObligationMsg { ciphertext, digest }) => {
11090
execute::submit_obligation(deps, ciphertext, digest)
11191
}
@@ -120,7 +100,7 @@ pub fn execute(
120100
Ok(Response::new())
121101
}
122102
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
123-
execute::submit_setoffs(deps, env, info, setoffs_enc)
103+
execute::submit_setoffs(deps, env, setoffs_enc)
124104
}
125105
ExecuteMsg::InitClearing => execute::init_clearing(deps),
126106
}
@@ -131,6 +111,7 @@ pub mod execute {
131111

132112
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response, StdResult};
133113
use cw20_base::contract::{execute_burn, execute_mint};
114+
use k256::ecdsa::VerifyingKey;
134115
use quartz_cw::state::{Hash, EPOCH_COUNTER};
135116

136117
use crate::{
@@ -141,6 +122,28 @@ pub mod execute {
141122
ContractError,
142123
};
143124

125+
pub fn faucet_mint(
126+
mut deps: DepsMut,
127+
env: Env,
128+
recipient: String,
129+
amount: u64,
130+
) -> Result<Response, ContractError> {
131+
let info = MessageInfo {
132+
sender: env.contract.address.clone(),
133+
funds: vec![],
134+
};
135+
136+
execute_mint(
137+
deps.branch(),
138+
env.clone(),
139+
info.clone(),
140+
recipient.to_string(),
141+
amount.into(),
142+
)?;
143+
144+
Ok(Response::new().add_attribute("action", "faucet_mint"))
145+
}
146+
144147
pub fn submit_obligation(
145148
deps: DepsMut,
146149
ciphertext: HexBinary,
@@ -167,11 +170,12 @@ pub mod execute {
167170

168171
pub fn append_liquidity_sources(
169172
deps: DepsMut,
170-
liquidity_sources: Vec<String>,
173+
liquidity_sources: Vec<HexBinary>,
171174
) -> Result<(), ContractError> {
175+
// validate liquidity sources as public keys
172176
liquidity_sources
173177
.iter()
174-
.try_for_each(|ls| deps.api.addr_validate(ls).map(|_| ()))?;
178+
.try_for_each(|ls| VerifyingKey::from_sec1_bytes(ls).map(|_| ()))?;
175179

176180
// store the liquidity sources
177181
LiquiditySourcesItem::new(&current_epoch_key(LIQUIDITY_SOURCES_KEY, deps.storage)?)
@@ -186,7 +190,6 @@ pub mod execute {
186190
pub fn submit_setoffs(
187191
mut deps: DepsMut,
188192
env: Env,
189-
_info: MessageInfo,
190193
setoffs_enc: BTreeMap<RawHash, SettleOff>,
191194
) -> Result<Response, ContractError> {
192195
// store the `BTreeMap<RawHash, RawCipherText>`

apps/mtcs/contracts/cw-tee-mtcs/src/msg.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub struct InstantiateMsg(pub QuartzInstantiateMsg);
1313
#[allow(clippy::large_enum_variant)]
1414
pub enum ExecuteMsg {
1515
Quartz(QuartzExecuteMsg),
16+
FaucetMint(execute::FaucetMintMsg),
17+
Transfer(execute::Cw20Transfer),
1618
SubmitObligation(execute::SubmitObligationMsg),
1719
SubmitObligations(execute::SubmitObligationsMsg),
1820
SubmitSetoffs(execute::SubmitSetoffsMsg),
@@ -22,6 +24,18 @@ pub enum ExecuteMsg {
2224
pub mod execute {
2325
use super::*;
2426

27+
#[cw_serde]
28+
pub struct FaucetMintMsg {
29+
pub recipient: String,
30+
pub amount: u64,
31+
}
32+
33+
#[cw_serde]
34+
pub struct Cw20Transfer {
35+
pub recipient: String,
36+
pub amount: u64,
37+
}
38+
2539
#[cw_serde]
2640
pub struct SubmitObligationMsg {
2741
pub ciphertext: HexBinary,
@@ -33,7 +47,7 @@ pub mod execute {
3347
#[cw_serde]
3448
pub struct SubmitObligationsMsg {
3549
pub obligations: Vec<SubmitObligationMsg>,
36-
pub liquidity_sources: Vec<String>,
50+
pub liquidity_sources: Vec<HexBinary>,
3751
}
3852

3953
#[cw_serde]
@@ -69,7 +83,7 @@ pub struct GetAllSetoffsResponse {
6983

7084
#[cw_serde]
7185
pub struct GetLiquiditySourcesResponse {
72-
pub liquidity_sources: Vec<String>,
86+
pub liquidity_sources: Vec<HexBinary>,
7387
}
7488

7589
#[cfg(test)]

apps/mtcs/contracts/cw-tee-mtcs/src/state.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub type RawCipherText = HexBinary;
1010

1111
pub type ObligationsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
1212
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, SettleOff>>;
13-
pub type LiquiditySourcesItem<'a> = Item<'a, BTreeSet<String>>;
13+
pub type LiquiditySourcesItem<'a> = Item<'a, BTreeSet<HexBinary>>;
1414

1515
#[cw_serde]
1616
pub struct State {

core/quartz/src/mtcs_server.rs

+28-13
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,26 @@ use mtcs::{
1616
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
1717
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
1818
};
19+
use serde::{Deserialize, Serialize};
1920
use tonic::{Request, Response, Result as TonicResult, Status};
2021

2122
use crate::{
2223
attestor::Attestor,
2324
proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse},
2425
};
2526

26-
const BANK_PK: &str = "0216254f4636c4e68ae22d98538851a46810b65162fe37bf57cba6d563617c913e";
27-
2827
#[derive(Clone, Debug)]
2928
pub struct MtcsService<A> {
3029
sk: Arc<Mutex<Option<SigningKey>>>,
3130
_attestor: A,
3231
}
3332

33+
#[derive(Clone, Debug, Serialize, Deserialize)]
34+
pub struct RunClearingMessage {
35+
intents: BTreeMap<RawHash, RawCipherText>,
36+
liquidity_sources: Vec<HexBinary>,
37+
}
38+
3439
impl<A> MtcsService<A>
3540
where
3641
A: Attestor,
@@ -49,10 +54,12 @@ where
4954
&self,
5055
request: Request<RunClearingRequest>,
5156
) -> TonicResult<Response<RunClearingResponse>> {
52-
let message = request.into_inner().message;
57+
let message: RunClearingMessage = {
58+
let message = request.into_inner().message;
59+
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
60+
};
5361

54-
let digests_ciphertexts: BTreeMap<RawHash, RawCipherText> =
55-
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?;
62+
let digests_ciphertexts = message.intents;
5663
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();
5764

5865
let sk = self.sk.lock().unwrap();
@@ -64,9 +71,16 @@ where
6471
let mut mtcs = ComplexIdMtcs::wrapping(DefaultMtcs::new(PrimalDual::default()));
6572
let setoffs: Vec<SimpleSetoff<_, i64>> = mtcs.run(obligations).unwrap();
6673

74+
let liquidity_sources: Vec<_> = message
75+
.liquidity_sources
76+
.into_iter()
77+
.map(|ls| VerifyingKey::from_sec1_bytes(&ls))
78+
.collect::<Result<_, _>>()
79+
.map_err(|e| Status::invalid_argument(e.to_string()))?;
80+
6781
let setoffs_enc: BTreeMap<RawHash, SettleOff> = setoffs
6882
.into_iter()
69-
.map(into_settle_offs)
83+
.map(|so| into_settle_offs(so, &liquidity_sources))
7084
.zip(digests)
7185
.map(|(settle_off, digest)| (digest, settle_off))
7286
.collect();
@@ -76,25 +90,26 @@ where
7690
}
7791
}
7892

79-
fn into_settle_offs(so: SimpleSetoff<HexBinary, i64>) -> SettleOff {
93+
fn into_settle_offs(
94+
so: SimpleSetoff<HexBinary, i64>,
95+
liquidity_sources: &[VerifyingKey],
96+
) -> SettleOff {
8097
let debtor_pk = VerifyingKey::from_sec1_bytes(&so.debtor).unwrap();
8198
let creditor_pk = VerifyingKey::from_sec1_bytes(&so.creditor).unwrap();
8299

83-
let bank_pk = VerifyingKey::from_sec1_bytes(&hex::decode(BANK_PK).unwrap()).unwrap();
84-
let bank_addrs = wasm_address(bank_pk);
85-
if debtor_pk == bank_pk {
100+
if let Some(ls_pk) = liquidity_sources.iter().find(|ls| ls == &&debtor_pk) {
86101
// A setoff on a tender should result in the creditor's (i.e. the tender receiver) balance
87102
// decreasing by the setoff amount
88103
SettleOff::Transfer(Transfer {
89104
payer: wasm_address(creditor_pk),
90-
payee: bank_addrs,
105+
payee: wasm_address(*ls_pk),
91106
amount: so.set_off as u64,
92107
})
93-
} else if creditor_pk == bank_pk {
108+
} else if let Some(ls_pk) = liquidity_sources.iter().find(|ls| ls == &&creditor_pk) {
94109
// A setoff on an acceptance should result in the debtor's (i.e. the acceptance initiator)
95110
// balance increasing by the setoff amount
96111
SettleOff::Transfer(Transfer {
97-
payer: bank_addrs,
112+
payer: wasm_address(*ls_pk),
98113
payee: wasm_address(debtor_pk),
99114
amount: so.set_off as u64,
100115
})

utils/cycles-sync/src/cli.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ use displaydoc::Display;
66
use reqwest::Url;
77
use subtle_encoding::{bech32::decode as bech32_decode, Error as Bech32DecodeError};
88
use thiserror::Error;
9+
use uuid::Uuid;
10+
11+
use crate::ADDRESS_PREFIX;
912

1013
#[derive(Clone, Debug, Parser)]
1114
#[command(author, version, about)]
@@ -61,9 +64,17 @@ pub enum CliCommand {
6164
/// epoch pk
6265
#[arg(short, long)]
6366
epoch_pk: String,
67+
/// liquidity sources' UUIDs
68+
#[arg(short, long, num_args = 1.., value_parser = parse_uuid)]
69+
liquidity_sources: Vec<Uuid>,
6470
},
6571
/// Sync set-offs
6672
SyncSetOffs,
73+
/// Get address for Uuid
74+
GetAddress {
75+
#[arg(long, value_parser = parse_uuid)]
76+
uuid: Uuid,
77+
},
6778
}
6879

6980
#[derive(Display, Error, Debug)]
@@ -76,9 +87,13 @@ pub enum AddressError {
7687

7788
fn wasm_address(address_str: &str) -> Result<AccountId, AddressError> {
7889
let (hr, _) = bech32_decode(address_str).map_err(AddressError::NotBech32Encoded)?;
79-
if hr != "wasm" {
90+
if hr != ADDRESS_PREFIX {
8091
return Err(AddressError::HumanReadableMismatch(hr));
8192
}
8293

8394
Ok(address_str.parse().unwrap())
8495
}
96+
97+
fn parse_uuid(uuid_str: &str) -> Result<Uuid, String> {
98+
Uuid::parse_str(uuid_str).map_err(|e| e.to_string())
99+
}

0 commit comments

Comments
 (0)