moonstream-to / checkpls

Apache License 2.0
0 stars 1 forks source link

Checklist file syntax #2

Closed zomglings closed 11 months ago

zomglings commented 11 months ago

Check, Please users should be able to share checklists with each other without having to run a backend or subscribe to some third-party backend (such as Moonstream).

To this end, all Check, Please checklists will be defined as flat files by default. Check, Please backends can host representations of these files for their users, but any system that interacts with Check, Please will be assumed to support these flat checklist files.

Check, Please checklists must be:

  1. Human readable
  2. Easy to load and manipulate in any programming language

The clear choice is to represent these checklists as JSON.

Check lists cannot be of arbitrary JSON structure, though. Each checklist will consist of a requester, an executor, and a list of steps to start with. The requester will also be able to provide a description (in Markdown) about what the checklist represents.

The top-level structure of a checklist object will be:

{
    "requester": "<requester name, Ethereum address, or whatever>",
    "executor": "<executor Ethereum address>",
    "steps": [],
    "description": "Markdown description of this checklist"
}

In v0.1, each step will be a request for the executor to submit some on-chain transaction. As such, each step needs to specify the following:

  1. Blockchain (specified by chain_id)
  2. to address for the transaction
  3. value to be transferred with the transaction (native tokens) - this will be represented as a string and is denominated in wei
  4. Transaction calldata

Submitting arbitrary calldata to an arbitrary to address is nobody's definition of safe. As such, in each step that calls a function on a smart contract, the requester can also specify a method_abi for the method being called that can be used to decode the calldata. Check, Please frontends can use this to put executors at ease about what the calldata represents.

The requester can provide a description of each step.

Finally, the step contains a nullable tx_hash field. Once the step is complete, the executor can put the transaction hash of the corresponding transaction into this field (as a string) to denote completion.

Step structure:

{
    "chain_id": 1,
    "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "value": "0",
    "calldata": "a9059cbb000000000000000000000000000000000000000000000000000000000000dead00000000000000000000000000000000000000000000000000000000000f4240",
    "method_abi": {
        "inputs": [
        {
            "name": "recipient",
            "type": "address"
        },
        {
            "name": "amount",
            "type": "uint256"
        }
        ],
        "name": "transfer",
        "outputs": [
        {
            "name": "",
            "type": "bool"
        }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    "description": "Send 1 USDC to the dead address"
}
kompotkot commented 11 months ago

Only one suggestion to put "executor": "<executor Ethereum address>", into steps: [] otherwise if we will want in future to add multiple executors (for example 1check required 1 person and another step required 2nd person) we will need to run migration for previous checklists support

Andrei-Dolgolev commented 11 months ago

Maybe lestimated gas/ real gas used fields can be out of steps then when you share it user know what expect.

1 step can use output of another step how tool will handle it?

zomglings commented 11 months ago

Great suggestions @kompotkot and @Andrei-Dolgolev . I need to think about how to share state between steps. But will make the change about executor immediately.

zomglings commented 11 months ago

Ok, I changed the implementation substantially, based on your feedback:

  1. Removed JSON Schema. It is unnecessarily complicated for a single, static schema.
  2. Introduced a notion of step types. Currently, we have InputStep for manual inputs, ViewStep to call view methods on smart contracts, RawStep to submit transactions with calldata, and MethodCallStep to submit method calls to smart contract given their ABI.
  3. All object keys are specified in camel case rather than snake case now - makes it easier to directly load JSON checklists into our Javascript code.
  4. Using handlebars.js to interpolate the output of earlier steps into parameters of later steps. Currently only ViewStep and MethodCallStep can use output from their dependencies.
  5. Made stepID a required field on each step. Each step can declare dependencies using stepIDs.

I also added some code to check for cycles in dependencies, etc. Will open a PR for this shortly.

zomglings commented 11 months ago

@Andrei-Dolgolev : Gas estimates don't apply to all steps, and anyway this is the job of the wallet. I don't think that belongs here. You can see gas estimate before you submit transactions e.g. in Metamask.