Dyn liquidity sources (#52)

This commit is contained in:
Shoaib Ahmed 2024-06-18 02:30:00 -07:00 committed by GitHub
parent d78183b2c8
commit 3509edfe3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 221 additions and 127 deletions

View file

@ -4,7 +4,7 @@ use cosmwasm_std::{
};
use cw2::set_contract_version;
use cw20_base::{
contract::{execute_mint, query_balance as cw20_query_balance},
contract::query_balance as cw20_query_balance,
state::{MinterData, TokenInfo, TOKEN_INFO},
};
use quartz_cw::{handler::RawHandler, state::EPOCH_COUNTER};
@ -12,7 +12,10 @@ use quartz_cw::{handler::RawHandler, state::EPOCH_COUNTER};
use crate::{
error::ContractError,
msg::{
execute::{SubmitObligationMsg, SubmitObligationsMsg, SubmitSetoffsMsg},
execute::{
Cw20Transfer, FaucetMintMsg, SubmitObligationMsg, SubmitObligationsMsg,
SubmitSetoffsMsg,
},
ExecuteMsg, InstantiateMsg, QueryMsg,
},
state::{
@ -63,35 +66,6 @@ pub fn instantiate(
};
TOKEN_INFO.save(deps.storage, &data)?;
let info = MessageInfo {
sender: env.contract.address.clone(),
funds: vec![],
};
execute_mint(
deps.branch(),
env.clone(),
info.clone(),
"wasm1qv9nel6lwtrq5jmwruxfndqw7ejskn5ysz53hp".to_owned(),
Uint128::new(1000),
)?;
execute_mint(
deps.branch(),
env.clone(),
info.clone(),
"wasm1tfxrdcj5kk6rewzmmkku4d9htpjqr0kk6lcftv".to_owned(),
Uint128::new(1000),
)?;
execute_mint(
deps.branch(),
env.clone(),
info.clone(),
"wasm1gjg72awjl7jvtmq4kjqp3al9p6crstpar8wgn5".to_owned(),
Uint128::new(1000),
)?;
Ok(Response::new()
.add_attribute("method", "instantiate")
.add_attribute("owner", info.sender))
@ -106,6 +80,12 @@ pub fn execute(
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into),
ExecuteMsg::FaucetMint(FaucetMintMsg { recipient, amount }) => {
execute::faucet_mint(deps, env, recipient, amount)
}
ExecuteMsg::Transfer(Cw20Transfer { recipient, amount }) => Ok(
cw20_base::contract::execute_transfer(deps, env, info, recipient, amount.into())?,
),
ExecuteMsg::SubmitObligation(SubmitObligationMsg { ciphertext, digest }) => {
execute::submit_obligation(deps, ciphertext, digest)
}
@ -120,7 +100,7 @@ pub fn execute(
Ok(Response::new())
}
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
execute::submit_setoffs(deps, env, info, setoffs_enc)
execute::submit_setoffs(deps, env, setoffs_enc)
}
ExecuteMsg::InitClearing => execute::init_clearing(deps),
}
@ -131,6 +111,7 @@ pub mod execute {
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response, StdResult};
use cw20_base::contract::{execute_burn, execute_mint};
use k256::ecdsa::VerifyingKey;
use quartz_cw::state::{Hash, EPOCH_COUNTER};
use crate::{
@ -141,6 +122,28 @@ pub mod execute {
ContractError,
};
pub fn faucet_mint(
mut deps: DepsMut,
env: Env,
recipient: String,
amount: u64,
) -> Result<Response, ContractError> {
let info = MessageInfo {
sender: env.contract.address.clone(),
funds: vec![],
};
execute_mint(
deps.branch(),
env.clone(),
info.clone(),
recipient.to_string(),
amount.into(),
)?;
Ok(Response::new().add_attribute("action", "faucet_mint"))
}
pub fn submit_obligation(
deps: DepsMut,
ciphertext: HexBinary,
@ -167,11 +170,12 @@ pub mod execute {
pub fn append_liquidity_sources(
deps: DepsMut,
liquidity_sources: Vec<String>,
liquidity_sources: Vec<HexBinary>,
) -> Result<(), ContractError> {
// validate liquidity sources as public keys
liquidity_sources
.iter()
.try_for_each(|ls| deps.api.addr_validate(ls).map(|_| ()))?;
.try_for_each(|ls| VerifyingKey::from_sec1_bytes(ls).map(|_| ()))?;
// store the liquidity sources
LiquiditySourcesItem::new(&current_epoch_key(LIQUIDITY_SOURCES_KEY, deps.storage)?)
@ -186,7 +190,6 @@ pub mod execute {
pub fn submit_setoffs(
mut deps: DepsMut,
env: Env,
_info: MessageInfo,
setoffs_enc: BTreeMap<RawHash, SettleOff>,
) -> Result<Response, ContractError> {
// store the `BTreeMap<RawHash, RawCipherText>`

View file

@ -13,6 +13,8 @@ pub struct InstantiateMsg(pub QuartzInstantiateMsg);
#[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg {
Quartz(QuartzExecuteMsg),
FaucetMint(execute::FaucetMintMsg),
Transfer(execute::Cw20Transfer),
SubmitObligation(execute::SubmitObligationMsg),
SubmitObligations(execute::SubmitObligationsMsg),
SubmitSetoffs(execute::SubmitSetoffsMsg),
@ -22,6 +24,18 @@ pub enum ExecuteMsg {
pub mod execute {
use super::*;
#[cw_serde]
pub struct FaucetMintMsg {
pub recipient: String,
pub amount: u64,
}
#[cw_serde]
pub struct Cw20Transfer {
pub recipient: String,
pub amount: u64,
}
#[cw_serde]
pub struct SubmitObligationMsg {
pub ciphertext: HexBinary,
@ -33,7 +47,7 @@ pub mod execute {
#[cw_serde]
pub struct SubmitObligationsMsg {
pub obligations: Vec<SubmitObligationMsg>,
pub liquidity_sources: Vec<String>,
pub liquidity_sources: Vec<HexBinary>,
}
#[cw_serde]
@ -69,7 +83,7 @@ pub struct GetAllSetoffsResponse {
#[cw_serde]
pub struct GetLiquiditySourcesResponse {
pub liquidity_sources: Vec<String>,
pub liquidity_sources: Vec<HexBinary>,
}
#[cfg(test)]

View file

@ -10,7 +10,7 @@ pub type RawCipherText = HexBinary;
pub type ObligationsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, SettleOff>>;
pub type LiquiditySourcesItem<'a> = Item<'a, BTreeSet<String>>;
pub type LiquiditySourcesItem<'a> = Item<'a, BTreeSet<HexBinary>>;
#[cw_serde]
pub struct State {

View file

@ -16,6 +16,7 @@ use mtcs::{
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
};
use serde::{Deserialize, Serialize};
use tonic::{Request, Response, Result as TonicResult, Status};
use crate::{
@ -23,14 +24,18 @@ use crate::{
proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse},
};
const BANK_PK: &str = "0216254f4636c4e68ae22d98538851a46810b65162fe37bf57cba6d563617c913e";
#[derive(Clone, Debug)]
pub struct MtcsService<A> {
sk: Arc<Mutex<Option<SigningKey>>>,
_attestor: A,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RunClearingMessage {
intents: BTreeMap<RawHash, RawCipherText>,
liquidity_sources: Vec<HexBinary>,
}
impl<A> MtcsService<A>
where
A: Attestor,
@ -49,10 +54,12 @@ where
&self,
request: Request<RunClearingRequest>,
) -> TonicResult<Response<RunClearingResponse>> {
let message: RunClearingMessage = {
let message = request.into_inner().message;
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
};
let digests_ciphertexts: BTreeMap<RawHash, RawCipherText> =
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?;
let digests_ciphertexts = message.intents;
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();
let sk = self.sk.lock().unwrap();
@ -64,9 +71,16 @@ where
let mut mtcs = ComplexIdMtcs::wrapping(DefaultMtcs::new(PrimalDual::default()));
let setoffs: Vec<SimpleSetoff<_, i64>> = mtcs.run(obligations).unwrap();
let liquidity_sources: Vec<_> = message
.liquidity_sources
.into_iter()
.map(|ls| VerifyingKey::from_sec1_bytes(&ls))
.collect::<Result<_, _>>()
.map_err(|e| Status::invalid_argument(e.to_string()))?;
let setoffs_enc: BTreeMap<RawHash, SettleOff> = setoffs
.into_iter()
.map(into_settle_offs)
.map(|so| into_settle_offs(so, &liquidity_sources))
.zip(digests)
.map(|(settle_off, digest)| (digest, settle_off))
.collect();
@ -76,25 +90,26 @@ where
}
}
fn into_settle_offs(so: SimpleSetoff<HexBinary, i64>) -> SettleOff {
fn into_settle_offs(
so: SimpleSetoff<HexBinary, i64>,
liquidity_sources: &[VerifyingKey],
) -> SettleOff {
let debtor_pk = VerifyingKey::from_sec1_bytes(&so.debtor).unwrap();
let creditor_pk = VerifyingKey::from_sec1_bytes(&so.creditor).unwrap();
let bank_pk = VerifyingKey::from_sec1_bytes(&hex::decode(BANK_PK).unwrap()).unwrap();
let bank_addrs = wasm_address(bank_pk);
if debtor_pk == bank_pk {
if let Some(ls_pk) = liquidity_sources.iter().find(|ls| ls == &&debtor_pk) {
// A setoff on a tender should result in the creditor's (i.e. the tender receiver) balance
// decreasing by the setoff amount
SettleOff::Transfer(Transfer {
payer: wasm_address(creditor_pk),
payee: bank_addrs,
payee: wasm_address(*ls_pk),
amount: so.set_off as u64,
})
} else if creditor_pk == bank_pk {
} else if let Some(ls_pk) = liquidity_sources.iter().find(|ls| ls == &&creditor_pk) {
// A setoff on an acceptance should result in the debtor's (i.e. the acceptance initiator)
// balance increasing by the setoff amount
SettleOff::Transfer(Transfer {
payer: bank_addrs,
payer: wasm_address(*ls_pk),
payee: wasm_address(debtor_pk),
amount: so.set_off as u64,
})

View file

@ -6,6 +6,9 @@ use displaydoc::Display;
use reqwest::Url;
use subtle_encoding::{bech32::decode as bech32_decode, Error as Bech32DecodeError};
use thiserror::Error;
use uuid::Uuid;
use crate::ADDRESS_PREFIX;
#[derive(Clone, Debug, Parser)]
#[command(author, version, about)]
@ -61,9 +64,17 @@ pub enum CliCommand {
/// epoch pk
#[arg(short, long)]
epoch_pk: String,
/// liquidity sources' UUIDs
#[arg(short, long, num_args = 1.., value_parser = parse_uuid)]
liquidity_sources: Vec<Uuid>,
},
/// Sync set-offs
SyncSetOffs,
/// Get address for Uuid
GetAddress {
#[arg(long, value_parser = parse_uuid)]
uuid: Uuid,
},
}
#[derive(Display, Error, Debug)]
@ -76,9 +87,13 @@ pub enum AddressError {
fn wasm_address(address_str: &str) -> Result<AccountId, AddressError> {
let (hr, _) = bech32_decode(address_str).map_err(AddressError::NotBech32Encoded)?;
if hr != "wasm" {
if hr != ADDRESS_PREFIX {
return Err(AddressError::HumanReadableMismatch(hr));
}
Ok(address_str.parse().unwrap())
}
fn parse_uuid(uuid_str: &str) -> Result<Uuid, String> {
Uuid::parse_str(uuid_str).map_err(|e| e.to_string())
}

View file

@ -12,9 +12,10 @@ use bip32::{
ecdsa::VerifyingKey,
sha2::{Digest, Sha256},
},
Language, Mnemonic, Prefix, PrivateKey, Seed, XPrv,
Error as Bip32Error, Language, Mnemonic, Prefix, PrivateKey, Seed, XPrv,
};
use clap::Parser;
use cosmrs::{tendermint::account::Id as TmAccountId, AccountId};
use cosmwasm_std::HexBinary;
use serde::{Deserialize, Serialize};
use serde_json::json;
@ -26,7 +27,7 @@ use crate::{
obligato_client::{http::HttpClient, Client},
types::{
Obligation, ObligatoObligation, ObligatoSetOff, RawEncryptedObligation, RawObligation,
RawOffset, RawSetOff, SubmitObligationsMsg,
RawOffset, RawSetOff, SubmitObligationsMsg, SubmitObligationsMsgInner,
},
wasmd_client::{CliWasmdClient, QueryResult, WasmdClient},
};
@ -38,8 +39,7 @@ mod wasmd_client;
const MNEMONIC_PHRASE: &str = "clutch debate vintage foster barely primary clown leader sell manual leopard ladder wet must embody story oyster imitate cable alien six square rice wedding";
const ALICE_ID: &str = "7bfad4e8-d898-4ce2-bbac-1beff7182319";
const BANK_DEBTOR_ID: &str = "3879fa15-d86e-4464-b679-0a3d78cf3dd3";
const ADDRESS_PREFIX: &str = "wasm";
type Sha256Digest = [u8; 32];
@ -65,15 +65,38 @@ async fn main() -> Result<(), DynError> {
.init();
match cli.command {
CliCommand::SyncObligations { ref epoch_pk } => {
sync_obligations(cli.clone(), epoch_pk).await?
}
CliCommand::SyncObligations {
ref epoch_pk,
ref liquidity_sources,
} => sync_obligations(cli.clone(), epoch_pk, liquidity_sources).await?,
CliCommand::SyncSetOffs => sync_setoffs(cli).await?,
CliCommand::GetAddress { uuid } => address_from_uuid(uuid)?,
}
Ok(())
}
fn address_from_uuid(uuid: Uuid) -> Result<(), DynError> {
let seed = global_seed()?;
let sk = derive_child_xprv(&seed, uuid);
let pk_b = sk.public_key().public_key().to_sec1_bytes();
let pk = VerifyingKey::from_sec1_bytes(&pk_b)?;
println!("{}", wasm_address(pk));
Ok(())
}
fn wasm_address(pk: VerifyingKey) -> String {
let tm_pk = TmAccountId::from(pk);
AccountId::new(ADDRESS_PREFIX, tm_pk.as_bytes())
.unwrap()
.to_string()
}
fn global_seed() -> Result<Seed, Bip32Error> {
let mnemonic = Mnemonic::new(MNEMONIC_PHRASE, Language::English)?;
Ok(mnemonic.to_seed("password"))
}
async fn sync_setoffs(cli: Cli) -> Result<(), DynError> {
let wasmd_client = CliWasmdClient::new(cli.node);
let query_result: QueryResult<QueryAllSetoffsResponse> =
@ -123,34 +146,48 @@ async fn sync_setoffs(cli: Cli) -> Result<(), DynError> {
Ok(())
}
async fn sync_obligations(cli: Cli, epoch_pk: &str) -> Result<(), DynError> {
async fn sync_obligations(
cli: Cli,
epoch_pk: &str,
liquidity_sources: &[Uuid],
) -> Result<(), DynError> {
let mut intents = {
let client = HttpClient::new(cli.obligato_url, cli.obligato_key);
client.get_obligations().await.unwrap()
let client = HttpClient::new(cli.obligato_url.clone(), cli.obligato_key);
client
.get_obligations()
.await
.map_err(|_| cli.obligato_url.to_string())?
};
let bank_id = Uuid::parse_str(BANK_DEBTOR_ID).unwrap();
let keys = derive_keys(&mut intents, bank_id)?;
let keys = derive_keys(&mut intents, liquidity_sources)?;
write_keys_to_file(cli.keys_file, &keys);
add_default_acceptances(&mut intents, bank_id);
add_default_acceptances(&mut intents, liquidity_sources);
debug!("intents: {intents:?}");
let intents_enc = {
let epoch_pk = VerifyingKey::from_sec1_bytes(&hex::decode(epoch_pk).unwrap()).unwrap();
encrypt_intents(intents, keys, &epoch_pk, cli.obligation_user_map_file)
encrypt_intents(intents, &keys, &epoch_pk, cli.obligation_user_map_file)
};
debug!("Encrypted {} intents", intents_enc.len());
let msg = create_wasm_msg(intents_enc);
let liquidity_sources = liquidity_sources
.iter()
.map(|id| keys[id].private_key().public_key())
.collect();
let msg = create_wasm_msg(intents_enc, liquidity_sources)?;
let wasmd_client = CliWasmdClient::new(cli.node);
wasmd_client.tx_execute(&cli.contract, &cli.chain_id, 3000000, cli.user, msg)?;
Ok(())
}
fn create_wasm_msg(obligations_enc: Vec<(Sha256Digest, Vec<u8>)>) -> serde_json::Value {
fn create_wasm_msg(
obligations_enc: Vec<(Sha256Digest, Vec<u8>)>,
liquidity_sources: Vec<VerifyingKey>,
) -> Result<serde_json::Value, DynError> {
let obligations_enc: Vec<_> = obligations_enc
.into_iter()
.map(|(digest, ciphertext)| {
@ -160,15 +197,23 @@ fn create_wasm_msg(obligations_enc: Vec<(Sha256Digest, Vec<u8>)>) -> serde_json:
})
.collect();
let liquidity_sources = liquidity_sources
.into_iter()
.map(|pk| HexBinary::from(pk.to_sec1_bytes().as_ref()))
.collect();
let msg = SubmitObligationsMsg {
submit_obligations: obligations_enc,
submit_obligations: SubmitObligationsMsgInner {
obligations: obligations_enc,
liquidity_sources,
},
};
serde_json::to_value(msg).unwrap()
serde_json::to_value(msg).map_err(Into::into)
}
fn encrypt_intents(
intents: Vec<ObligatoObligation>,
keys: HashMap<Uuid, XPrv>,
keys: &HashMap<Uuid, XPrv>,
epoch_pk: &VerifyingKey,
obligation_user_map_file: PathBuf,
) -> Vec<(Sha256Digest, Vec<u8>)> {
@ -209,17 +254,19 @@ fn encrypt_intents(
intents_enc
}
fn add_default_acceptances(obligations: &mut Vec<ObligatoObligation>, bank_id: Uuid) {
fn add_default_acceptances(obligations: &mut Vec<ObligatoObligation>, liquidity_sources: &[Uuid]) {
let acceptances = obligations.iter().fold(HashSet::new(), |mut acc, o| {
if o.debtor_id != bank_id {
if !liquidity_sources.contains(&o.debtor_id) {
for ls in liquidity_sources {
let acceptance = ObligatoObligation {
id: Default::default(),
debtor_id: o.creditor_id,
creditor_id: bank_id,
creditor_id: *ls,
amount: u32::MAX as u64,
};
acc.insert(acceptance);
}
}
acc
});
@ -274,41 +321,46 @@ fn write_obligation_user_map_to_file(
fn derive_keys(
obligations: &mut Vec<ObligatoObligation>,
bank_id: Uuid,
liquidity_sources: &[Uuid],
) -> Result<HashMap<Uuid, XPrv>, DynError> {
// Derive a BIP39 seed value using the given password
let seed = {
let mnemonic = Mnemonic::new(MNEMONIC_PHRASE, Language::English)?;
mnemonic.to_seed("password")
};
let seed = global_seed()?;
obligations.sort_by_key(|o| o.debtor_id);
let mut keys = HashMap::new();
let mut child_num = 0;
let alice_id = Uuid::parse_str(ALICE_ID).unwrap();
keys.entry(alice_id)
.or_insert_with(|| derive_child_xprv(&seed, &mut child_num));
keys.entry(bank_id)
.or_insert_with(|| derive_child_xprv(&seed, &mut child_num));
for ls in liquidity_sources {
keys.entry(*ls)
.or_insert_with(|| derive_child_xprv(&seed, *ls));
}
for o in obligations {
keys.entry(o.debtor_id)
.or_insert_with(|| derive_child_xprv(&seed, &mut child_num));
.or_insert_with(|| derive_child_xprv(&seed, o.debtor_id));
keys.entry(o.creditor_id)
.or_insert_with(|| derive_child_xprv(&seed, &mut child_num));
.or_insert_with(|| derive_child_xprv(&seed, o.creditor_id));
}
Ok(keys)
}
fn derive_child_xprv(seed: &Seed, i: &mut usize) -> XPrv {
let child_path = format!("m/0/44'/118'/0'/0/{}", i).parse().unwrap();
fn derive_child_xprv(seed: &Seed, uuid: Uuid) -> XPrv {
// Hash the UUID using SHA-256
let mut hasher = Sha256::new();
hasher.update(uuid.as_bytes());
let uuid_digest = hasher.finalize();
// Convert the hash bytes to a number
let uuid_digest_num = u128::from_be_bytes(uuid_digest[..16].try_into().unwrap());
// Take modulo (2^31 - 1)
let address_index = uuid_digest_num % ((1u128 << 31) - 1);
let child_path = format!("m/0/44'/118'/0'/0/{address_index}")
.parse()
.unwrap();
let child_xprv = XPrv::derive_from_path(seed, &child_path);
*i += 1;
child_xprv.unwrap()
}
@ -316,52 +368,40 @@ fn derive_child_xprv(seed: &Seed, i: &mut usize) -> XPrv {
mod tests {
use std::{error::Error, str::FromStr};
use bip32::{Language, Mnemonic, Prefix, PrivateKey, XPrv};
use bip32::{Mnemonic, Prefix, PrivateKey, XPrv};
use rand_core::OsRng;
use uuid::Uuid;
use crate::{derive_child_xprv, MNEMONIC_PHRASE};
use crate::{derive_child_xprv, global_seed};
#[test]
fn test_create_mnemonic() {
// Generate random Mnemonic using the default language (English)
let mnemonic = Mnemonic::random(&mut OsRng, Default::default());
println!("{}", mnemonic.phrase());
}
#[test]
fn test_enc_dec_for_derived() -> Result<(), Box<dyn Error>> {
let seed = {
let mnemonic = Mnemonic::new(MNEMONIC_PHRASE, Language::English)?;
mnemonic.to_seed("password")
};
let seed = global_seed()?;
let alice_uuid = Uuid::from_u128(1);
let alice_sk = derive_child_xprv(&seed, alice_uuid);
let alice_pk = alice_sk.private_key().public_key();
let mut child_num = 0;
let alice_sk = derive_child_xprv(&seed, &mut child_num);
let alice_sk_str = alice_sk.to_string(Prefix::XPRV).to_string();
assert_eq!(
alice_sk.private_key().public_key().to_sec1_bytes(),
hex::decode("02027e3510f66f1f6c1ea5e3600062255928e518220f7883810cac3fc7fc092057")
alice_pk.to_sec1_bytes(),
hex::decode("0219b0b8ee5fe9b317b69119fd15170d79737380c4f020e251b7839096f5513ccf")
.unwrap()
.into()
);
let alice_sk_str = alice_sk.to_string(Prefix::XPRV).to_string();
assert_eq!(XPrv::from_str(&alice_sk_str).unwrap(), alice_sk);
let alice_pk = alice_sk.private_key().public_key();
assert_eq!(
alice_pk.to_sec1_bytes().into_vec(),
vec![
2, 2, 126, 53, 16, 246, 111, 31, 108, 30, 165, 227, 96, 0, 98, 37, 89, 40, 229, 24,
34, 15, 120, 131, 129, 12, 172, 63, 199, 252, 9, 32, 87
]
);
let msg = r#"{"debtor":"02027e3510f66f1f6c1ea5e3600062255928e518220f7883810cac3fc7fc092057","creditor":"0216254f4636c4e68ae22d98538851a46810b65162fe37bf57cba6d563617c913e","amount":10,"salt":"65c188bcc133add598f7eecc449112f4bf61024345316cff0eb5ce61291991b141073dcd3c543ea142e66fffa8f483dc382043d37e490ef9b8069c489ce94a0b"}"#;
let ciphertext = ecies::encrypt(&alice_pk.to_sec1_bytes(), msg.as_bytes()).unwrap();
// let ciphertext = hex::decode("0418d9051cbfc86c8ddd57ae43ea3d1ac8b30353a3ecd8c806bb11f0693dfd282d5f07d1de32cbcd933d5ab7cd0aa171c972e75531b915e968f0fdeba78fa3f359c7f3ef7ae2dfffeb19493e9b2418dc774e6e80448a2dc4a7ba657cd4a8456e120977ebe372a57187d53981cc5856fbd63e9c1bdf001ed71c3d50cbaff594561191d33dad852cb782126f480add2cc92758b59eb63de857d299eaa5f09fbc55643a73b1d8206ce83453b5296b566d9f622520679bb3e6d9c8b7a707f33d3093c41dfc0a8267749b4028e9ee0faad0c8df64f1682a348f220585fdd9b9ac411bdaaa6a249b45accc89a80e5af09abb239231aa869e29459e562721b685d98b3da3eeaef14e1c5f3bd20cf27c0cbbae7b5c618e737df9a84f9a040bb472b7254af2cf4ccc76784cf8432080e528f700ca2a082b7020d94f0f5325dd4998c03972a0b39e6670b65be89e7a80aad7af08a393fcf2e103999254380c1f0355d97ddcdfaeed4bcfaf15b578cee1f6d3fd4ceccd85760b9bd714f81698ddf6fbbc06152a9306a5dd0052c722e390470f0c70eeac81a5da0090").unwrap();
println!("{}", hex::encode(&ciphertext));
// println!("{}", hex::encode(&ciphertext));
let msg_dec =
ecies::decrypt(&alice_sk.private_key().to_bytes(), ciphertext.as_slice()).unwrap();

View file

@ -4,10 +4,11 @@ use uuid::Uuid;
use crate::{
obligato_client::Client,
types::{ObligatoObligation, ObligatoSetOff},
BANK_DEBTOR_ID,
};
pub struct MockClient;
pub struct MockClient {
pub bank: Uuid,
}
#[async_trait]
impl Client for MockClient {
@ -25,7 +26,7 @@ impl Client for MockClient {
// tender: $ --10--> 1
ObligatoObligation {
id: Uuid::from_u128(2),
debtor_id: Uuid::parse_str(BANK_DEBTOR_ID).unwrap(),
debtor_id: self.bank,
creditor_id: Uuid::from_u128(1),
amount: 10,
},

View file

@ -47,7 +47,13 @@ pub struct RawEncryptedObligation {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubmitObligationsMsg {
pub submit_obligations: Vec<RawEncryptedObligation>,
pub submit_obligations: SubmitObligationsMsgInner,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubmitObligationsMsgInner {
pub obligations: Vec<RawEncryptedObligation>,
pub liquidity_sources: Vec<HexBinary>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]