diff --git a/README.md b/README.md index 177ebd6..bba0296 100644 --- a/README.md +++ b/README.md @@ -255,15 +255,15 @@ echo 'export CC=/opt/homebrew/opt/llvm/bin/clang' >> ~/.zshrc source ~/.zshrc ``` -* Compile. Note: Outputs contract.wasm and contract.wasm.gz file in the root directory of the secret-contracts/nunya-contract folder +* Run Docker (e.g. Docker Desktop on macOS) + +* [Compile](https://docs.scrt.network/secret-network-documentation/development/readme-1/compile-and-deploy#compile-the-code). Note: Outputs contract.wasm and contract.wasm.gz file in the root directory of the secret-contracts/nunya-contract folder. Using `make build-mainnet-reproducible` will remove contract.wasm so only the optimised contract.wasm.gz remains. Warning: If you only run `make build-mainnet` then you will get this error https://github.com/svub/nunya/issues/8 when deploying. ``` cd packages/secret-contracts/nunya-contract -make build +make build-mainnet-reproducible ``` -* OPTIONAL - optimize contract code. Refer to official Secret network docs - * Upload and Instantiate > IMPORTANT: Currently unable to deploy due to this TNLS error https://github.com/svub/nunya/issues/8 @@ -272,6 +272,10 @@ make build yarn run secret:clean:uploadContract yarn run secret:start:uploadContract ``` +* Query Pubkey +``` +yarn run secret:queryPubkey +``` * View logs at ./logs/instantiateOutput.log * View on Secret Testnet block explorer at https://testnet.ping.pub/secret/ diff --git a/docker/secret-contract-optimizer.Dockerfile b/docker/secret-contract-optimizer.Dockerfile new file mode 100644 index 0000000..d4ce5a6 --- /dev/null +++ b/docker/secret-contract-optimizer.Dockerfile @@ -0,0 +1,20 @@ +# https://github.com/scrtlabs/SecretNetwork/blob/master/deployment/dockerfiles/base-images/secret-contract-optimizer.Dockerfile#L9 +# v1.0.10 +# Modifications: +# - removed `--locked` +# - added `--enable-threads --enable-bulk-memory --all-features` +FROM rust:1.71.0-slim-bullseye + +RUN rustup target add wasm32-unknown-unknown +RUN apt update && apt install -y binaryen clang && rm -rf /var/lib/apt/lists/* + +WORKDIR /contract + +ENTRYPOINT ["/bin/bash", "-c", "\ + RUSTFLAGS='-C link-arg=-s' cargo build --release --lib --target wasm32-unknown-unknown && \ + (mkdir -p ./optimized-wasm/ && rm -f ./optimized-wasm/* && cp ./target/wasm32-unknown-unknown/release/*.wasm ./optimized-wasm/) && \ + for w in ./optimized-wasm/*.wasm; do \ + wasm-opt -Oz $w -o $w --enable-threads --enable-bulk-memory --all-features; \ + done && \ + (cd ./optimized-wasm && gzip -n -9 -f *) \ +"] diff --git a/logs/instantiateOutput.log b/logs/instantiateOutput.log index 90bb808..5e15095 100644 --- a/logs/instantiateOutput.log +++ b/logs/instantiateOutput.log @@ -1,15 +1,16 @@ Starting deployment... -codeId: 10593 -CODE_HASH: 5ea3b37c0f3b06a621e58327bd7235fd8c323a4a595b095914c5fd2a5511dc93 +tx.rawLog: [{"events":[{"type":"message","attributes":[{"key":"action","value":"/secret.compute.v1beta1.MsgStoreCode"},{"key":"module","value":"compute"},{"key":"sender","value":"secret1am2mk908456twwgehmaua85s6laar4yr3awzzj"},{"key":"signer","value":"secret1am2mk908456twwgehmaua85s6laar4yr3awzzj"},{"key":"code_id","value":"11036"}]}]}] +codeId: 11036 +CODE_HASH: 1af180cc6506af23fb3ee2c0f6ece37ab3ad32db82e061b6b30679fb8a3f1323 params: { - codeId: '10593', - contractCodeHash: '5ea3b37c0f3b06a621e58327bd7235fd8c323a4a595b095914c5fd2a5511dc93' + codeId: '11036', + contractCodeHash: '1af180cc6506af23fb3ee2c0f6ece37ab3ad32db82e061b6b30679fb8a3f1323' } Instantiating contract... tx: { - height: 7098192, - timestamp: '', - transactionHash: 'C5419257F2ED564093D27F1B73F4EAC4EAABC950EBE590C6B7C9C7B9CC434DEC', + height: 7247704, + timestamp: '2024-10-15T20:20:28Z', + transactionHash: '7575955CBA2BFA353C96E5F58767A07DC35FEEDEBA92BD8847D4391F0F8F0DF6', code: 0, codespace: '', info: '', @@ -24,19 +25,19 @@ tx: { }, auth_info: { signer_infos: [Array], fee: [Object] }, signatures: [ - 'J1Ei+KHikPOXjRfuP1b22UYlxdHJM6TpntR8KFmAEmBPRW2CFou8WFO9Nubg/vAR/bC0cKybR7d9+Rkb77rjNQ==' + 'BwgEzvF5mUkZALqvFQwb+SxuBGWJwbJQoGCbdvys2FlQ10LtkIc0xJwQTpiSszYCjluE/+nHVX6kzWBiICMpOQ==' ] }, - rawLog: '[{"events":[{"type":"instantiate","attributes":[{"key":"contract_address","value":"secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9"},{"key":"code_id","value":"10593"}]},{"type":"message","attributes":[{"key":"action","value":"/secret.compute.v1beta1.MsgInstantiateContract"},{"key":"module","value":"compute"},{"key":"sender","value":"secret1am2mk908456twwgehmaua85s6laar4yr3awzzj"},{"key":"contract_address","value":"secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9"}]},{"type":"wasm","attributes":[{"key":"contract_address","value":"secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9"}]}]}]', + rawLog: '[{"events":[{"type":"instantiate","attributes":[{"key":"contract_address","value":"secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3"},{"key":"code_id","value":"11036"}]},{"type":"message","attributes":[{"key":"action","value":"/secret.compute.v1beta1.MsgInstantiateContract"},{"key":"module","value":"compute"},{"key":"sender","value":"secret1am2mk908456twwgehmaua85s6laar4yr3awzzj"},{"key":"contract_address","value":"secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3"}]},{"type":"wasm","attributes":[{"key":"contract_address","value":"secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3"}]}]}]', jsonLog: [ { events: [Array], msg_index: 0 } ], arrayLog: [ { msg: 0, type: 'instantiate', key: 'contract_address', - value: 'secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9' + value: 'secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3' }, - { msg: 0, type: 'instantiate', key: 'code_id', value: '10593' }, + { msg: 0, type: 'instantiate', key: 'code_id', value: '11036' }, { msg: 0, type: 'message', @@ -54,13 +55,13 @@ tx: { msg: 0, type: 'message', key: 'contract_address', - value: 'secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9' + value: 'secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3' }, { msg: 0, type: 'wasm', key: 'contract_address', - value: 'secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9' + value: 'secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3' } ], events: [ @@ -77,10 +78,10 @@ tx: { { type: 'message', attributes: [Array] } ], data: [ - + ], - gasUsed: 43476, + gasUsed: 45183, gasWanted: 400000, ibcResponses: [] } -SECRET_ADDRESS: secret19kk5wcmxp2alr356emljyr8xp90atndxy3r2c9 +SECRET_ADDRESS: secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3 diff --git a/package.json b/package.json index 9c787d7..eb5bfc6 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "vercel": "yarn workspace @se-2/nextjs vercel", "vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo", "verify": "yarn workspace @se-2/hardhat verify", + "secret:queryPubkey": "yarn workspace secret-upload-contract queryPubkey", "secret:clean:uploadContract": "yarn workspace secret-upload-contract clean", "secret:start:uploadContract": "yarn workspace secret-upload-contract start", "secret:clean:instantiateContract": "yarn workspace secret-instantiate-contract clean", diff --git a/packages/hardhat/contracts/NunyaBusiness.sol b/packages/hardhat/contracts/NunyaBusiness.sol index 76ca0ce..4417456 100644 --- a/packages/hardhat/contracts/NunyaBusiness.sol +++ b/packages/hardhat/contracts/NunyaBusiness.sol @@ -53,6 +53,7 @@ contract NunyaBusiness { // TODO: only uncomment when hardhat has gateway deployed // TODO can we test if it's deployed and call then automatically? // IDEA use requestId to make sure nobody else is calling the callback, see below. + // Note: It may be necessary to call using snake case. // const requestId = secretContract.retrievePubkey(); // expectedResult[requestId] = FunctionCallType.GET_KEY; diff --git a/packages/secret-contracts/nunya-contract/.gitignore b/packages/secret-contracts/nunya-contract/.gitignore index 215f142..41760ce 100644 --- a/packages/secret-contracts/nunya-contract/.gitignore +++ b/packages/secret-contracts/nunya-contract/.gitignore @@ -29,4 +29,6 @@ yarn-error.log* contract.wasm contract.wasm.gz -/target \ No newline at end of file +/optimized-wasm + +/target diff --git a/packages/secret-contracts/nunya-contract/Cargo.lock b/packages/secret-contracts/nunya-contract/Cargo.lock index 6fcbc9b..e44965f 100644 --- a/packages/secret-contracts/nunya-contract/Cargo.lock +++ b/packages/secret-contracts/nunya-contract/Cargo.lock @@ -100,9 +100,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.88" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" [[package]] name = "cfg-if" @@ -589,13 +589,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.17.2" +source = "git+https://github.com/scrtlabs/rust-secp256k1#0782872fb0bed2e9166e91e837b8242bcf761859" +dependencies = [ + "secp256k1-sys 0.1.2", +] + [[package]] name = "secp256k1" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.8.1", "serde", ] @@ -605,7 +613,15 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.8.1", +] + +[[package]] +name = "secp256k1-sys" +version = "0.1.2" +source = "git+https://github.com/scrtlabs/rust-secp256k1#0782872fb0bed2e9166e91e837b8242bcf761859" +dependencies = [ + "cc", ] [[package]] @@ -760,7 +776,9 @@ dependencies = [ "anybuf", "base64 0.22.0", "cosmwasm-schema", + "hex", "schemars", + "secp256k1 0.17.2", "secret-cosmwasm-std", "secret-cosmwasm-storage", "secret-toolkit", diff --git a/packages/secret-contracts/nunya-contract/Makefile b/packages/secret-contracts/nunya-contract/Makefile index 3723740..8577628 100644 --- a/packages/secret-contracts/nunya-contract/Makefile +++ b/packages/secret-contracts/nunya-contract/Makefile @@ -34,12 +34,16 @@ _build-mainnet: cargo clean && AR=/opt/homebrew/opt/llvm/bin/llvm-ar CC=/opt/homebrew/opt/llvm/bin/clang RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown # like build-mainnet, but slower and more deterministic +# https://hub.docker.com/r/enigmampc/secret-contract-optimizer/tags .PHONY: build-mainnet-reproducible build-mainnet-reproducible: - docker run --rm -v "$$(pwd)":/contract \ - --mount type=volume,source="$$(basename "$$(pwd)")_cache",target=/contract/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - ghcr.io/scrtlabs/localsecret:v1.6.0-rc.3 + cargo clean && AR=/opt/homebrew/opt/llvm/bin/llvm-ar CC=/opt/homebrew/opt/llvm/bin/clang RUSTFLAGS='-C link-arg=-s' && \ + docker rmi sco && \ + docker buildx build --label "sco" --tag "sco" -f "../../../docker/secret-contract-optimizer.Dockerfile" . && \ + docker run --rm -v "$$(pwd)":/contract \ + --mount type=volume,source="$$(basename "$$(pwd)")_cache",target=/contract/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + sco:latest .PHONY: compress-wasm compress-wasm: diff --git a/packages/secret-contracts/nunya-contract/cargo.toml b/packages/secret-contracts/nunya-contract/cargo.toml index 4fb93ef..cb85e7c 100644 --- a/packages/secret-contracts/nunya-contract/cargo.toml +++ b/packages/secret-contracts/nunya-contract/cargo.toml @@ -50,6 +50,11 @@ tnls = { git = "https://github.com/SecretSaturn/TNLS", branch = "main", package # cw-storage-plus = { version = "0.14.0", default-features = false } anybuf = {version = "0.5.0"} +# crypto +hex = "0.4.3" +# secp256k1 = { version = "0.17.2", default-features = false } +secp256k1 = { git = "https://github.com/scrtlabs/rust-secp256k1" } + [[bin]] name = "schema" required-features = ["schema"] diff --git a/packages/secret-contracts/nunya-contract/src/contract.rs b/packages/secret-contracts/nunya-contract/src/contract.rs index a412d09..c96016e 100644 --- a/packages/secret-contracts/nunya-contract/src/contract.rs +++ b/packages/secret-contracts/nunya-contract/src/contract.rs @@ -6,7 +6,7 @@ use crate::{ }, state::{ PaymentReceipt, PaymentReferenceBalance, ResponseStatusCode, - State, CONFIG, MY_KEYS, + MyKeys, State, CONFIG, MY_KEYS, VIEWING_KEY, VIEWING_KEY_TO_PAYMENT_REF_TO_BALANCES_MAP, }, }; @@ -19,6 +19,7 @@ use tnls::{ msg::{PostExecutionMsg, PrivContractHandleMsg}, state::Task, }; +use secp256k1::{PublicKey, Secp256k1, SecretKey}; use anybuf::Anybuf; @@ -26,10 +27,37 @@ use anybuf::Anybuf; /// response size pub const BLOCK_SIZE: usize = 256; +// Create Secret Contract Keys +// TODO: use ContractError instead of StdError +// pub fn try_create_keys(deps: DepsMut, env: Env) -> Result { +pub fn try_create_keys(deps: DepsMut, env: Env) -> StdResult { + let rng = env.block.random.unwrap().0; + let secp = Secp256k1::new(); + + // Private Key + let private_key = SecretKey::from_slice(&rng).unwrap(); + let private_key_string = private_key.to_string(); + let private_key_bytes = hex::decode(private_key_string).unwrap(); + + // Public Key + let public_key = PublicKey::from_secret_key(&secp, &private_key); + let public_key_bytes = public_key.serialize().to_vec(); + // let public_key_string = public_key.to_string(); + + let my_keys = MyKeys { + private_key: private_key_bytes, + public_key: public_key_bytes, + }; + + MY_KEYS.save(deps.storage, &my_keys)?; + + Ok(Response::default()) +} + #[entry_point] pub fn instantiate( deps: DepsMut, - _env: Env, + env: Env, _info: MessageInfo, msg: InstantiateMsg, ) -> StdResult { @@ -42,6 +70,8 @@ pub fn instantiate( CONFIG.save(deps.storage, &state)?; + try_create_keys(deps, env)?; + Ok(Response::default()) } @@ -63,6 +93,10 @@ fn try_handle( // verify signature with stored gateway public key let config = CONFIG.load(deps.storage)?; + // SecretPath source code + // public network user address + let user_address = msg.user_address; + // Security // // reference: evm-kv-store-demo @@ -309,6 +343,7 @@ fn create_pay( let input: PayStoreMsg = serde_json_wasm::from_str(&input_values) .map_err(|err| StdError::generic_err(err.to_string()))?; + // TODO: validate the input.secret_user input let viewing_key_index = input.secret_user.as_str(); // convert u8 to String let payment_ref = input.payment_ref.as_str(); // convert Uint256 to String // TODO: handle error if issue with amount or denomination received diff --git a/packages/secret-upload-contract/package.json b/packages/secret-upload-contract/package.json index 3e25b4b..53a30e9 100644 --- a/packages/secret-upload-contract/package.json +++ b/packages/secret-upload-contract/package.json @@ -4,6 +4,7 @@ "main": "index.js", "private": true, "scripts": { + "queryPubkey": "yarn build && node ./dist/queryPubkey.js", "build": "./node_modules/.bin/tsc --build", "clean": "./node_modules/.bin/tsc --build --clean", "start": "yarn build && node ./dist/index.js" diff --git a/packages/secret-upload-contract/src/index.ts b/packages/secret-upload-contract/src/index.ts index f0416d4..2578e73 100644 --- a/packages/secret-upload-contract/src/index.ts +++ b/packages/secret-upload-contract/src/index.ts @@ -181,7 +181,7 @@ async function main () { const query_tx = await secretjs.query.compute.queryContract({ contract_address: params?.contractAddress?.toString(), code_hash: params?.contractCodeHash?.toString(), - query: { retrieve_pubkey_query: { key: 1 } }, + query: { retrieve_pubkey: {} }, }); console.log(query_tx); } diff --git a/packages/secret-upload-contract/src/queryPubkey.js b/packages/secret-upload-contract/src/queryPubkey.js new file mode 100644 index 0000000..523f30f --- /dev/null +++ b/packages/secret-upload-contract/src/queryPubkey.js @@ -0,0 +1,42 @@ +import { SecretNetworkClient } from "secretjs"; + +// Replace with deployed Secret contract details +const SECRET_ADDRESS = "secret1uwqdjnzrttepn86p2sjmnugfph7tz97hmcwjs3" +const CODE_HASH = "1af180cc6506af23fb3ee2c0f6ece37ab3ad32db82e061b6b30679fb8a3f1323" + +let query_pubkey = async (secretjs, params) => { + const query_tx = await secretjs.query.compute.queryContract({ + contract_address: params.contractAddress, + code_hash: params.contractCodeHash, + query: { retrieve_pubkey: {} }, + }); + console.log(query_tx); + return query_tx; +} + +async function main() { + let contractParams = { + contractAddress: SECRET_ADDRESS, + contractCodeHash: CODE_HASH, + }; + + const secretjs = new SecretNetworkClient({ + url: "https://lcd.testnet.secretsaturn.net", + chainId: "pulsar-3", + }); + + // Chain the execution using promises + await query_pubkey(secretjs, contractParams) + .then(async (res) => { + console.log('res: ', res); + }) + .catch((error) => { + console.error("Error:", error); + }); + + process.exit() +} +main().catch((error) => { + console.error(error); + process.exit(-1); +});