SecretFoundation / dev_committee

0 stars 0 forks source link

Organize secret contracts guide repo #7

Open cankisagun opened 3 years ago

cankisagun commented 3 years ago

Goal is to improve the organization of information and add additional info to create a comprehensive secret contract guide

I think we need to add the following / create sections so the information is easily accessible. The read me can then act as an index.

Getting setup (probably simpler to add a md on this and link to it:

Setup secret contracts

Build your initial simple secret contract

link to the secretToolkit

build an advanced secret contract( new md.) ->

build a UI using Secret.JS ->

Deploy it on testnet and miannet

baedrik commented 3 years ago

I do like the idea of having a doc broken down into headers for actions people will commonly need. So if they already have a feel for what a contract is, but need a specific example of how to do one thing, they can just look for the header in that doc instead of having to go through a whole walkthrough. As an example, just some stuff I'm copying over from my WIP walkthrough revision...

Calling another contract:

If you need to "roll your own" calls to contracts that do not have toolkit shortcuts, you can do the following:

use cosmwasm_std::{WasmMsg, CosmosMsg, StdResult, Coin, to_binary};
use secret_toolkit::utils::{space_pad};
pub const MSG_BLOCK_SIZE: usize = 256;

use example_package::msg::HandleMsg as CallbackHandleMsg;

I included some example uses that you may not already have listed. Add as needed. The last one is the important one. You first add an "example_package" dependency in the Cargo.toml to point to the repo of the contract you want to call. Change "example_package" to whatever package name is listed in their Cargo.toml. The use statement above will use all the HandleMsg definitions in the contract you want to call and allow you to refer to them as the CallbackHandleMsg enum. If their HandleMsg enum is NOT defined in the typical msg.rs file, you will change the use statement to include the specific crate it is defined in. Alternatively you could just copy and paste the HandleMsg enum you want to use, and define it in your own contract instead of including the use statement.

...
    HandleMsgName {
        some: String,
        data: String,
        fields: String,
    },
...
}

For this example, let's assume the HandleMsg you want to execute is defined as above.

trait Callback {
    fn to_cosmos_msg(
        &self,
        callback_code_hash: String,
        contract_addr: HumanAddr,
        send_amount: Option<Uint128>,
    ) -> StdResult<CosmosMsg>;
}

impl Callback for CallbackHandleMsg {
    fn to_cosmos_msg(
        &self,
        callback_code_hash: String,
        contract_addr: HumanAddr,
        send_amount: Option<Uint128>,
    ) -> StdResult<CosmosMsg> {
        let mut msg = to_binary(self)?;
        space_pad(&mut msg.0, MSG_BLOCK_SIZE);
        let mut send = Vec::new();
        if let Some(amount) = send_amount {
            send.push(Coin {
                amount,
                denom: String::from("uscrt"),
            });
        }
        let execute = WasmMsg::Execute {
            msg,
            contract_addr,
            callback_code_hash,
            send,
        };
        Ok(execute.into())
    }
}

Then you define a trait that you want to add to the enum you are importing from the other contract, and implement that trait as above. What you are doing is adding a function to the HandleMsg enum that will return the CosmosMsg you need to add to the messages Vec of the InitResponse/HandleResponse. If you only copy-and-pasted the enum definition, you will not define the trait, and you will change impl Callback for CallbackHandleMsg { to impl CallbackHandleMsg { (if you named your copy-and-pasted enum CallbackHandleMsg). The send_amount parameter is the amount of uSCRT you want to send to the contract with the HandleMsg. If the function does not require any SCRT being sent, you will want to call to_cosmos_msg with None as the send_amount.
The code above pads the message to a block size of MSG_BLOCK_SIZE using the space_pad function in the utils package of https://github.com/enigmampc/secret-toolkit. It is best practice to pad your messages so that their byte size can not be used to glean information about what message was processed.
Then to call the contract:

    Ok(InitResponse {
        messages: vec![
            CallbackHandleMsg::HandleMsgName {
                some: "a".to_string(), 
                data: "b".to_string(),
                fields: "c".to_string(),
            }
            .to_cosmos_msg(
                code_hash_of_contract_you_want_to_call,
                that_contracts_address,
                Some(1000000),
            )?,
        ],
        log: vec![],
    })
}

This calls the example HandleMsg defined earlier and also sends 1000000uscrt along with the callback message. The messages field of InitReponse/HandleResponse is a Vec<CosmosMsg>. Anytime you want to call another contract, you push the appropriate CosmosMsg onto that Vec.

Maybe have headers for Calling another contract, querying another contract, using storage (broken down into small examples for just using set/get, setting up/using Singleton, Bucket, etc...

cankisagun commented 3 years ago

@levackt and I discussed to change the docs page on build as such

image

reuvenpo commented 3 years ago

@cankisagun I think referencing the toolkit would be ok, even great. It's still a work in progress, but it has a lot of things in it that can help people in their learning curve, as they'll have some boilerplate already wrapped up for them.

@baedrik I think that copying the other contract's message types would be the easiest move for now, but we could fiddle with the secret-template to make it more library-reuse friendly :) Right now you can't just import things from other contracts that are based on the template, since doing that will cause a duplicate definition of the contract entry points. This is not a fundamental issue, and can think of one or two ways of circumventing it.

As for your explanation of the Callback trait, i think it can be made much simpler to use. Let me know what you think about this: https://github.com/enigmampc/secret-toolkit/pull/9

cankisagun commented 3 years ago

The goal of this effort is to eventually fit these parts under https://build.scrt.network/dev/developers.html

reuvenpo commented 3 years ago

yeah, i think that using the toolkit can make some sections of the code shorter

baedrik commented 3 years ago

@baedrik I think that copying the other contract's message types would be the easiest move for now, but we could fiddle with the secret-template to make it more library-reuse friendly :) Right now you can't just import things from other contracts that are based on the template, since doing that will cause a duplicate definition of the contract entry points. This is not a fundamental issue, and can think of one or two ways of circumventing it.

As for your explanation of the Callback trait, i think it can be made much simpler to use. Let me know what you think about this: enigmampc/secret-toolkit#9

@reuvenpo I like it! I added a comment on the PR that I'm curious what your thoughts are

reuvenpo commented 3 years ago

Thanks! I left my reply in the PR discussion :)

guyz commented 3 years ago

Re: organization, both contracts (simple and advanced) should have a UI component.

I should not need to go through setup, building a simple secret contract, building an advance secret contract, building a UI to get a to functional app.

The structure should indeed generally be:

  1. Setup
  2. Your first secret contract (including UI)
  3. More advanced features
  4. A more advanced contract (including UI).

3 and #4 ordering can be flipped.

cankisagun commented 3 years ago

will integrate these comments once the current PR is merged @guyz