feat: decoupling quartz from applications, creating transfers app (#64)
Co-authored-by: hu55a1n1 <sufialhussaini@gmail.com> Co-authored-by: Ethan Buchman <ethan@coinculture.info> Co-authored-by: David Kajpust <kajpustd@gmail.com>
This commit is contained in:
parent
fcad39e5d0
commit
47544c66ae
38 changed files with 7930 additions and 28 deletions
61
Cargo.lock
generated
61
Cargo.lock
generated
|
@ -477,6 +477,7 @@ version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d184abb7b0039cc64f282dfa5b34165e4c5a7410ab46804636d53f4d09aee44"
|
checksum = "5d184abb7b0039cc64f282dfa5b34165e4c5a7410ab46804636d53f4d09aee44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bip32",
|
||||||
"cosmos-sdk-proto",
|
"cosmos-sdk-proto",
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
@ -652,6 +653,25 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw-multi-test"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d818f5323c80ed4890db7f89d65eda3f0261fe21878e628c27ea2d8de4b7ba4"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus",
|
||||||
|
"cw-utils",
|
||||||
|
"derivative",
|
||||||
|
"itertools 0.11.0",
|
||||||
|
"prost",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cw-proof"
|
name = "cw-proof"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1020,6 +1040,36 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enclave"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"color-eyre",
|
||||||
|
"cosmrs",
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-multi-test",
|
||||||
|
"cw-tee-mtcs",
|
||||||
|
"cycles-sync",
|
||||||
|
"ecies",
|
||||||
|
"hex",
|
||||||
|
"k256",
|
||||||
|
"mtcs",
|
||||||
|
"prost",
|
||||||
|
"quartz-cw",
|
||||||
|
"quartz-enclave",
|
||||||
|
"quartz-proto",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tendermint 0.36.0",
|
||||||
|
"tendermint-light-client",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tonic",
|
||||||
|
"tonic-build",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.34"
|
version = "0.8.34"
|
||||||
|
@ -1568,6 +1618,15 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -2312,7 +2371,6 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"k256",
|
"k256",
|
||||||
"mtcs",
|
"mtcs",
|
||||||
"prost",
|
|
||||||
"quartz-cw",
|
"quartz-cw",
|
||||||
"quartz-proto",
|
"quartz-proto",
|
||||||
"quartz-relayer",
|
"quartz-relayer",
|
||||||
|
@ -2325,7 +2383,6 @@ dependencies = [
|
||||||
"tm-stateless-verifier",
|
"tm-stateless-verifier",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-build",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [ "apps/mtcs/enclave",
|
||||||
"core/light-client-proofs/*",
|
"core/light-client-proofs/*",
|
||||||
"core/quartz",
|
"core/quartz",
|
||||||
"cosmwasm/packages/*",
|
"cosmwasm/packages/*",
|
||||||
"utils/*",
|
"utils/*",
|
||||||
]
|
]
|
||||||
exclude = ["apps/mtcs/contracts/cw-tee-mtcs"]
|
exclude = ["apps/mtcs/contracts/cw-tee-mtcs", "apps/mtcs/enclave", "apps/transfers", "apps/transfers/enclave"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
52
apps/mtcs/enclave/Cargo.toml
Normal file
52
apps/mtcs/enclave/Cargo.toml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
[package]
|
||||||
|
name = "enclave"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
debug = false
|
||||||
|
rpath = false
|
||||||
|
lto = true
|
||||||
|
debug-assertions = false
|
||||||
|
codegen-units = 1
|
||||||
|
panic = 'abort'
|
||||||
|
incremental = false
|
||||||
|
overflow-checks = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# external
|
||||||
|
hex = { version = "0.4.3", default-features = false }
|
||||||
|
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] }
|
||||||
|
schemars = "0.8.15"
|
||||||
|
serde = { version = "1.0.189", default-features = false, features = ["derive"] }
|
||||||
|
thiserror = { version = "1.0.49" }
|
||||||
|
tonic = { version = "0.11.0"}
|
||||||
|
tonic-build = "0.11.0"
|
||||||
|
cosmrs = { version = "0.16.0"}
|
||||||
|
cosmwasm-std = { version = "1.5.2", default-features = false }
|
||||||
|
serde_json = { version = "1.0.94", default-features = false }
|
||||||
|
ecies = { version = "0.2.3", default-features = false, features = ["pure"] }
|
||||||
|
clap = { version = "4.1.8", default-features = false, features = ["derive", "std"] }
|
||||||
|
tokio = { version = "1.0", default-features = false, features = ["macros", "rt-multi-thread"] }
|
||||||
|
tendermint = { version = "=0.36.0", default-features = false }
|
||||||
|
tendermint-light-client = { version = "=0.36.0", default-features = false, features = ["rust-crypto"] }
|
||||||
|
color-eyre = { version = "0.6.2", default-features = false }
|
||||||
|
prost = { version = "0.12.3", default-features = false }
|
||||||
|
|
||||||
|
# local
|
||||||
|
cw-tee-mtcs.workspace = true
|
||||||
|
cycles-sync.workspace = true
|
||||||
|
mtcs.workspace = true
|
||||||
|
|
||||||
|
# quartz
|
||||||
|
quartz-cw = { path = "../../../cosmwasm/packages/quartz-cw" }
|
||||||
|
quartz-proto = { path = "../../../core/quartz-proto" }
|
||||||
|
quartz-enclave = { path = "../../../core/quartz"}
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
cw-multi-test = "0.17.0"
|
||||||
|
serde_json = "1.0.113"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tonic-build.workspace = true
|
1
apps/mtcs/enclave/README.md
Normal file
1
apps/mtcs/enclave/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
## MTCS Server
|
|
@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use tendermint::Hash;
|
use cosmrs::tendermint::Hash;
|
||||||
use tendermint_light_client::types::{Height, TrustThreshold};
|
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||||
|
|
||||||
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
|
@ -13,11 +13,9 @@
|
||||||
unused_qualifications
|
unused_qualifications
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod attestor;
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod mtcs_server;
|
mod mtcs_server;
|
||||||
mod proto;
|
mod proto;
|
||||||
mod server;
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
@ -25,17 +23,16 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use cli::Cli;
|
||||||
|
use mtcs_server::MtcsService;
|
||||||
|
use proto::clearing_server::ClearingServer as MtcsServer;
|
||||||
use quartz_cw::state::{Config, LightClientOpts};
|
use quartz_cw::state::{Config, LightClientOpts};
|
||||||
use quartz_proto::quartz::core_server::CoreServer;
|
use quartz_enclave::{
|
||||||
use tonic::transport::Server;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
attestor::{Attestor, EpidAttestor},
|
attestor::{Attestor, EpidAttestor},
|
||||||
cli::Cli,
|
|
||||||
mtcs_server::MtcsService,
|
|
||||||
proto::clearing_server::ClearingServer as MtcsServer,
|
|
||||||
server::CoreService,
|
server::CoreService,
|
||||||
};
|
};
|
||||||
|
use quartz_proto::quartz::core_server::CoreServer;
|
||||||
|
use tonic::transport::Server;
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
@ -5,9 +5,10 @@ use std::{
|
||||||
|
|
||||||
use cosmrs::{tendermint::account::Id as TmAccountId, AccountId};
|
use cosmrs::{tendermint::account::Id as TmAccountId, AccountId};
|
||||||
use cosmwasm_std::HexBinary;
|
use cosmwasm_std::HexBinary;
|
||||||
|
//TODO: get rid of this
|
||||||
use cw_tee_mtcs::{
|
use cw_tee_mtcs::{
|
||||||
msg::execute::SubmitSetoffsMsg,
|
msg::execute::SubmitSetoffsMsg,
|
||||||
state::{RawCipherText, RawHash, SettleOff, Transfer},
|
state::{RawHash, SettleOff, Transfer},
|
||||||
};
|
};
|
||||||
use cycles_sync::types::RawObligation;
|
use cycles_sync::types::RawObligation;
|
||||||
use ecies::{decrypt, encrypt};
|
use ecies::{decrypt, encrypt};
|
||||||
|
@ -16,13 +17,14 @@ use mtcs::{
|
||||||
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
|
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
|
||||||
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
|
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
|
||||||
};
|
};
|
||||||
|
use quartz_cw::msg::execute::attested::RawAttested;
|
||||||
|
use quartz_enclave::attestor::Attestor;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tonic::{Request, Response, Result as TonicResult, Status};
|
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||||
|
|
||||||
use crate::{
|
use crate::proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse};
|
||||||
attestor::Attestor,
|
|
||||||
proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse},
|
pub type RawCipherText = HexBinary;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MtcsService<A> {
|
pub struct MtcsService<A> {
|
||||||
|
@ -60,6 +62,23 @@ where
|
||||||
&self,
|
&self,
|
||||||
request: Request<RunClearingRequest>,
|
request: Request<RunClearingRequest>,
|
||||||
) -> TonicResult<Response<RunClearingResponse>> {
|
) -> TonicResult<Response<RunClearingResponse>> {
|
||||||
|
// Pass in JSON of Requests vector and the STATE
|
||||||
|
|
||||||
|
// Serialize into Requests enum
|
||||||
|
// Loop through, decrypt the ciphertexts
|
||||||
|
|
||||||
|
// Read the state blob from chain
|
||||||
|
|
||||||
|
// Decrypt and deserialize
|
||||||
|
|
||||||
|
// Loop through requests and apply onto state
|
||||||
|
|
||||||
|
// Encrypt state
|
||||||
|
|
||||||
|
// Create withdraw requests
|
||||||
|
|
||||||
|
// Send to chain
|
||||||
|
|
||||||
let message: RunClearingMessage = {
|
let message: RunClearingMessage = {
|
||||||
let message = request.into_inner().message;
|
let message = request.into_inner().message;
|
||||||
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
||||||
|
@ -93,12 +112,12 @@ where
|
||||||
|
|
||||||
let msg = SubmitSetoffsMsg { setoffs_enc };
|
let msg = SubmitSetoffsMsg { setoffs_enc };
|
||||||
|
|
||||||
let quote = self
|
let attestation = self
|
||||||
.attestor
|
.attestor
|
||||||
.quote(msg.clone())
|
.quote(msg.clone())
|
||||||
.map_err(|e| Status::internal(e.to_string()))?;
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
|
||||||
let attested_msg = AttestedMsg { msg, quote };
|
let attested_msg = RawAttested { msg, attestation };
|
||||||
let message = serde_json::to_string(&attested_msg).unwrap();
|
let message = serde_json::to_string(&attested_msg).unwrap();
|
||||||
Ok(Response::new(RunClearingResponse { message }))
|
Ok(Response::new(RunClearingResponse { message }))
|
||||||
}
|
}
|
5
apps/transfers/contracts/.cargo/config
Normal file
5
apps/transfers/contracts/.cargo/config
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[alias]
|
||||||
|
wasm = "build --target wasm32-unknown-unknown --release --lib"
|
||||||
|
wasm-debug = "build --target wasm32-unknown-unknown --lib"
|
||||||
|
schema = "run schema"
|
||||||
|
|
1102
apps/transfers/contracts/Cargo.lock
generated
Normal file
1102
apps/transfers/contracts/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
45
apps/transfers/contracts/Cargo.toml
Normal file
45
apps/transfers/contracts/Cargo.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[package]
|
||||||
|
name = "transfers_contracts"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
exclude = ["contract.wasm", "hash.txt"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "schema"
|
||||||
|
path = "bin/schema.rs"
|
||||||
|
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
debug = false
|
||||||
|
rpath = false
|
||||||
|
lto = true
|
||||||
|
debug-assertions = false
|
||||||
|
codegen-units = 1
|
||||||
|
panic = 'abort'
|
||||||
|
incremental = false
|
||||||
|
overflow-checks = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
backtraces = ["cosmwasm-std/backtraces"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# external
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
serde_json = "1.0.117"
|
||||||
|
thiserror = { version = "1.0.49" }
|
||||||
|
|
||||||
|
# cosmwasm
|
||||||
|
cosmwasm-schema = "1.5.0"
|
||||||
|
cosmwasm-std = { version = "1.5.0", features = ["cosmwasm_1_3"] }
|
||||||
|
cw-storage-plus = "1.1.0"
|
||||||
|
cw-utils = "1.0.3"
|
||||||
|
cw2 = "1.1.1"
|
||||||
|
cw20-base = { version = "1.1.1", features = ["library"] }
|
||||||
|
|
||||||
|
# quartz
|
||||||
|
quartz-cw = { path = "../../../cosmwasm/packages/quartz-cw" }
|
9
apps/transfers/contracts/bin/schema.rs
Normal file
9
apps/transfers/contracts/bin/schema.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use cosmwasm_schema::write_api;
|
||||||
|
use transfers_contracts::msg::{ExecuteMsg, InstantiateMsg};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
write_api! {
|
||||||
|
instantiate: InstantiateMsg,
|
||||||
|
execute: ExecuteMsg,
|
||||||
|
}
|
||||||
|
}
|
321
apps/transfers/contracts/schema/raw/execute.json
Normal file
321
apps/transfers/contracts/schema/raw/execute.json
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExecuteMsg",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"deposit",
|
||||||
|
"withdraw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"quartz"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"quartz": {
|
||||||
|
"$ref": "#/definitions/RawExecute_for_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"transfer_request"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"transfer_request": {
|
||||||
|
"$ref": "#/definitions/TransferRequestMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"clear_text_transfer_request"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"clear_text_transfer_request": {
|
||||||
|
"$ref": "#/definitions/ClearTextTransferRequestMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"update"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"update": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawUpdateMsg_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"Binary": {
|
||||||
|
"description": "Binary is a wrapper around Vec<u8> 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<u8>. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ClearTextTransferRequestMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"amount",
|
||||||
|
"receiver",
|
||||||
|
"sender"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"$ref": "#/definitions/Uint128"
|
||||||
|
},
|
||||||
|
"receiver": {
|
||||||
|
"$ref": "#/definitions/Addr"
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"$ref": "#/definitions/Addr"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"HexBinary": {
|
||||||
|
"description": "This is a wrapper around Vec<u8> to add hex de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is similar to `cosmwasm_std::Binary` but uses hex. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"IASReport": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report",
|
||||||
|
"reportsig"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/ReportBody"
|
||||||
|
},
|
||||||
|
"reportsig": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawSessionCreate_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawSessionCreate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawSessionSetPubKey_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawSessionSetPubKey"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawUpdateMsg_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawUpdateMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/IASReport"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawExecute_for_RawEpidAttestation": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"session_create"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"session_create": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawSessionCreate_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"session_set_pub_key"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"session_set_pub_key": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawSessionSetPubKey_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"RawSessionCreate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nonce"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nonce": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawSessionSetPubKey": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nonce",
|
||||||
|
"pub_key"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nonce": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"pub_key": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawUpdateMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ciphertext",
|
||||||
|
"quantity",
|
||||||
|
"withdrawals"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"ciphertext": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"withdrawals": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/Uint128"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ReportBody": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"advisoryIDs",
|
||||||
|
"advisoryURL",
|
||||||
|
"epidPseudonym",
|
||||||
|
"id",
|
||||||
|
"isvEnclaveQuoteBody",
|
||||||
|
"isvEnclaveQuoteStatus",
|
||||||
|
"platformInfoBlob",
|
||||||
|
"timestamp",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"advisoryIDs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advisoryURL": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"epidPseudonym": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteBody": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"platformInfoBlob": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"TransferRequestMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ciphertext",
|
||||||
|
"digest"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"ciphertext": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"digest": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
233
apps/transfers/contracts/schema/raw/instantiate.json
Normal file
233
apps/transfers/contracts/schema/raw/instantiate.json
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "InstantiateMsg",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"denom",
|
||||||
|
"quartz"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"denom": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"quartz": {
|
||||||
|
"$ref": "#/definitions/RawInstantiate_for_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"definitions": {
|
||||||
|
"Binary": {
|
||||||
|
"description": "Binary is a wrapper around Vec<u8> 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<u8>. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nanos",
|
||||||
|
"secs"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nanos": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"secs": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HexBinary": {
|
||||||
|
"description": "This is a wrapper around Vec<u8> to add hex de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is similar to `cosmwasm_std::Binary` but uses hex. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"IASReport": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report",
|
||||||
|
"reportsig"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/ReportBody"
|
||||||
|
},
|
||||||
|
"reportsig": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawCoreInstantiate_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawCoreInstantiate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"epoch_duration",
|
||||||
|
"light_client_opts",
|
||||||
|
"mr_enclave"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"epoch_duration": {
|
||||||
|
"$ref": "#/definitions/Duration"
|
||||||
|
},
|
||||||
|
"light_client_opts": {
|
||||||
|
"$ref": "#/definitions/RawLightClientOpts"
|
||||||
|
},
|
||||||
|
"mr_enclave": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawCoreInstantiate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"config"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"$ref": "#/definitions/RawConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/IASReport"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawInstantiate_for_RawEpidAttestation": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawCoreInstantiate_and_RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"RawLightClientOpts": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"chain_id",
|
||||||
|
"max_block_lag",
|
||||||
|
"max_clock_drift",
|
||||||
|
"trust_threshold",
|
||||||
|
"trusted_hash",
|
||||||
|
"trusted_height",
|
||||||
|
"trusting_period"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"chain_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"max_block_lag": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"max_clock_drift": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"trust_threshold": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"maxItems": 2,
|
||||||
|
"minItems": 2
|
||||||
|
},
|
||||||
|
"trusted_hash": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"trusted_height": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"trusting_period": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ReportBody": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"advisoryIDs",
|
||||||
|
"advisoryURL",
|
||||||
|
"epidPseudonym",
|
||||||
|
"id",
|
||||||
|
"isvEnclaveQuoteBody",
|
||||||
|
"isvEnclaveQuoteStatus",
|
||||||
|
"platformInfoBlob",
|
||||||
|
"timestamp",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"advisoryIDs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advisoryURL": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"epidPseudonym": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteBody": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"platformInfoBlob": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
563
apps/transfers/contracts/schema/transfers.json
Normal file
563
apps/transfers/contracts/schema/transfers.json
Normal file
|
@ -0,0 +1,563 @@
|
||||||
|
{
|
||||||
|
"contract_name": "transfers",
|
||||||
|
"contract_version": "0.1.0",
|
||||||
|
"idl_version": "1.0.0",
|
||||||
|
"instantiate": {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "InstantiateMsg",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"denom",
|
||||||
|
"quartz"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"denom": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"quartz": {
|
||||||
|
"$ref": "#/definitions/RawInstantiate_for_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"definitions": {
|
||||||
|
"Binary": {
|
||||||
|
"description": "Binary is a wrapper around Vec<u8> 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<u8>. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nanos",
|
||||||
|
"secs"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nanos": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"secs": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HexBinary": {
|
||||||
|
"description": "This is a wrapper around Vec<u8> to add hex de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is similar to `cosmwasm_std::Binary` but uses hex. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"IASReport": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report",
|
||||||
|
"reportsig"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/ReportBody"
|
||||||
|
},
|
||||||
|
"reportsig": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawCoreInstantiate_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawCoreInstantiate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"epoch_duration",
|
||||||
|
"light_client_opts",
|
||||||
|
"mr_enclave"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"epoch_duration": {
|
||||||
|
"$ref": "#/definitions/Duration"
|
||||||
|
},
|
||||||
|
"light_client_opts": {
|
||||||
|
"$ref": "#/definitions/RawLightClientOpts"
|
||||||
|
},
|
||||||
|
"mr_enclave": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawCoreInstantiate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"config"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"$ref": "#/definitions/RawConfig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/IASReport"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawInstantiate_for_RawEpidAttestation": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawCoreInstantiate_and_RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"RawLightClientOpts": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"chain_id",
|
||||||
|
"max_block_lag",
|
||||||
|
"max_clock_drift",
|
||||||
|
"trust_threshold",
|
||||||
|
"trusted_hash",
|
||||||
|
"trusted_height",
|
||||||
|
"trusting_period"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"chain_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"max_block_lag": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"max_clock_drift": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"trust_threshold": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"maxItems": 2,
|
||||||
|
"minItems": 2
|
||||||
|
},
|
||||||
|
"trusted_hash": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"trusted_height": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"trusting_period": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ReportBody": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"advisoryIDs",
|
||||||
|
"advisoryURL",
|
||||||
|
"epidPseudonym",
|
||||||
|
"id",
|
||||||
|
"isvEnclaveQuoteBody",
|
||||||
|
"isvEnclaveQuoteStatus",
|
||||||
|
"platformInfoBlob",
|
||||||
|
"timestamp",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"advisoryIDs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advisoryURL": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"epidPseudonym": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteBody": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"platformInfoBlob": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"execute": {
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExecuteMsg",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"deposit",
|
||||||
|
"withdraw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"quartz"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"quartz": {
|
||||||
|
"$ref": "#/definitions/RawExecute_for_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"transfer_request"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"transfer_request": {
|
||||||
|
"$ref": "#/definitions/TransferRequestMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"clear_text_transfer_request"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"clear_text_transfer_request": {
|
||||||
|
"$ref": "#/definitions/ClearTextTransferRequestMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"update"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"update": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawUpdateMsg_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"Binary": {
|
||||||
|
"description": "Binary is a wrapper around Vec<u8> 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<u8>. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ClearTextTransferRequestMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"amount",
|
||||||
|
"receiver",
|
||||||
|
"sender"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"$ref": "#/definitions/Uint128"
|
||||||
|
},
|
||||||
|
"receiver": {
|
||||||
|
"$ref": "#/definitions/Addr"
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"$ref": "#/definitions/Addr"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"HexBinary": {
|
||||||
|
"description": "This is a wrapper around Vec<u8> to add hex de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is similar to `cosmwasm_std::Binary` but uses hex. See also <https://github.com/CosmWasm/cosmwasm/blob/main/docs/MESSAGE_TYPES.md>.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"IASReport": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report",
|
||||||
|
"reportsig"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/ReportBody"
|
||||||
|
},
|
||||||
|
"reportsig": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawSessionCreate_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawSessionCreate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawSessionSetPubKey_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawSessionSetPubKey"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawAttested_for_RawUpdateMsg_and_RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"attestation",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"attestation": {
|
||||||
|
"$ref": "#/definitions/RawEpidAttestation"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"$ref": "#/definitions/RawUpdateMsg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawEpidAttestation": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"report"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"report": {
|
||||||
|
"$ref": "#/definitions/IASReport"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawExecute_for_RawEpidAttestation": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"session_create"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"session_create": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawSessionCreate_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"session_set_pub_key"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"session_set_pub_key": {
|
||||||
|
"$ref": "#/definitions/RawAttested_for_RawSessionSetPubKey_and_RawEpidAttestation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"RawSessionCreate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nonce"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nonce": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawSessionSetPubKey": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"nonce",
|
||||||
|
"pub_key"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"nonce": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"pub_key": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"RawUpdateMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ciphertext",
|
||||||
|
"quantity",
|
||||||
|
"withdrawals"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"ciphertext": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"withdrawals": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/Uint128"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ReportBody": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"advisoryIDs",
|
||||||
|
"advisoryURL",
|
||||||
|
"epidPseudonym",
|
||||||
|
"id",
|
||||||
|
"isvEnclaveQuoteBody",
|
||||||
|
"isvEnclaveQuoteStatus",
|
||||||
|
"platformInfoBlob",
|
||||||
|
"timestamp",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"advisoryIDs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advisoryURL": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"epidPseudonym": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteBody": {
|
||||||
|
"$ref": "#/definitions/Binary"
|
||||||
|
},
|
||||||
|
"isvEnclaveQuoteStatus": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"platformInfoBlob": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"TransferRequestMsg": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ciphertext",
|
||||||
|
"digest"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"ciphertext": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
},
|
||||||
|
"digest": {
|
||||||
|
"$ref": "#/definitions/HexBinary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": null,
|
||||||
|
"migrate": null,
|
||||||
|
"sudo": null,
|
||||||
|
"responses": null
|
||||||
|
}
|
148
apps/transfers/contracts/src/contract.rs
Normal file
148
apps/transfers/contracts/src/contract.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
use cosmwasm_std::{entry_point, DepsMut, Env, HexBinary, MessageInfo, Response};
|
||||||
|
use quartz_cw::handler::RawHandler;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::ContractError,
|
||||||
|
msg::{
|
||||||
|
execute::{Request, UpdateMsg},
|
||||||
|
ExecuteMsg, InstantiateMsg,
|
||||||
|
},
|
||||||
|
state::{DENOM, REQUESTS, STATE},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||||
|
pub fn instantiate(
|
||||||
|
mut deps: DepsMut,
|
||||||
|
env: Env,
|
||||||
|
info: MessageInfo,
|
||||||
|
msg: InstantiateMsg,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
// must be handled first!
|
||||||
|
msg.quartz.handle_raw(deps.branch(), &env, &info)?;
|
||||||
|
|
||||||
|
DENOM.save(deps.storage, &msg.denom)?;
|
||||||
|
|
||||||
|
let requests: Vec<Request> = Vec::new();
|
||||||
|
REQUESTS.save(deps.storage, &requests)?;
|
||||||
|
|
||||||
|
let state: HexBinary = HexBinary::from(&[0x00]);
|
||||||
|
STATE.save(deps.storage, &state)?;
|
||||||
|
|
||||||
|
Ok(Response::new()
|
||||||
|
.add_attribute("method", "instantiate")
|
||||||
|
.add_attribute("owner", info.sender))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||||
|
pub fn execute(
|
||||||
|
mut deps: DepsMut,
|
||||||
|
env: Env,
|
||||||
|
info: MessageInfo,
|
||||||
|
msg: ExecuteMsg,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
use execute::*;
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into),
|
||||||
|
ExecuteMsg::TransferRequest(msg) => transfer_request(deps, env, info, msg),
|
||||||
|
ExecuteMsg::Update(attested_msg) => {
|
||||||
|
let _ = attested_msg
|
||||||
|
.clone()
|
||||||
|
.handle_raw(deps.branch(), &env, &info)?;
|
||||||
|
|
||||||
|
// Extract underlying UpdateMsg and pass to update()
|
||||||
|
update(deps, env, info, UpdateMsg(attested_msg.msg))
|
||||||
|
}
|
||||||
|
ExecuteMsg::Deposit => deposit(deps, env, info),
|
||||||
|
ExecuteMsg::Withdraw => withdraw(deps, env, info),
|
||||||
|
ExecuteMsg::ClearTextTransferRequest(_) => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod execute {
|
||||||
|
use cosmwasm_std::{coins, BankMsg, DepsMut, Env, MessageInfo, Response};
|
||||||
|
use cw_utils::must_pay;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::ContractError,
|
||||||
|
msg::execute::{Request, TransferRequestMsg, UpdateMsg},
|
||||||
|
state::{DENOM, REQUESTS, STATE},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn transfer_request(
|
||||||
|
deps: DepsMut,
|
||||||
|
_env: Env,
|
||||||
|
_info: MessageInfo,
|
||||||
|
msg: TransferRequestMsg,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
let mut requests = REQUESTS.load(deps.storage)?;
|
||||||
|
|
||||||
|
requests.push(Request::Transfer(msg.ciphertext));
|
||||||
|
|
||||||
|
REQUESTS.save(deps.storage, &requests)?;
|
||||||
|
|
||||||
|
Ok(Response::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
deps: DepsMut,
|
||||||
|
_env: Env,
|
||||||
|
_info: MessageInfo,
|
||||||
|
msg: UpdateMsg,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
// Store state
|
||||||
|
STATE.save(deps.storage, &msg.0.ciphertext)?;
|
||||||
|
|
||||||
|
// Clear queue
|
||||||
|
let mut requests: Vec<Request> = REQUESTS.load(deps.storage)?;
|
||||||
|
|
||||||
|
requests.drain(0..msg.0.quantity as usize);
|
||||||
|
|
||||||
|
REQUESTS.save(deps.storage, &requests)?;
|
||||||
|
|
||||||
|
// Process withdrawals
|
||||||
|
let denom = DENOM.load(deps.storage)?;
|
||||||
|
|
||||||
|
let messages = msg
|
||||||
|
.0
|
||||||
|
.withdrawals
|
||||||
|
.into_iter()
|
||||||
|
.map(|(user, funds)| BankMsg::Send {
|
||||||
|
to_address: user.to_string(),
|
||||||
|
amount: coins(funds.into(), &denom),
|
||||||
|
});
|
||||||
|
|
||||||
|
let resp = Response::new().add_messages(messages);
|
||||||
|
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deposit(deps: DepsMut, _env: Env, info: MessageInfo) -> Result<Response, ContractError> {
|
||||||
|
let denom = DENOM.load(deps.storage)?;
|
||||||
|
let quantity = must_pay(&info, &denom)?;
|
||||||
|
|
||||||
|
let mut requests = REQUESTS.load(deps.storage)?;
|
||||||
|
|
||||||
|
requests.push(Request::Deposit(info.sender, quantity));
|
||||||
|
|
||||||
|
REQUESTS.save(deps.storage, &requests)?;
|
||||||
|
|
||||||
|
Ok(Response::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn withdraw(
|
||||||
|
deps: DepsMut,
|
||||||
|
_env: Env,
|
||||||
|
info: MessageInfo,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
// TODO: verify denom
|
||||||
|
|
||||||
|
let mut requests = REQUESTS.load(deps.storage)?;
|
||||||
|
|
||||||
|
requests.push(Request::Withdraw(info.sender));
|
||||||
|
|
||||||
|
REQUESTS.save(deps.storage, &requests)?;
|
||||||
|
|
||||||
|
Ok(Response::new())
|
||||||
|
}
|
||||||
|
}
|
41
apps/transfers/contracts/src/error.rs
Normal file
41
apps/transfers/contracts/src/error.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use cosmwasm_std::StdError;
|
||||||
|
use cw20_base::ContractError as Cw20ContractError;
|
||||||
|
use cw_utils::PaymentError;
|
||||||
|
use quartz_cw::error::Error as QuartzError;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ContractError {
|
||||||
|
#[error("{0}")]
|
||||||
|
Std(#[from] StdError),
|
||||||
|
|
||||||
|
#[error("{0}")]
|
||||||
|
Quartz(#[from] QuartzError),
|
||||||
|
|
||||||
|
#[error("Unauthorized")]
|
||||||
|
Unauthorized,
|
||||||
|
|
||||||
|
#[error("Duplicate entry found")]
|
||||||
|
DuplicateEntry,
|
||||||
|
|
||||||
|
#[error("Invalid length")]
|
||||||
|
BadLength,
|
||||||
|
|
||||||
|
#[error("Cw20 error: {0}")]
|
||||||
|
Cw20(Cw20ContractError),
|
||||||
|
|
||||||
|
#[error("Payment error: {0}")]
|
||||||
|
CwUtil(PaymentError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Cw20ContractError> for ContractError {
|
||||||
|
fn from(e: Cw20ContractError) -> Self {
|
||||||
|
Self::Cw20(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PaymentError> for ContractError {
|
||||||
|
fn from(e: PaymentError) -> Self {
|
||||||
|
Self::CwUtil(e)
|
||||||
|
}
|
||||||
|
}
|
6
apps/transfers/contracts/src/lib.rs
Normal file
6
apps/transfers/contracts/src/lib.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
extern crate cosmwasm_std;
|
||||||
|
|
||||||
|
pub mod contract;
|
||||||
|
pub mod error;
|
||||||
|
pub mod msg;
|
||||||
|
pub mod state;
|
121
apps/transfers/contracts/src/msg.rs
Normal file
121
apps/transfers/contracts/src/msg.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||||
|
use quartz_cw::{
|
||||||
|
msg::execute::attested::{RawAttested, RawEpidAttestation},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct InstantiateMsg {
|
||||||
|
pub quartz: QuartzInstantiateMsg,
|
||||||
|
pub denom: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
pub enum ExecuteMsg {
|
||||||
|
// quartz initialization
|
||||||
|
Quartz(QuartzExecuteMsg),
|
||||||
|
|
||||||
|
// ----- user txs
|
||||||
|
// clear text
|
||||||
|
Deposit,
|
||||||
|
Withdraw,
|
||||||
|
|
||||||
|
// ciphertext
|
||||||
|
TransferRequest(execute::TransferRequestMsg),
|
||||||
|
// ---- end user txs
|
||||||
|
ClearTextTransferRequest(execute::ClearTextTransferRequestMsg),
|
||||||
|
|
||||||
|
// enclave msg
|
||||||
|
Update(RawAttested<execute::RawUpdateMsg, RawEpidAttestation>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod execute {
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, StdError};
|
||||||
|
use quartz_cw::{
|
||||||
|
error::Error,
|
||||||
|
handler::Handler,
|
||||||
|
msg::{execute::attested::HasUserData, HasDomainType},
|
||||||
|
state::UserData,
|
||||||
|
};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct TransferRequestMsg {
|
||||||
|
pub ciphertext: HexBinary,
|
||||||
|
pub digest: HexBinary,
|
||||||
|
// pub proof: π
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct ClearTextTransferRequestMsg {
|
||||||
|
pub sender: Addr,
|
||||||
|
pub receiver: Addr,
|
||||||
|
pub amount: Uint128,
|
||||||
|
// pub proof: π
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ciphertext of a transfer request
|
||||||
|
#[cw_serde]
|
||||||
|
pub enum Request {
|
||||||
|
Transfer(HexBinary),
|
||||||
|
Withdraw(Addr),
|
||||||
|
Deposit(Addr, Uint128),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawUpdateMsg {
|
||||||
|
pub ciphertext: HexBinary,
|
||||||
|
pub quantity: u32,
|
||||||
|
pub withdrawals: Vec<(Addr, Uint128)>,
|
||||||
|
// pub proof: π
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct UpdateMsg(pub RawUpdateMsg);
|
||||||
|
|
||||||
|
impl HasUserData for UpdateMsg {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(serde_json::to_string(&self.0).expect("infallible serializer"));
|
||||||
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
|
|
||||||
|
let mut user_data = [0u8; 64];
|
||||||
|
user_data[0..32].copy_from_slice(&digest);
|
||||||
|
user_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawUpdateMsg {
|
||||||
|
type DomainType = UpdateMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawUpdateMsg> for UpdateMsg {
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawUpdateMsg) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UpdateMsg> for RawUpdateMsg {
|
||||||
|
fn from(value: UpdateMsg) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler for UpdateMsg {
|
||||||
|
fn handle(
|
||||||
|
self,
|
||||||
|
_deps: DepsMut<'_>,
|
||||||
|
_env: &Env,
|
||||||
|
_info: &MessageInfo,
|
||||||
|
) -> Result<Response, Error> {
|
||||||
|
// basically handle `transfer_request` here
|
||||||
|
Ok(Response::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
apps/transfers/contracts/src/state.rs
Normal file
9
apps/transfers/contracts/src/state.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use cosmwasm_std::HexBinary;
|
||||||
|
use cw_storage_plus::Item;
|
||||||
|
|
||||||
|
use crate::msg::execute::Request;
|
||||||
|
|
||||||
|
pub const STATE: Item<HexBinary> = Item::new("state");
|
||||||
|
pub const REQUESTS: Item<Vec<Request>> = Item::new("requests");
|
||||||
|
|
||||||
|
pub const DENOM: Item<String> = Item::new("donation_denom");
|
4323
apps/transfers/enclave/Cargo.lock
generated
Normal file
4323
apps/transfers/enclave/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
56
apps/transfers/enclave/Cargo.toml
Normal file
56
apps/transfers/enclave/Cargo.toml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
[package]
|
||||||
|
name = "enclave"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
debug = false
|
||||||
|
rpath = false
|
||||||
|
lto = true
|
||||||
|
debug-assertions = false
|
||||||
|
codegen-units = 1
|
||||||
|
panic = 'abort'
|
||||||
|
incremental = false
|
||||||
|
overflow-checks = true
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "encrypt"
|
||||||
|
path = "bin/encrypt.rs"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# external
|
||||||
|
hex = { version = "0.4.3", default-features = false }
|
||||||
|
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] }
|
||||||
|
schemars = "0.8.15"
|
||||||
|
serde = { version = "1.0.189", default-features = false, features = ["derive"] }
|
||||||
|
thiserror = { version = "1.0.49" }
|
||||||
|
tonic = { version = "0.11.0"}
|
||||||
|
cosmrs = { version = "0.16.0"}
|
||||||
|
cosmwasm-std = { version = "1.5.2", default-features = false }
|
||||||
|
serde_json = { version = "1.0.94", default-features = false }
|
||||||
|
ecies = { version = "0.2.3", default-features = false, features = ["pure"] }
|
||||||
|
clap = { version = "4.1.8", default-features = false, features = ["derive", "std"] }
|
||||||
|
tokio = { version = "1.0", default-features = false, features = ["macros", "rt-multi-thread"] }
|
||||||
|
tendermint = { version = "=0.36.0", default-features = false }
|
||||||
|
tendermint-light-client = { version = "=0.36.0", default-features = false, features = ["rust-crypto"] }
|
||||||
|
color-eyre = { version = "0.6.2", default-features = false }
|
||||||
|
prost = { version = "0.12.3", default-features = false }
|
||||||
|
anyhow ={ version = "*" }
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
|
||||||
|
# local
|
||||||
|
transfers_contracts = { path = "../contracts" }
|
||||||
|
|
||||||
|
# quartz
|
||||||
|
quartz-cw = { path = "../../../cosmwasm/packages/quartz-cw" }
|
||||||
|
quartz-proto = { path = "../../../core/quartz-proto" }
|
||||||
|
quartz-enclave = { path = "../../../core/quartz"}
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
cw-multi-test = "0.17.0"
|
||||||
|
serde_json = "1.0.113"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tonic-build = "0.11.0"
|
1
apps/transfers/enclave/README.md
Normal file
1
apps/transfers/enclave/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
## MTCS Server
|
62
apps/transfers/enclave/bin/encrypt.rs
Normal file
62
apps/transfers/enclave/bin/encrypt.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
|
use anyhow;
|
||||||
|
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||||
|
use ecies::{decrypt, encrypt};
|
||||||
|
use k256::{
|
||||||
|
ecdsa::{SigningKey, VerifyingKey},
|
||||||
|
pkcs8::DecodePublicKey,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use transfers_contracts::msg::execute::ClearTextTransferRequestMsg;
|
||||||
|
|
||||||
|
pub type RawCipherText = HexBinary;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct State {
|
||||||
|
pub state: BTreeMap<Addr, Uint128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct RawState {
|
||||||
|
pub state: BTreeMap<Addr, Uint128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RawEncryptedState {
|
||||||
|
pub ciphertext: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<State> for RawState {
|
||||||
|
fn from(o: State) -> Self {
|
||||||
|
Self { state: o.state }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawState> for State {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(o: RawState) -> Result<Self, anyhow::Error> {
|
||||||
|
Ok(Self { state: o.state })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let msg = ClearTextTransferRequestMsg {
|
||||||
|
sender: Addr::unchecked("alice"),
|
||||||
|
receiver: Addr::unchecked("bob"),
|
||||||
|
amount: Uint128::from(100 as u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
let decoded: Vec<u8> =
|
||||||
|
hex::decode("03e8d63b96a3b3fa442f0a8f39a580f5e898dab7b86eaa685466e82d79022eedff")
|
||||||
|
.expect("Decoding failed");
|
||||||
|
let sk = VerifyingKey::from_sec1_bytes(&decoded).unwrap();
|
||||||
|
|
||||||
|
let serialized_state = serde_json::to_string(&msg).expect("infallible serializer");
|
||||||
|
let encrypted_state = encrypt(&sk.to_sec1_bytes(), serialized_state.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let result: HexBinary = encrypted_state.into();
|
||||||
|
|
||||||
|
println!("{}", result);
|
||||||
|
}
|
6
apps/transfers/enclave/build.rs
Normal file
6
apps/transfers/enclave/build.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
tonic_build::configure()
|
||||||
|
.out_dir("src/prost")
|
||||||
|
.compile(&["proto/transfers.proto"], &["proto"])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
15
apps/transfers/enclave/proto/transfers.proto
Normal file
15
apps/transfers/enclave/proto/transfers.proto
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package transfers;
|
||||||
|
|
||||||
|
service Settlement {
|
||||||
|
rpc Run (RunTransfersRequest) returns (RunTransfersResponse) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message RunTransfersRequest {
|
||||||
|
string message = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RunTransfersResponse {
|
||||||
|
string message = 1;
|
||||||
|
}
|
52
apps/transfers/enclave/src/cli.rs
Normal file
52
apps/transfers/enclave/src/cli.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use color_eyre::eyre::{eyre, Result};
|
||||||
|
use cosmrs::tendermint::Hash;
|
||||||
|
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||||
|
|
||||||
|
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
||||||
|
if let Some((l, r)) = s.split_once('/') {
|
||||||
|
TrustThreshold::new(l.parse()?, r.parse()?).map_err(Into::into)
|
||||||
|
} else {
|
||||||
|
Err(eyre!(
|
||||||
|
"invalid trust threshold: {s}, format must be X/Y where X and Y are integers"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(author, version, about, long_about = None)]
|
||||||
|
pub struct Cli {
|
||||||
|
/// RPC server address
|
||||||
|
#[clap(long, default_value = "127.0.0.1:11090")]
|
||||||
|
pub rpc_addr: SocketAddr,
|
||||||
|
|
||||||
|
/// Identifier of the chain
|
||||||
|
#[clap(long)]
|
||||||
|
pub chain_id: String,
|
||||||
|
|
||||||
|
/// Height of the trusted header (AKA root-of-trust)
|
||||||
|
#[clap(long)]
|
||||||
|
pub trusted_height: Height,
|
||||||
|
|
||||||
|
/// Hash of the trusted header (AKA root-of-trust)
|
||||||
|
#[clap(long)]
|
||||||
|
pub trusted_hash: Hash,
|
||||||
|
|
||||||
|
/// Trust threshold
|
||||||
|
#[clap(long, value_parser = parse_trust_threshold, default_value_t = TrustThreshold::TWO_THIRDS)]
|
||||||
|
pub trust_threshold: TrustThreshold,
|
||||||
|
|
||||||
|
/// Trusting period, in seconds (default: two weeks)
|
||||||
|
#[clap(long, default_value = "1209600")]
|
||||||
|
pub trusting_period: u64,
|
||||||
|
|
||||||
|
/// Maximum clock drift, in seconds
|
||||||
|
#[clap(long, default_value = "5")]
|
||||||
|
pub max_clock_drift: u64,
|
||||||
|
|
||||||
|
/// Maximum block lag, in seconds
|
||||||
|
#[clap(long, default_value = "5")]
|
||||||
|
pub max_block_lag: u64,
|
||||||
|
}
|
79
apps/transfers/enclave/src/main.rs
Normal file
79
apps/transfers/enclave/src/main.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![warn(
|
||||||
|
clippy::checked_conversions,
|
||||||
|
clippy::panic,
|
||||||
|
clippy::panic_in_result_fn,
|
||||||
|
missing_docs,
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
rust_2018_idioms,
|
||||||
|
unused_lifetimes,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications
|
||||||
|
)]
|
||||||
|
|
||||||
|
pub mod cli;
|
||||||
|
pub mod proto;
|
||||||
|
pub mod state;
|
||||||
|
pub mod transfers_server;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use cli::Cli;
|
||||||
|
use proto::settlement_server::SettlementServer as TransfersServer;
|
||||||
|
use quartz_cw::state::{Config, LightClientOpts};
|
||||||
|
use quartz_enclave::{
|
||||||
|
attestor::{Attestor, EpidAttestor},
|
||||||
|
server::CoreService,
|
||||||
|
};
|
||||||
|
use quartz_proto::quartz::core_server::CoreServer;
|
||||||
|
use tonic::transport::Server;
|
||||||
|
use transfers_server::TransfersService;
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let args = Cli::parse();
|
||||||
|
|
||||||
|
let light_client_opts = LightClientOpts::new(
|
||||||
|
args.chain_id,
|
||||||
|
args.trusted_height.into(),
|
||||||
|
Vec::from(args.trusted_hash)
|
||||||
|
.try_into()
|
||||||
|
.expect("invalid trusted hash"),
|
||||||
|
(
|
||||||
|
args.trust_threshold.numerator(),
|
||||||
|
args.trust_threshold.denominator(),
|
||||||
|
),
|
||||||
|
args.trusting_period,
|
||||||
|
args.max_clock_drift,
|
||||||
|
args.max_block_lag,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let config = Config::new(
|
||||||
|
EpidAttestor.mr_enclave()?,
|
||||||
|
Duration::from_secs(30 * 24 * 60),
|
||||||
|
light_client_opts,
|
||||||
|
);
|
||||||
|
|
||||||
|
let sk = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
|
Server::builder()
|
||||||
|
.add_service(CoreServer::new(CoreService::new(
|
||||||
|
config,
|
||||||
|
sk.clone(),
|
||||||
|
EpidAttestor,
|
||||||
|
)))
|
||||||
|
.add_service(TransfersServer::new(TransfersService::<EpidAttestor>::new(
|
||||||
|
sk.clone(),
|
||||||
|
EpidAttestor,
|
||||||
|
)))
|
||||||
|
.serve(args.rpc_addr)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
303
apps/transfers/enclave/src/prost/transfers.rs
Normal file
303
apps/transfers/enclave/src/prost/transfers.rs
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
// This file is @generated by prost-build.
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct RunTransfersRequest {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub message: ::prost::alloc::string::String,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct RunTransfersResponse {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub message: ::prost::alloc::string::String,
|
||||||
|
}
|
||||||
|
/// Generated client implementations.
|
||||||
|
pub mod settlement_client {
|
||||||
|
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||||
|
use tonic::codegen::*;
|
||||||
|
use tonic::codegen::http::Uri;
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SettlementClient<T> {
|
||||||
|
inner: tonic::client::Grpc<T>,
|
||||||
|
}
|
||||||
|
impl SettlementClient<tonic::transport::Channel> {
|
||||||
|
/// Attempt to create a new client by connecting to a given endpoint.
|
||||||
|
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
|
||||||
|
where
|
||||||
|
D: TryInto<tonic::transport::Endpoint>,
|
||||||
|
D::Error: Into<StdError>,
|
||||||
|
{
|
||||||
|
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
|
||||||
|
Ok(Self::new(conn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> SettlementClient<T>
|
||||||
|
where
|
||||||
|
T: tonic::client::GrpcService<tonic::body::BoxBody>,
|
||||||
|
T::Error: Into<StdError>,
|
||||||
|
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
|
||||||
|
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
|
||||||
|
{
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
let inner = tonic::client::Grpc::new(inner);
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
pub fn with_origin(inner: T, origin: Uri) -> Self {
|
||||||
|
let inner = tonic::client::Grpc::with_origin(inner, origin);
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
pub fn with_interceptor<F>(
|
||||||
|
inner: T,
|
||||||
|
interceptor: F,
|
||||||
|
) -> SettlementClient<InterceptedService<T, F>>
|
||||||
|
where
|
||||||
|
F: tonic::service::Interceptor,
|
||||||
|
T::ResponseBody: Default,
|
||||||
|
T: tonic::codegen::Service<
|
||||||
|
http::Request<tonic::body::BoxBody>,
|
||||||
|
Response = http::Response<
|
||||||
|
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
<T as tonic::codegen::Service<
|
||||||
|
http::Request<tonic::body::BoxBody>,
|
||||||
|
>>::Error: Into<StdError> + Send + Sync,
|
||||||
|
{
|
||||||
|
SettlementClient::new(InterceptedService::new(inner, interceptor))
|
||||||
|
}
|
||||||
|
/// Compress requests with the given encoding.
|
||||||
|
///
|
||||||
|
/// This requires the server to support it otherwise it might respond with an
|
||||||
|
/// error.
|
||||||
|
#[must_use]
|
||||||
|
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||||
|
self.inner = self.inner.send_compressed(encoding);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Enable decompressing responses.
|
||||||
|
#[must_use]
|
||||||
|
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||||
|
self.inner = self.inner.accept_compressed(encoding);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Limits the maximum size of a decoded message.
|
||||||
|
///
|
||||||
|
/// Default: `4MB`
|
||||||
|
#[must_use]
|
||||||
|
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
|
||||||
|
self.inner = self.inner.max_decoding_message_size(limit);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Limits the maximum size of an encoded message.
|
||||||
|
///
|
||||||
|
/// Default: `usize::MAX`
|
||||||
|
#[must_use]
|
||||||
|
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
|
||||||
|
self.inner = self.inner.max_encoding_message_size(limit);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub async fn run(
|
||||||
|
&mut self,
|
||||||
|
request: impl tonic::IntoRequest<super::RunTransfersRequest>,
|
||||||
|
) -> std::result::Result<
|
||||||
|
tonic::Response<super::RunTransfersResponse>,
|
||||||
|
tonic::Status,
|
||||||
|
> {
|
||||||
|
self.inner
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tonic::Status::new(
|
||||||
|
tonic::Code::Unknown,
|
||||||
|
format!("Service was not ready: {}", e.into()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let codec = tonic::codec::ProstCodec::default();
|
||||||
|
let path = http::uri::PathAndQuery::from_static("/transfers.Settlement/Run");
|
||||||
|
let mut req = request.into_request();
|
||||||
|
req.extensions_mut().insert(GrpcMethod::new("transfers.Settlement", "Run"));
|
||||||
|
self.inner.unary(req, path, codec).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Generated server implementations.
|
||||||
|
pub mod settlement_server {
|
||||||
|
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||||
|
use tonic::codegen::*;
|
||||||
|
/// Generated trait containing gRPC methods that should be implemented for use with SettlementServer.
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Settlement: Send + Sync + 'static {
|
||||||
|
async fn run(
|
||||||
|
&self,
|
||||||
|
request: tonic::Request<super::RunTransfersRequest>,
|
||||||
|
) -> std::result::Result<
|
||||||
|
tonic::Response<super::RunTransfersResponse>,
|
||||||
|
tonic::Status,
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SettlementServer<T: Settlement> {
|
||||||
|
inner: _Inner<T>,
|
||||||
|
accept_compression_encodings: EnabledCompressionEncodings,
|
||||||
|
send_compression_encodings: EnabledCompressionEncodings,
|
||||||
|
max_decoding_message_size: Option<usize>,
|
||||||
|
max_encoding_message_size: Option<usize>,
|
||||||
|
}
|
||||||
|
struct _Inner<T>(Arc<T>);
|
||||||
|
impl<T: Settlement> SettlementServer<T> {
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
Self::from_arc(Arc::new(inner))
|
||||||
|
}
|
||||||
|
pub fn from_arc(inner: Arc<T>) -> Self {
|
||||||
|
let inner = _Inner(inner);
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
accept_compression_encodings: Default::default(),
|
||||||
|
send_compression_encodings: Default::default(),
|
||||||
|
max_decoding_message_size: None,
|
||||||
|
max_encoding_message_size: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn with_interceptor<F>(
|
||||||
|
inner: T,
|
||||||
|
interceptor: F,
|
||||||
|
) -> InterceptedService<Self, F>
|
||||||
|
where
|
||||||
|
F: tonic::service::Interceptor,
|
||||||
|
{
|
||||||
|
InterceptedService::new(Self::new(inner), interceptor)
|
||||||
|
}
|
||||||
|
/// Enable decompressing requests with the given encoding.
|
||||||
|
#[must_use]
|
||||||
|
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||||
|
self.accept_compression_encodings.enable(encoding);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Compress responses with the given encoding, if the client supports it.
|
||||||
|
#[must_use]
|
||||||
|
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||||
|
self.send_compression_encodings.enable(encoding);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Limits the maximum size of a decoded message.
|
||||||
|
///
|
||||||
|
/// Default: `4MB`
|
||||||
|
#[must_use]
|
||||||
|
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
|
||||||
|
self.max_decoding_message_size = Some(limit);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/// Limits the maximum size of an encoded message.
|
||||||
|
///
|
||||||
|
/// Default: `usize::MAX`
|
||||||
|
#[must_use]
|
||||||
|
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
|
||||||
|
self.max_encoding_message_size = Some(limit);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T, B> tonic::codegen::Service<http::Request<B>> for SettlementServer<T>
|
||||||
|
where
|
||||||
|
T: Settlement,
|
||||||
|
B: Body + Send + 'static,
|
||||||
|
B::Error: Into<StdError> + Send + 'static,
|
||||||
|
{
|
||||||
|
type Response = http::Response<tonic::body::BoxBody>;
|
||||||
|
type Error = std::convert::Infallible;
|
||||||
|
type Future = BoxFuture<Self::Response, Self::Error>;
|
||||||
|
fn poll_ready(
|
||||||
|
&mut self,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<std::result::Result<(), Self::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
fn call(&mut self, req: http::Request<B>) -> Self::Future {
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
match req.uri().path() {
|
||||||
|
"/transfers.Settlement/Run" => {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
struct RunSvc<T: Settlement>(pub Arc<T>);
|
||||||
|
impl<
|
||||||
|
T: Settlement,
|
||||||
|
> tonic::server::UnaryService<super::RunTransfersRequest>
|
||||||
|
for RunSvc<T> {
|
||||||
|
type Response = super::RunTransfersResponse;
|
||||||
|
type Future = BoxFuture<
|
||||||
|
tonic::Response<Self::Response>,
|
||||||
|
tonic::Status,
|
||||||
|
>;
|
||||||
|
fn call(
|
||||||
|
&mut self,
|
||||||
|
request: tonic::Request<super::RunTransfersRequest>,
|
||||||
|
) -> Self::Future {
|
||||||
|
let inner = Arc::clone(&self.0);
|
||||||
|
let fut = async move {
|
||||||
|
<T as Settlement>::run(&inner, request).await
|
||||||
|
};
|
||||||
|
Box::pin(fut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let accept_compression_encodings = self.accept_compression_encodings;
|
||||||
|
let send_compression_encodings = self.send_compression_encodings;
|
||||||
|
let max_decoding_message_size = self.max_decoding_message_size;
|
||||||
|
let max_encoding_message_size = self.max_encoding_message_size;
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
let fut = async move {
|
||||||
|
let inner = inner.0;
|
||||||
|
let method = RunSvc(inner);
|
||||||
|
let codec = tonic::codec::ProstCodec::default();
|
||||||
|
let mut grpc = tonic::server::Grpc::new(codec)
|
||||||
|
.apply_compression_config(
|
||||||
|
accept_compression_encodings,
|
||||||
|
send_compression_encodings,
|
||||||
|
)
|
||||||
|
.apply_max_message_size_config(
|
||||||
|
max_decoding_message_size,
|
||||||
|
max_encoding_message_size,
|
||||||
|
);
|
||||||
|
let res = grpc.unary(method, req).await;
|
||||||
|
Ok(res)
|
||||||
|
};
|
||||||
|
Box::pin(fut)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Box::pin(async move {
|
||||||
|
Ok(
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("grpc-status", "12")
|
||||||
|
.header("content-type", "application/grpc")
|
||||||
|
.body(empty_body())
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Settlement> Clone for SettlementServer<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let inner = self.inner.clone();
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
accept_compression_encodings: self.accept_compression_encodings,
|
||||||
|
send_compression_encodings: self.send_compression_encodings,
|
||||||
|
max_decoding_message_size: self.max_decoding_message_size,
|
||||||
|
max_encoding_message_size: self.max_encoding_message_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Settlement> Clone for _Inner<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(Arc::clone(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Settlement> tonic::server::NamedService for SettlementServer<T> {
|
||||||
|
const NAME: &'static str = "transfers.Settlement";
|
||||||
|
}
|
||||||
|
}
|
3
apps/transfers/enclave/src/proto.rs
Normal file
3
apps/transfers/enclave/src/proto.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#![allow(clippy::unwrap_used, unused_qualifications)]
|
||||||
|
|
||||||
|
include!(concat!("prost/", "transfers.rs"));
|
34
apps/transfers/enclave/src/state.rs
Normal file
34
apps/transfers/enclave/src/state.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
|
use anyhow;
|
||||||
|
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct State {
|
||||||
|
pub state: BTreeMap<Addr, Uint128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
pub struct RawState {
|
||||||
|
pub state: BTreeMap<Addr, Uint128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RawEncryptedState {
|
||||||
|
pub ciphertext: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<State> for RawState {
|
||||||
|
fn from(o: State) -> Self {
|
||||||
|
Self { state: o.state }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawState> for State {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(o: RawState) -> Result<Self, anyhow::Error> {
|
||||||
|
Ok(Self { state: o.state })
|
||||||
|
}
|
||||||
|
}
|
223
apps/transfers/enclave/src/transfers_server.rs
Normal file
223
apps/transfers/enclave/src/transfers_server.rs
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
use std::{
|
||||||
|
collections::{btree_map::Entry, BTreeMap},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||||
|
|
||||||
|
pub type RawCipherText = HexBinary;
|
||||||
|
|
||||||
|
use ecies::{decrypt, encrypt};
|
||||||
|
use k256::ecdsa::{SigningKey, VerifyingKey};
|
||||||
|
use quartz_cw::{
|
||||||
|
msg::execute::attested::{HasUserData, RawAttested},
|
||||||
|
state::UserData,
|
||||||
|
};
|
||||||
|
use quartz_enclave::attestor::Attestor;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||||
|
use transfers_contracts::msg::execute::{ClearTextTransferRequestMsg, Request as TransfersRequest};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
proto::{settlement_server::Settlement, RunTransfersRequest, RunTransfersResponse},
|
||||||
|
state::{RawState, State},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TransfersService<A> {
|
||||||
|
sk: Arc<Mutex<Option<SigningKey>>>,
|
||||||
|
attestor: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RunTransfersRequestMessage {
|
||||||
|
state: HexBinary,
|
||||||
|
requests: Vec<TransfersRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RunTransfersResponseMessage {
|
||||||
|
ciphertext: HexBinary,
|
||||||
|
quantity: u32,
|
||||||
|
withdrawals: Vec<(Addr, Uint128)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasUserData for RunTransfersResponseMessage {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(serde_json::to_string(&self).expect("infallible serializer"));
|
||||||
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
|
|
||||||
|
let mut user_data = [0u8; 64];
|
||||||
|
user_data[0..32].copy_from_slice(&digest);
|
||||||
|
user_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> TransfersService<A>
|
||||||
|
where
|
||||||
|
A: Attestor,
|
||||||
|
{
|
||||||
|
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
|
||||||
|
Self { sk, attestor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl<A> Settlement for TransfersService<A>
|
||||||
|
where
|
||||||
|
A: Attestor + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
async fn run(
|
||||||
|
&self,
|
||||||
|
request: Request<RunTransfersRequest>,
|
||||||
|
) -> TonicResult<Response<RunTransfersResponse>> {
|
||||||
|
// Request contains a serialized json string
|
||||||
|
|
||||||
|
// Serialize request into struct containing State and the Requests vec
|
||||||
|
let message: RunTransfersRequestMessage = {
|
||||||
|
let message = request.into_inner().message;
|
||||||
|
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decrypt and deserialize the state
|
||||||
|
let mut state = {
|
||||||
|
if message.state.len() == 1 && message.state[0] == 0 {
|
||||||
|
println!("{}", message.state);
|
||||||
|
|
||||||
|
State {
|
||||||
|
state: BTreeMap::<Addr, Uint128>::new(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let sk_lock = self
|
||||||
|
.sk
|
||||||
|
.lock()
|
||||||
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
let sk = sk_lock
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(Status::internal("SigningKey unavailable"))?;
|
||||||
|
|
||||||
|
decrypt_state(sk, &message.state)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let requests_len = message.requests.len() as u32;
|
||||||
|
// Instantiate empty withdrawals map to include in response (Update message to smart contract)
|
||||||
|
let mut withdrawals_response = Vec::<(Addr, Uint128)>::new();
|
||||||
|
|
||||||
|
// Loop through requests, match on cases, and apply changes to state
|
||||||
|
for req in message.requests {
|
||||||
|
match req {
|
||||||
|
TransfersRequest::Transfer(ciphertext) => {
|
||||||
|
// Decrypt transfer ciphertext into cleartext struct (acquires lock on enclave sk to do so)
|
||||||
|
let transfer: ClearTextTransferRequestMsg = {
|
||||||
|
let sk_lock = self
|
||||||
|
.sk
|
||||||
|
.lock()
|
||||||
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
let sk = sk_lock
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(Status::internal("SigningKey unavailable"))?;
|
||||||
|
|
||||||
|
decrypt_transfer(sk, &ciphertext)?
|
||||||
|
};
|
||||||
|
if let Entry::Occupied(mut entry) = state.state.entry(transfer.sender) {
|
||||||
|
let balance = entry.get();
|
||||||
|
if balance >= &transfer.amount {
|
||||||
|
entry.insert(balance - transfer.amount);
|
||||||
|
|
||||||
|
state
|
||||||
|
.state
|
||||||
|
.entry(transfer.receiver)
|
||||||
|
.and_modify(|bal| *bal += transfer.amount)
|
||||||
|
.or_insert(transfer.amount);
|
||||||
|
}
|
||||||
|
// TODO: handle errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransfersRequest::Withdraw(receiver) => {
|
||||||
|
// If a user with no balance requests withdraw, withdraw request for 0 coins gets processed
|
||||||
|
// TODO: A no-op seems like a bad design choice in a privacy system
|
||||||
|
if let Some(withdraw_bal) = state.state.remove(&receiver) {
|
||||||
|
withdrawals_response.push((receiver, withdraw_bal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TransfersRequest::Deposit(sender, amount) => {
|
||||||
|
state
|
||||||
|
.state
|
||||||
|
.entry(sender)
|
||||||
|
.and_modify(|bal| *bal += amount)
|
||||||
|
.or_insert(amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt state
|
||||||
|
// Gets lock on PrivKey, generates PubKey to encrypt with
|
||||||
|
let state_enc = {
|
||||||
|
let sk_lock = self
|
||||||
|
.sk
|
||||||
|
.lock()
|
||||||
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
let pk = VerifyingKey::from(
|
||||||
|
sk_lock
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(Status::internal("SigningKey unavailable"))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
encrypt_state(RawState::from(state), pk)
|
||||||
|
.map_err(|e| Status::invalid_argument(e.to_string()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prepare message to chain
|
||||||
|
let msg = RunTransfersResponseMessage {
|
||||||
|
ciphertext: state_enc,
|
||||||
|
quantity: requests_len,
|
||||||
|
withdrawals: withdrawals_response,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attest to message
|
||||||
|
let attestation = self
|
||||||
|
.attestor
|
||||||
|
.quote(msg.clone())
|
||||||
|
.map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
|
||||||
|
let attested_msg = RawAttested { msg, attestation };
|
||||||
|
let message =
|
||||||
|
serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Response::new(RunTransfersResponse { message }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: consider using generics for these decrypt functions
|
||||||
|
fn decrypt_transfer(
|
||||||
|
sk: &SigningKey,
|
||||||
|
ciphertext: &HexBinary,
|
||||||
|
) -> TonicResult<ClearTextTransferRequestMsg> {
|
||||||
|
let o =
|
||||||
|
decrypt(&sk.to_bytes(), ciphertext).map_err(|e| Status::invalid_argument(e.to_string()))?;
|
||||||
|
|
||||||
|
serde_json::from_slice(&o)
|
||||||
|
.map_err(|e| Status::internal(format!("Could not deserialize transfer {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt_state(sk: &SigningKey, ciphertext: &HexBinary) -> TonicResult<State> {
|
||||||
|
let o: RawState = {
|
||||||
|
let o = decrypt(&sk.to_bytes(), ciphertext)
|
||||||
|
.map_err(|e| Status::invalid_argument(e.to_string()))?;
|
||||||
|
serde_json::from_slice(&o).map_err(|e| Status::invalid_argument(e.to_string()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
State::try_from(o).map_err(|e| Status::internal(format!("Could not deserialize state {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt_state(state: RawState, enclave_pk: VerifyingKey) -> TonicResult<RawCipherText> {
|
||||||
|
let serialized_state = serde_json::to_string(&state).expect("infallible serializer");
|
||||||
|
|
||||||
|
match encrypt(&enclave_pk.to_sec1_bytes(), serialized_state.as_bytes()) {
|
||||||
|
Ok(encrypted_state) => Ok(encrypted_state.into()),
|
||||||
|
Err(e) => Err(Status::internal(format!("Encryption error: {}", e))),
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ repository.workspace = true
|
||||||
keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
|
keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# external
|
# external
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
|
@ -16,7 +19,6 @@ color-eyre.workspace = true
|
||||||
ecies.workspace = true
|
ecies.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
k256.workspace = true
|
k256.workspace = true
|
||||||
prost.workspace = true
|
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
@ -39,6 +41,3 @@ quartz-proto.workspace = true
|
||||||
quartz-relayer.workspace = true
|
quartz-relayer.workspace = true
|
||||||
quartz-tee-ra.workspace = true
|
quartz-tee-ra.workspace = true
|
||||||
tm-stateless-verifier.workspace = true
|
tm-stateless-verifier.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
tonic-build.workspace = true
|
|
||||||
|
|
17
core/quartz/src/lib.rs
Normal file
17
core/quartz/src/lib.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![warn(
|
||||||
|
clippy::checked_conversions,
|
||||||
|
clippy::panic,
|
||||||
|
clippy::panic_in_result_fn,
|
||||||
|
missing_docs,
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
rust_2018_idioms,
|
||||||
|
unused_lifetimes,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications
|
||||||
|
)]
|
||||||
|
|
||||||
|
pub mod attestor;
|
||||||
|
pub mod server;
|
|
@ -9,8 +9,8 @@ use crate::{
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Attested<M, A> {
|
pub struct Attested<M, A> {
|
||||||
msg: M,
|
pub msg: M,
|
||||||
attestation: A,
|
pub attestation: A,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, A> Attested<M, A> {
|
impl<M, A> Attested<M, A> {
|
||||||
|
|
Loading…
Reference in a new issue