Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNIP-24 - Query Permits #22

Merged
merged 41 commits into from
Oct 19, 2021
Merged

SNIP-24 - Query Permits #22

merged 41 commits into from
Oct 19, 2021

Conversation

assafmo
Copy link
Member

@assafmo assafmo commented Sep 25, 2021

A way to do authenticated queries without needing to set a viewing key first. 👀

Docs: https://github.com/SecretFoundation/SNIPs/blob/master/SNIP-24.md

Keplr example (SNIP-20):

const permitName = "secretswap.io";
const allowedTokens = ["secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg"];
const permissions = ["balance" /* , "history", "allowance" */];

const { signature } = await window.keplr.signAmino(
  chainId,
  myAddress,
  {
    chain_id: chainId,
    account_number: "0", // Must be 0
    sequence: "0", // Must be 0
    fee: {
      amount: [{ denom: "uscrt", amount: "0" }], // Must be 0 uscrt
      gas: "1", // Must be 1
    },
    msgs: [
      {
        type: "query_permit", // Must be "query_permit"
        value: {
          permit_name: permitName,
          allowed_tokens: allowedTokens,
          permissions: permissions,
        },
      },
    ],
    memo: "", // Must be empty
  },
  {
    preferNoSetFee: true, // Fee must be 0, so hide it from the user
    preferNoSetMemo: true, // Memo must be empty, so hide it from the user
  }
);

const { balance } = await secretjs.queryContractSmart(
  "secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg",
  {
    with_permit: {
      query: { balance: {} },
      permit: {
        params: {
          permit_name: permitName,
          allowed_tokens: allowedTokens,
          chain_id: chainId,
          permissions: permissions,
        },
        signature: signature,
      },
    },
  }
);

console.log(balance.amount);

Keplr example (SNIP-721):

const permitName = "A cool Secret NFT game";
const allowedTokens = ["secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg"];
const permissions = ["owner"];

const { signature } = await window.keplr.signAmino(
  chainId,
  myAddress,
  {
    chain_id: chainId,
    account_number: "0", // Must be 0
    sequence: "0", // Must be 0
    fee: {
      amount: [{ denom: "uscrt", amount: "0" }], // Must be 0 uscrt
      gas: "1", // Must be 1
    },
    msgs: [
      {
        type: "query_permit", // Must be "query_permit"
        value: {
          permit_name: permitName,
          allowed_tokens: allowedTokens,
          permissions: permissions,
        },
      },
    ],
    memo: "", // Must be empty
  },
  {
    preferNoSetFee: true, // Fee must be 0, so hide it from the user
    preferNoSetMemo: true, // Memo must be empty, so hide it from the user
  }
);

const tokens = await secretjs.queryContractSmart(
  "secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg",
  {
    with_permit: {
      query: { tokens: {} },
      permit: {
        params: {
          permit_name: permitName,
          allowed_tokens: allowedTokens,
          chain_id: chainId,
          permissions: permissions,
        },
        signature: signature,
      },
    },
  }
);

console.log(tokens);

CLI example (SNIP-20):

$ echo '{
    "chain_id": "secret-3",
    "account_number": "0",
    "sequence": "0",
    "msgs": [
        {
            "type": "query_permit",
            "value": {
                "permit_name": "test",
                "allowed_tokens": [
                    "secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg"
                ],
                "permissions": ["balance"]
            }
        }
    ],
    "fee": {
        "amount": [
            {
                "denom": "uscrt",
                "amount": "0"
            }
        ],
        "gas": "1"
    },
    "memo": ""
}' > ./permit.json
$ secretcli tx sign-doc ./permit.json --from yo > ./sig.json
$ secretcli q compute query secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg '{"with_permit":{"query":{"balance":{}},"permit":{"params":{"permit_name":"test","allowed_tokens":["secret18vd8fpwxzck93qlwghaj6arh4p7c5n8978vsyg"],"chain_id":"secret-3","permissions":["balance"]},"signature":'"$(cat ./sig.json)"'}}}'

of querying my balance with a signed permit instead of a viewing key
And rename permit_id to permit_user_id
In order to verify the signature, we need to serialize the permit's content into JSON as UTF8 bytes. Amino encoding requires JSON serialization to sort object fields alphabetically, so to do so inside the contract a reorder of the permit data structs had to be done. Apparently serde_json_wasm keeps this order while serializing to bytes.

For reference, this is how it's done by Keplr/cosmjs: https://github.com/enigmampc/cosmjs/blob/b2279928c6d46a568e619cafddc6c1bbd17ec1b0/packages/amino/src/signdoc.ts?plain=1#L31-L51
@assafmo
Copy link
Member Author

assafmo commented Sep 26, 2021

src/contract.rs Outdated Show resolved Hide resolved
@the-dusky
Copy link
Contributor

Does this mean that you will need to sign a tx every time you query a balance? Will this live along side viewing keys as a sort of "one time passcode" for queries that access private state?

Makefile Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/msg.rs Outdated Show resolved Hide resolved
src/msg.rs Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
@assafmo
Copy link
Member Author

assafmo commented Sep 26, 2021

@the-dusky

Does this mean that you will need to sign a tx every time you query a balance?

No, you sign it offline (you don't broadcast a tx) and the signature (=permit) is sent with the balance query (like a viewing key) and is reusable for multiple queries. To revoke a permit the user needs to send a "revoke permit" tx.

Will this live along side viewing keys as a sort of "one time passcode" for queries that access private state?

This is an addition, so viewing keys remain untouched. It's reusable, so not exactly a "one time passcode".

To make sure it's aligned with Amino encoding
- Balance
- TransferHistory
- TransactionHistory
- Allowance
Makefile Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/msg.rs Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/contract.rs Outdated Show resolved Hide resolved
src/msg.rs Show resolved Hide resolved
@assafmo assafmo changed the title Query balance with a signed permit instead of a viewing key Query with a signed permit instead of a viewing key Sep 27, 2021
src/state.rs Outdated Show resolved Hide resolved
@assafmo assafmo force-pushed the query-balance-prmit branch from 9e937b0 to 942debd Compare October 17, 2021 18:46
@assafmo assafmo marked this pull request as ready for review October 19, 2021 20:59
@assafmo assafmo merged commit bf165a5 into master Oct 19, 2021
@dylanschultzie
Copy link

Omg it's happening. 😍

@assafmo assafmo deleted the query-balance-prmit branch October 19, 2021 21:08
@assafmo assafmo changed the title Query with a signed permit instead of a viewing key SNIP-24 - Query Permits Oct 19, 2021
assafmo added a commit to scrtlabs/SecretNetwork that referenced this pull request Nov 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants