diff --git a/Cargo.lock b/Cargo.lock index 2b90797..a813f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2146,6 +2146,7 @@ dependencies = [ name = "mtcs-intent" version = "0.1.0" dependencies = [ + "bip32 0.5.1", "clap", "cosmrs 0.16.0", "cosmwasm-std", diff --git a/README.md b/README.md index d7dacb2..995e47f 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,5 @@ Gramine applications and accompanying Dockerfiles for ease-of-usage. ## Demos * [Quartz v0.2 demo](quartz_v0_2_demo.md) - Instructions to run the v0.2 demo. -* [Obligato Web3 liquidity demo](obligato_web3_liquidity_demo.md) - Instructions to run the Obligato with web3 liquidity +* [Obligato Web3 liquidity demo](demo/README.md) - Instructions to run the Obligato with web3 liquidity demo. diff --git a/enclaves/quartz/src/mtcs_server.rs b/enclaves/quartz/src/mtcs_server.rs index 89750c9..49a9cdf 100644 --- a/enclaves/quartz/src/mtcs_server.rs +++ b/enclaves/quartz/src/mtcs_server.rs @@ -23,7 +23,7 @@ use crate::{ proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse}, }; -const BANK_PK: &str = "02027e3510f66f1f6c1ea5e3600062255928e518220f7883810cac3fc7fc092057"; +const BANK_PK: &str = "0216254f4636c4e68ae22d98538851a46810b65162fe37bf57cba6d563617c913e"; #[derive(Clone, Debug)] pub struct MtcsService { diff --git a/obligato_web3_liquidity_demo.md b/obligato_web3_liquidity_demo.md deleted file mode 100644 index 735828e..0000000 --- a/obligato_web3_liquidity_demo.md +++ /dev/null @@ -1,270 +0,0 @@ -# Obligato web3 liquidity demo - -This demo shows end-to-end integration with Obligato for web3 liquidity (i.e. a native ERC20 token). - -This demo is expected to run on a single machine that has SGX. - -It depends on `wasmd` (version v0.44.0). Follow the instructions [here](https://docs.cosmwasm.com/docs/getting-started/installation/#wasmd) to install, but checkout version `v0.44.0`. - -## Create obligations and tenders on Obligato - -Make sure tenders have backing funds. - -## Start blockchain - -``` -# cd bisenzone-cw-mvp - -./scripts/keygen.sh -./scripts/init-node.sh -./scripts/run-node.sh -``` - -## Build contract - -``` -./scripts/build-contract.sh -``` - -## Listen to events (for debugging) - -``` -websocat ws://127.0.0.1:26657/websocket -{ "jsonrpc": "2.0", "method": "subscribe", "params": ["tm.event='Tx'"], "id": 1 } -``` - -## Init enclave - -### Setup and build - -Generate the private key and build the binary that will run in the enclave: - -``` -# cd tee-mtcs/enclaves/quartz - -gramine-sgx-gen-private-key - -CARGO_TARGET_DIR=./target cargo build --release -``` - -The built binary is a grpc server that hosts the (currently built-in) mtcs application. - -### Update enclave trusted hash - -Now we need to get the trusted hash to initialize the enclave. Running tm-prover with wrong trusted-hash should print the correct one. - -``` -# cd tee-mtcs/utils/tm-prover - -rm light-client-proof.json -cargo run -- --chain-id testing \ ---primary "http://127.0.0.1:26657" \ ---witnesses "http://127.0.0.1:26657" \ ---trusted-height 1 \ ---trusted-hash "5237772462A41C0296ED688A0327B8A60DF310F08997AD760EB74A70D0176C27" \ ---contract-address "wasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s0phg4d" \ ---storage-key "quartz_session" \ ---trace-file light-client-proof.json &> output -cat output | grep found | head -1 | awk '{print $NF}' | sed 's/\x1b\[[0-9;]*m//g' > trusted.hash -export TRUSTED_HASH=$(cat trusted.hash) -``` - -Note we dump the output of the command into the `output` file, which we then parse to get the trusted hash, -strip of any extra chars, and finally save into the `trusted.hash` file (we'll use this again laster). We also save it to an env var. - - -### Start enclave - -Update the `quartz-manifest.template` with the correct ("found") hash from the previous command: - -``` -# cd tee-mtcs/enclaves/quartz - -sed -i -r "s/(\"--trusted-hash\", \")[A-Z0-9]+(\"])/\1$TRUSTED_HASH\2/" quartz.manifest.template -``` - -That will overwrite the template file in place, inserting the new hash in place of the old one. - -Now we can start the enclave: - -``` -# cd tee-mtcs/enclaves/quartz - -gramine-manifest \ --Dlog_level="error" \ --Dhome=${HOME} \ --Darch_libdir="/lib/$(gcc -dumpmachine)" \ --Dra_type="epid" \ --Dra_client_spid="51CAF5A48B450D624AEFE3286D314894" \ --Dra_client_linkable=1 \ --Dquartz_dir="$(pwd)" \ -quartz.manifest.template quartz.manifest - -gramine-sgx-sign --manifest quartz.manifest --output quartz.manifest.sgx -gramine-sgx ./quartz -``` - -## Send initiate request - -Now with the binary running in the enclave, we can run commands in another window. - -First, let's instantiate: - -``` -# cd tee-mtcs/utils/quartz-relayer - -export INSTANTIATE_MSG=$(./scripts/relay.sh Instantiate) -``` - -Note we save the output into an env variable. - -## Deploy contract - -We can now deploy the contract. The deploy script will read from $INSTANTIATE_MSG and use the attestation to create the contract. - -``` -# cd bisenzone-cw-mvp - -./scripts/deploy-contract.sh artifacts/cw_tee_mtcs.wasm &> output - -export CONTRACT=$(cat output | grep Address | awk '{print $NF}' | sed 's/\x1b\[[0-9;]*m//g') -``` - -Note again we save the output to a file, and then parse the file to get the contract address, which we save in an env var. - -## Create session - -Now we can initialize a session on the enclave, which will generate a nonce to use: - -``` -# cd tee-mtcs/utils/quartz-relayer - -export EXECUTE=$(./scripts/relay.sh SessionCreate) -``` - -And we can execute the session creation on the contract: - -``` -wasmd tx wasm execute "$CONTRACT" "$EXECUTE" --from alice --chain-id testing -y -``` - -## Set session pk - -Now let's generate a light client proof that the contract has created the session: - -``` -# cd tee-mtcs/utils/tm-prover - -rm light-client-proof.json -export TRUSTED_HASH=$(cat trusted.hash) -cargo run -- --chain-id testing \ ---primary "http://127.0.0.1:26657" \ ---witnesses "http://127.0.0.1:26657" \ ---trusted-height 1 \ ---trusted-hash $TRUSTED_HASH \ ---contract-address $CONTRACT \ ---storage-key "quartz_session" \ ---trace-file light-client-proof.json -``` - -And store the proof in an env var: - -``` -export POP=$(cat light-client-proof.json) -export POP_MSG=$(jq -nc --arg message "$POP" '$ARGS.named') -``` - -Now we can relay this proof to the enclave, so it can attest to the pubkey: - -``` -# cd tee-mtcs/utils/quartz-relayer - -export EXECUTE=$(./scripts/relay.sh SessionSetPubKey "$POP_MSG") -``` - -And send the attestation back to the contract: - -``` -wasmd tx wasm execute "$CONTRACT" "$EXECUTE" --from alice --chain-id testing -y -``` - -## Check for session success - -Wait a few seconds for the tx to commit, and then fetch the nonce and pubkey data: - -``` -export NONCE_AND_KEY=$(wasmd query wasm contract-state raw "$CONTRACT" $(printf '%s' "quartz_session" | hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d) -echo $NONCE_AND_KEY -# Note if you see an empty pubkey, wait a few seconds and rerun the above wasmd query command -# {"nonce":"d3283ed5d646298c27f5ef1726c42bf4853ed7f3d30c905fd3607ecc56903db4","pub_key":"02e4d8bc80d032ad610e4643c3da4235076b4d24335cc4c77592562bdcd62ce1d0"} - -export PUBKEY=$(echo $NONCE_AND_KEY | jq -r .pub_key) -``` - -## Sync obligations - -Now with the pubkey in hand, we can fetch the obligations from Obligato and encrypt them: - -``` -# cd tee-mtcs/utils/cycles-sync - -cargo run -- --keys-file keys.json \ - --obligation-user-map-file o_map.json \ - --user "alice" \ - --contract $CONTRACT \ - sync-obligations \ - --epoch-pk $PUBKEY - -export OBLIGATIONS=$(wasmd query wasm contract-state raw "$CONTRACT" $(printf '%s' "1/obligations" | hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d) -``` - -## Init clearing - -Create a clearing cycle on Obligato (required to be able to upload setoffs to Obligato) and initiate clearing on the -blockchain. - -``` -wasmd tx wasm execute $CONTRACT '"init_clearing"' --from alice --chain-id testing -y -``` - -## Run clearing on enclave - -With the encrypted obligations in hand, and clearing run initiated on chain, we can run clearing on the enclave: - -``` -# cd tee-mtcs/enclaves/quartz - -export REQUEST_MSG=$(jq -nc --arg message "$OBLIGATIONS" '$ARGS.named') - -export SETOFFS=$(grpcurl -plaintext -import-path ../../enclaves/quartz/proto/ -proto mtcs.proto -d "$REQUEST_MSG" '127.0.0.1:11090' mtcs.Clearing/Run | jq -c '.message | fromjson') -``` - -## Submit setoffs - -``` -export EXECUTE=$(jq -nc --argjson submit_setoffs "$SETOFFS" '$ARGS.named') -wasmd tx wasm execute "$CONTRACT" "$EXECUTE" --from alice --chain-id testing -y --gas 2000000 - -wasmd query wasm contract-state raw "$CONTRACT" $(printf '%s' "1/setoffs" | hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d -``` - -## Verify CW20 balances - -TODO: replace addresses - -``` -wasmd query wasm contract-state smart "$CONTRACT" '{"balance": {"address": "wasm1gjg72awjl7jvtmq4kjqp3al9p6crstpar8wgn5"}}' -wasmd query wasm contract-state smart "$CONTRACT" '{"balance": {"address": "wasm1tawlwmllmnwm950a7uttqlyne3k4774rsnuw6e"}}' -``` - -## Sync setoffs - -``` -# cd tee-mtcs/utils/cycles-sync - -cargo run -- --keys-file keys.json \ - --obligation-user-map-file o_map.json \ - --user "alice" \ - --contract $CONTRACT \ - sync-set-offs -``` diff --git a/utils/cycles-sync/src/main.rs b/utils/cycles-sync/src/main.rs index f6e1de8..eb1f45b 100644 --- a/utils/cycles-sync/src/main.rs +++ b/utils/cycles-sync/src/main.rs @@ -38,9 +38,10 @@ mod wasmd_client; const MNEMONIC_PHRASE: &str = "clutch debate vintage foster barely primary clown leader sell manual leopard ladder wet must embody story oyster imitate cable alien six square rice wedding"; +const ALICE_ID: &str = "7bfad4e8-d898-4ce2-bbac-1beff7182319"; const BANK_DEBTOR_ID: &str = "3879fa15-d86e-4464-b679-0a3d78cf3dd3"; -const OBLIGATO_URL: &str = "https://deploy-preview-329--obligato-app-bisenzone.netlify.app"; +const OBLIGATO_URL: &str = "https://bisenzone.obligato.network"; type Sha256Digest = [u8; 32]; @@ -114,6 +115,8 @@ async fn sync_setoffs(cli: Cli) -> Result<(), DynError> { }) .collect(); + info!("setoffs: {setoffs:?}"); + // send to Obligato let client = HttpClient::new(OBLIGATO_URL.parse().unwrap()); client.set_setoffs(setoffs).await?; @@ -133,7 +136,7 @@ async fn sync_obligations(cli: Cli, epoch_pk: &str) -> Result<(), DynError> { add_default_acceptances(&mut intents, bank_id); - // info!("intents: {intents:?}"); + info!("intents: {intents:?}"); let intents_enc = { let epoch_pk = VerifyingKey::from_sec1_bytes(&hex::decode(epoch_pk).unwrap()).unwrap(); @@ -143,7 +146,7 @@ async fn sync_obligations(cli: Cli, epoch_pk: &str) -> Result<(), DynError> { let msg = create_wasm_msg(intents_enc); let wasmd_client = CliWasmdClient; - wasmd_client.tx_execute(&cli.contract, &cli.chain_id, 2000000, cli.user, msg)?; + wasmd_client.tx_execute(&cli.contract, &cli.chain_id, 3000000, cli.user, msg)?; Ok(()) } @@ -285,6 +288,14 @@ fn derive_keys( let mut keys = HashMap::new(); let mut child_num = 0; + let alice_id = Uuid::parse_str(ALICE_ID).unwrap(); + + keys.entry(alice_id) + .or_insert_with(|| derive_child_xprv(&seed, &mut child_num)); + + keys.entry(bank_id) + .or_insert_with(|| derive_child_xprv(&seed, &mut child_num)); + for o in obligations { keys.entry(o.debtor_id) .or_insert_with(|| derive_child_xprv(&seed, &mut child_num)); @@ -292,9 +303,6 @@ fn derive_keys( .or_insert_with(|| derive_child_xprv(&seed, &mut child_num)); } - keys.entry(bank_id) - .or_insert_with(|| derive_child_xprv(&seed, &mut child_num)); - Ok(keys) } diff --git a/utils/cycles-sync/src/obligato_client/http.rs b/utils/cycles-sync/src/obligato_client/http.rs index 676423d..03e1c49 100644 --- a/utils/cycles-sync/src/obligato_client/http.rs +++ b/utils/cycles-sync/src/obligato_client/http.rs @@ -28,6 +28,8 @@ impl HttpClient { } } +// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNhZXNzdGpjdG16bXVqaW55cGJlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDMwMTkxNDksImV4cCI6MjAxODU5NTE0OX0.gQsQ26W2AGfwmncTecfKaenRaxhXwZFqLtmcllD_7Sg + #[async_trait] impl Client for HttpClient { type Error = reqwest::Error; @@ -36,7 +38,7 @@ impl Client for HttpClient { let response = self .client .post(self.url_with_path("api/sync/obligations2contract")) - .json(&json!({"denom_id": "1", "key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRydXZveWVhYXN5bXZubGxmdnZ5Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxMTYyNDgzNiwiZXhwIjoyMDI3MjAwODM2fQ.y-2iTQCplrXBEzHrvz_ZGFmMx-iLMzRZ6I0N5htJ39c"})) + .json(&json!({"denom_id": "1", "key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNhZXNzdGpjdG16bXVqaW55cGJlIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcwMzAxOTE0OSwiZXhwIjoyMDE4NTk1MTQ5fQ.EV6v5J3dz8WHAdTK4_IEisKzF-n1Gqyn4wCce_Zrqf4"})) .send() .await? .json::() diff --git a/utils/mtcs-intent/Cargo.toml b/utils/mtcs-intent/Cargo.toml index 4131986..6385efe 100644 --- a/utils/mtcs-intent/Cargo.toml +++ b/utils/mtcs-intent/Cargo.toml @@ -16,3 +16,5 @@ rand = "0.8.5" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.114" sha2 = "0.10.8" +bip32 = { version = "0.5.1" , features = ["alloc"] } + diff --git a/utils/mtcs-intent/src/main.rs b/utils/mtcs-intent/src/main.rs index 87e93ec..b976d99 100644 --- a/utils/mtcs-intent/src/main.rs +++ b/utils/mtcs-intent/src/main.rs @@ -17,8 +17,10 @@ use std::{ fs::{read_to_string, File}, io::Write, path::PathBuf, + str::FromStr, }; +use bip32::XPrv; use clap::{Parser, Subcommand}; use cosmrs::{tendermint::account::Id as TmAccountId, AccountId}; use cosmwasm_std::HexBinary; @@ -77,6 +79,10 @@ enum Command { #[clap(long)] pk: String, }, + PrintAddressFromPriv { + #[clap(long)] + sk_str: String, + }, } fn parse_obligation_json(s: &str) -> Result { @@ -300,6 +306,19 @@ fn main() -> Result<(), Box> { let tm_pk = TmAccountId::from(pk); println!("{}", AccountId::new("wasm", tm_pk.as_bytes()).unwrap()); } + Command::PrintAddressFromPriv { sk_str } => { + let sk = XPrv::from_str(&sk_str).unwrap(); + + let pk_b = sk.public_key().public_key().to_sec1_bytes(); + let pk = VerifyingKey::from_sec1_bytes(&pk_b)?; + + let pk_bytes = hex::encode(pk.to_sec1_bytes()); + + println!("{}", pk_bytes); + + let tm_pk = TmAccountId::from(pk); + println!("{}", AccountId::new("wasm", tm_pk.as_bytes()).unwrap()); + } } Ok(()) diff --git a/utils/quartz-relayer/scripts/relay.sh b/utils/quartz-relayer/scripts/relay.sh index e91e610..a395369 100755 --- a/utils/quartz-relayer/scripts/relay.sh +++ b/utils/quartz-relayer/scripts/relay.sh @@ -10,9 +10,9 @@ usage() { IAS_API_KEY="669244b3e6364b5888289a11d2a1726d" RA_CLIENT_SPID="51CAF5A48B450D624AEFE3286D314894" -QUOTE_FILE="/tmp/test.quote" -REPORT_FILE="/tmp/datareport" -REPORT_SIG_FILE="/tmp/datareportsig" +QUOTE_FILE="/tmp/${USER}_test.quote" +REPORT_FILE="/tmp/${USER}_datareport" +REPORT_SIG_FILE="/tmp/${USER}_datareportsig" REQUEST="$1" REQUEST_MSG=${2:-"{}"}