Policy Cheatsheet
Overview
Welcome to the Policy Cheatsheet!
This quick reference guide is designed to assist you in writing effective policies for your Tarobase app. For a deeper understanding of how policies work and best practices for creating secure and scalable policies, please visit the Policies page.
Policy Structure
A Tarobase policy is a JSON object that defines rules, fields, storage preferences, and triggers for specific paths in your data structure.
Basic Structure:
{
"path": {
"rules": {
"read": "<condition>",
"write": "<condition>"
},
"fields": {
"fieldName": "Types.DataType"
},
"onchain": true | false,
"triggers": [
"<operation>: <action>"
]
}
}
Example:
{
"messages/$messageId": {
"rules": {
"read": "true",
"write": "@prevState == null && @newState.text != null && @newState.createdBy == @walletAddress"
},
"fields": {
"createdBy": "Types.Address",
"text": "Types.String"
},
"onchain": true,
"triggers": [
"create: @TokenPlugin.transferWholeTokens(@TokenPlugin.USDC, @walletAddress, recipientAddress, 1)"
]
}
}
Special Variables
@prevState
: The current state of the document before the write operation.@newState
: The proposed new state of the document during the write operation.@walletAddress
: The wallet address of the user making the request.@root
: References the root of your app's document structure, allowing you to access any document.
Conditions and Operators
Use standard JavaScript-like operators to define conditions:
- Logical Operators:
&&
(and),||
(or),!
(not) - Comparison Operators:
==
,!=
,<
,>
,<=
,>=
- Null Check:
variable != null
,variable == null
Rules
Define who can read and write to specific paths:
- Read Rule (
"read"
): Condition that must be true for a read operation to succeed - Write Rule (
"write"
): Condition that must be true for a write operation to succeed
Examples:
- Allow everyone to read:
"read": true
- Allow writes only if the user is the owner:
"write": "@newState.createdBy == @walletAddress"
Fields and Data Types
Specify the expected fields and their data types for on-chain storage:
Available Data Types:
Types.String
Types.Address
Types.Int
Types.UInt
Types.Bool
Example:
"fields": {
"createdBy": "Types.Address",
"text": "Types.String",
"amount": "Types.UInt"
}
On-Chain Storage
To store data on-chain, set the "onchain" property to true:
"onchain": true
Note: When using on-chain storage, you must define all fields you will use in the "fields"
section.
Triggers
Triggers allow you to perform additional actions after a successful write operation.
Syntax:
"triggers": [
"<operation>: <action>"
]
Supported Operations:
create
: Triggered after a new document is createdupdate
: Triggered after an existing document is updateddelete
: Triggered after a document is deleted
Example:
"triggers": [
"create: @TokenPlugin.transferWholeTokens(@TokenPlugin.USDC, @walletAddress, recipientAddress, amount)"
]
Plugins
Plugins extend the functionality of your policies. For example, the @TokenPlugin provides token-related actions.
TokenPlugin Actions:
@TokenPlugin.transferWholeTokens(tokenAddress, fromAddress, toAddress, amount)
@TokenPlugin.transfer(tokenAddress, fromAddress, toAddress, amountInWei)
Example Usage in Triggers:
"triggers": [
"create: @TokenPlugin.transferWholeTokens(@TokenPlugin.USDC, @walletAddress, 0xRecipientAddress, 1)"
]
Sample policy with nested paths:
{
"posts/$postId/comments/$commentId": {
"rules": {
"read": "@root/posts/$postId.createdBy == @walletAddress || @prevState.createdBy == @walletAddress",
"write": "@prevState == null && @newState.createdBy == @walletAddress"
},
"fields": {
"text": "Types.String",
"createdBy": "Types.Address"
}
}
}
Explanation:
Explanation:
- Read Rule: Allows reading if the user is the post owner or the comment creator.
- Write Rule: Allows creating a new comment if the user is the one making the request.
- Fields: Defines text and createdBy fields for on-chain storage.
Best Practices
-
Principle of Least Privilege: Start with the minimal permissions necessary and expand as needed.
-
Use Dynamic Segments: Leverage $variable in paths to make policies reusable.
-
Explicit Field Definitions: Always define fields and data types when using on-chain storage.
-
Validate Data: Use conditions in write rules to ensure data integrity.
-
Test Policies Thoroughly: Before deploying, test your policies to ensure they behave as expected.
-
Limit Triggers: Use triggers judiciously to avoid unnecessary complexity and potential performance issues.
-
Document Your Policies: Add comments within your JSON (if supported) or maintain separate documentation to explain complex rules.
Quick Reference
Allow Read to Everyone:
"read": "true"
Allow Write Only to Owner:
"write": "@newState.createdBy == @walletAddress"
Check for Non-Null Fields:
"@newState.text != null"
Prevent Updates or Deletes:
"write": "@prevState == null"
Use Triggers for Actions:
"triggers": [
"create: <action>"
]
Common Use Cases
User Authentication:
Allow users to read and write their own data:
"users/$userId": {
"rules": {
"read": "@walletAddress == $userId",
"write": "@walletAddress == $userId"
}
}
Public Data with Controlled Writes:
Allow everyone to read but restrict who can write:
"publicData/$id": {
"rules": {
"read": "true",
"write": "@walletAddress == 0xAdminAddress"
}
}
Feel free to refer back to this cheatsheet whenever you're crafting or updating your Tarobase policies. If you have any questions or need further assistance, don't hesitate to reach out in our discord community.