8.5 KiB
🦀 Warp contracts - Rust template
Following repository is a template for writing SmartWeave contracts in Rust and building them into WASM binaries which can be then processed by Warp SDK.
It contains an example implementation of a PST contract - which you can use as a base for implementing your own contract. If you are not familiar with the concept of Profit Sharing Tokens, check out a tutorial for writing your first PST contract in our Warp Academy.
📦 Installation
You will need:
- Rust :-) (https://doc.rust-lang.org/cargo/getting-started/installation.html)
- wasm-pack (on Apple's M1s you may need Rosetta
softwareupdate --install-rosettafor wasm-pack to run) - Node.js version 16.5 or above
- yarn installed
To install all Node.js dependencies run the following command:
yarn install
🔍 Code structure
- deploy/ - contains deployment scripts for localhost/testnet/mainnet and contract's initial state definition
- contract - contains definitions and implementation for the contract
- definition/ - contains contract definitions (e.g. actions, errors and state) which define shape of the contract, it also includes tools to generate JSON files from contract definition files
- action.rs - contains enums of the
WriteAction,ReadActionandReadResponse, each of it includes structs with specific definitons (e.g.Balancestruct), it also containsActionResultandHandlerResultenums - error.rs - contains the definition of contract's business errors (e.g. "not enough balance")
- generate_json.rs - tool to generate JSON schemas from the definitions
- state.rs - contains the definition of contract's state
- action.rs - contains enums of the
- implementation - contains implementation for the contract definitions, it will be compiled to WASM and used when deploying contract to the blockchain
- pkg/ - generated by
wasm-packduring build process - contains compiled wasm binary, js "glue" code, etc. - src/ - contains the source code of the contract implementing contract definitions
- actions/ - the main part of the contract - contains
actions(functions) that can be called to interact with the contract (and either change its internal state or return a view of the current state). These functions contain all the business logic of the contract - contract_utils/ - contains low-level code responsible for mapping types, storing state,
definition of functions imported from js, etc.
🔥Do Not Edit🔥, unless you really know what you're doing :-) - contract.rs - entry point (from the contract's developer perspective) to the contract.
Contains the
handlefunction that calls specific contract's functions based on passed action
- actions/ - the main part of the contract - contains
- pkg/ - generated by
- definition/ - contains contract definitions (e.g. actions, errors and state) which define shape of the contract, it also includes tools to generate JSON files from contract definition files
- tests/ - contains integration tests written in Jest
🧑💻 Writing contract
If you want to edit contract's code and create your own implementation you can do it by following these steps:
- Edit
init-state.jsonby adding the initial state for your contract - deploy/state/init-state.json - Modify the state definition of the contract - contract/definition/src/state.rs
- Edit/add actions which user will be able to call while interacting with the contract - contract/definiton/src/actions and contract/implementation/src/actions. We suggest keeping each action in a separate file.
- Add above action functions to the pattern matching in
handlefunction in contract/implementation/src/contract.rs
Accessing JavaScript imports
An example of how to access imports can be found here: contract/implementation/src/contract.rs
Foreign contract read
An example of how to read other contract state can be found here: contract/implementation/src/actions/foreign_read.rs
Foreign contract write
An example of how to call other contract function can be found here: contract/implementation/src/actions/foreign_write.rs
Keep in mind that internal contract writes require the flag internalWrites to be turned on in the
evaluation options (for both calling and callee contracts). See tests/contract.spec.ts.
In order to access the calling contract tx id - use SmartWeave::caller().
SmartWeave::caller() returns:
- same value as
Transaction::owner()- for standard interactions with contract - transaction id of the calling contract - in case of internal writes
👷 Build
Compile your contract to WASM binary by running following command:
yarn build
Typescript bindings
Rust contract definitions can be compiled to Typescript:
- Firstly JSON schemas are generated from Rust contract definitions using schemars.
- Then, JSON schemas are compiled to Typescript using json-schema-to-typescript.
- Lastly, a helper class is generated from typescript bindings which allows to easily interact with the contract. Instead of using
writeInteractionmethod each time, specific functions can be called within the contract, e.g.:
async transfer(transfer: Transfer, options?: WriteInteractionOptions): Promise<WriteInteractionResponse | null> {
return await this.contract.writeInteraction<BaseInput & Transfer>({ function: 'transfer', ...transfer }, options);
}
Generate JSON:
yarn gen-json
Compile JSON to Typescript:
yarn gen-ts
Gnerate JSON and compile to Typescript:
yarn gen-bindings
Files will be generated in contract/definition/bindings.
🧪 Tests
Write tests for your contract (we will use Jest library for testing) - you can find a template in the tests/ folder. Run tests with
yarn test
📜 Deploy
Deploy your contract to one of the networks (mainnet/Warp public testnet/localhost) by running following command (network: mainnet | testnet | local)
Please note that in case of local deployment, you need to have ArLocal instance running - npx arlocal.
yarn deploy:[network]
💡NOTE: If you want to deploy your contract locally you need to run Arlocal by typing following command:
npx arlocal
💡NOTE: When using mainnet please put your wallet key in deploy/mainnet/.secrets/wallet-mainnet.json. .secrets folder has been added to .gitignore so your key is kept securely.
You can view deploy script code here.
🟥 Using SDK
Optionally - you can run one of the scripts which uses Warp SDK to interact with the contract. Using SDKs' methods works exactly the same as in case of a regular JS contract.
💡NOTE You will need to have a file with the wallet key and a file with the contract id to run these scripts. If you do not have them please run a deploy script.
read- reads contract state, check out the code in deploy/scripts/read-contract-state.js
npm run read:[network]
balance- get balance for a wallet address, check out the code in deploy/scripts/interact-balance.js
npm run balance:[network]
transfer- transfer specific amount of tokens to the indicated wallet, check out the code in deploy/scripts/interact-transfer.js