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.
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-rosetta
for 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
- 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
,ReadAction
andReadResponse
, each of it includes structs with specific definitons (e.g.Balance
struct), it also containsActionResult
andHandlerResult
enums - 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-pack
during 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
handle
function 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
If you want to edit contract's code and create your own implementation you can do it by following these steps:
- Edit
init-state.json
by 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
handle
function in contract/implementation/src/contract.rs
An example of how to access imports can be found here: contract/implementation/src/contract.rs
An example of how to read other contract state can be found here: contract/implementation/src/actions/foreign_read.rs
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
Compile your contract to WASM binary by running following command:
yarn build
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
writeInteraction
method 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.
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 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.
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