Patract Labs (https://patract.network) provides solutions for Polkadot's parachain smart contract ecosystem. Three weeks ago, we applied a treasury proposal for Redspot v0.1. Here is a youtube video for overall demonstration. Now, we have finished all the features on time. We ask the councillors to check our work and give feedbacks. Welcome to our riot room to talk about smart contract development.
Redspot is inspired by Ethereum's Truffle. Redspot is a development environment, testing framework and asset pipeline for pallet-contracts. Redspot is trying to let the development of ink! be projectized and simplify the testing and interacting with contracts. The source code is in https://github.com/patractlabs/redspot.
Jupiter is a long term Substrate testnet, dedicated in WASM smart contract development. We also host a public node in develop mode for deploying and testing smart contract. The source code is in https://github.com/patractlabs/jupiter.
Except the requirements in the proposal, we have provided an objectified way to operate with contracts, which has not been implemented in Polkadot-js SDK yet. For more information, please check out contractApi. Most of the requirements are finished, expect some issues because ink! is a little unstable.
Redspot's migration
and test
can be used just like web3.js. Developer can write scripts like this rather than using raw call
to build raw extrinsic or RPC parameters.
// contractApi can be obtained by contract.load and contract.deployed, it can call the methods of the contract.
// It calls the balanceOf method of the contract and returns the corresponding type by rpc.
contractApi.messages.balanceOf(Alice.publicKey).call(<option>)
// It sends a contract transfer to the chain and get a Result type.
contractApi.messages.transfer(Bob.publicKey, '100000').send(<option>)
And then, We will show you the details about how Redspot works:
Currently, Redspot only support macOS and Linux, without Windows (waiting for ink! to support).
Now, let's assume that you are a new developer for pallet-contracts
. You know nothing about Substrate, hasn't prepared the developing environment for contracts. But, you had read some guides or cookbooks, and known a little about ink!. Then, you try to write WASM contracts for pallet-contracts
.
Just follow us to use Redspot and build your own contracts!
You do not need to clone Redspot project, just need to check whether there is a npx
command on your machine.
npx
is a package running tool that comes withnpm
5.2+ and higher, it ensures that you always install the latest version.if you don't have
npx
command, just donpm install -g npx
If you have installed npx
, you must already have npm
, or you could install yarn
command, which is also what we recommend to use.
Install and use Redspot to pull a contract project template
npx redspot-new <app-name> --template <template-name>
npx
would automatically download the newest redspot-now
on your machine, and could use it in any place. So, you do not need to compile or build Redspot project.
For example, if you want to create a contract project named myerc20
and use the erc20 template as initial contract project framework, you could use the following command:
npx redspot-new myerc20 --template erc20
If you don't add --template
, Redspot would use flipper
as default template.
Awesome, the myerc20
is your own contract project, you could start developing contracts from now!
$ npx Redspot-new myerc20 --template erc20
npx: installed 43 in 2.664s
✨ Creating a new Project in /myerc20.
Installing packages. This might take a while.
yarn add v1.22.5
info No lockfile found.
[1/4] Resolving packages...
# ...
Done in 2.80s.
🎉 Success! Created myerc20 at /myerc20
👉 Inside that directory, you can run several commands to help you develop the contract:
yarn build
Compile the contract.
yarn test
Test the contract.
yarn Migrate
Migrate the contract
Then, there is a template contract project in you current directory.
The directory structure is similar with the directory that truffle generated, including migartions
, tests
, Redspot-config.js
and so on. But currently, We can't support a contracts
directory due to ink!
's limit. After ink!
become stable in the future, we will move all the contracts into contracts
directory and organise contracts. About more information, please refer to this ink Issue.
Same with Truffle, the config file Redspot-config.js
is the most important file in the project, which would let Redspot to identity the contract project.
If you want to know more about config file, please refer to Project config.
For the project structure, please refer to Directory tree.
Now, lib.rs
is your contract file in your directory.
This file will be changed in the future. You can just write you custom contract logic in it. For more information, please refer to ink!
, and we advice new developers to look through all example in ink!
.
Compile your contract!
In the current directory, you could use those commands to compile you contract:
npm run build
# or
yarn build
That means you could use npm run
or yarn
to do the same operation. Later, we will use yarn
to represent all cases for npm run
However you may haven't installed contract compile toolchain, then you would get:
$ npm run build
> [email protected] build /myerc20
> Redspot build
/bin/sh: 1: cargo: not found
ERROR: No `cargo-contract` found
Run the following command to install it:
$ cargo install --git https://github.com/paritytech/cargo-contract cargo-contract --force
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `Redspot build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2020-09-11T10_03_43_152Z-debug.log
Currently we just print some errors to advice developers to download toolchain, because ink!
and cargo-contract
is not stable now. In the future, we would automatically download all toolchains and install them, without bothering developers.
After installing all toolchains, you could continue following steps.
If compilation is done, you could get the artifacts in artifacts
directory.
$ yarn build
yarn run v1.22.4
$ Redspot build
✨ Detect contracts: erc20(/.../.../myerc20/Cargo.toml)
===== Compile erc20 =====
cargo +nightly contract build
[1/3] Building cargo project
Compiling serde_derive v1.0.116
# ...
Compiling erc20 v2.1.0 (/tmp/cargo-contract_OOAxF6)
Finished release [optimized] target(s) in 14.86s
[2/3] Post processing wasm file
[3/3] Optimizing wasm file
Original wasm size: 59.8K, Optimized: 37.6K
Your contract is ready. You can find it here:
/.../.../erc20/target/erc20.wasm
===== Generate metadata erc20 =====
cargo +nightly contract generate-metadata
Generating metadata
[1/3] Building cargo project
Finished release [optimized] target(s) in 0.03s
[2/3] Post processing wasm file
[3/3] Optimizing wasm file
Original wasm size: 59.8K, Optimized: 37.6K
Updating git repository `https://github.com/paritytech/ink`
Updating crates.io index
Compiling serde v1.0.116
# ...
Compiling metadata-gen v0.1.0 (/tmp/cargo-contract_VQK5N3/.ink/metadata_gen)
Finished release [optimized] target(s) in 21.21s
Running `target/release/metadata-gen`
Your metadata file is ready.
You can find it here:
/.../.../myerc20/target/metadata.json
🚚 Copy wasm files: erc20.wasm
🚚 Copy abi files: metadata.json
🎉 Compile successfully! You can find them at /.../.../myerc20/artifacts
Done in 59.94s.
In our case, the artifacts
directory contains:
artifacts
|- erc20.json
|- erc20.wasm
Deploy your contracts.
After development, it's time to deploy you contracts. But before your deployment, please checkout Redspot-config.js
.
module.exports = {
outDir: './artifacts',
networks: {
// this is the network config, same to truffle, the migaration/test command would connect network dependent on this config.
development: {
// `types` is related to connected chain, this is important for polkadot.js
types: {
Address: "AccountId",
LookupSource: "AccountId",
},
//`prefix` is the ss58check Version for chain address, this would affect the scripts in migrations/tests
prefix: 42,
endpoints: ['ws://127.0.0.1:9944'], // please check endpoints, it's the websocket address for blockchain
// accounts is the key pair for migrations/tests
accounts: [
{
name: 'alice',
publicKey: '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d',
secretKey: '0x98319d4ff8a9508c4bb0cf0b5a78d760a0b2082c02775e6e82370816fedfff48925a225d97aa00682d6a59b95b18780c10d7032336e88f3442b42361f4a66011',
},
// ...
],
},
},
};
networks
is as same as Truffle, will be used when set --network
parameter for migaration/test commands.
However, developers should be concerned with types
and prefix
. Those two parts are related to the connected blockchain. For example, If you want to connect with polkadot mainnet work, you should set types
as {}
and set prefix
as 1
. If you want to connect with a custom Substrate blockchain, I should set types
and prefix
to matching value. For the types, please refer to this link.
We recommend developers to use "Jupiter" as the testnet, because Jupiter contains a node in develop mode, which doesn't need interval time to produce blocks. This feature will save lot of time for developing contracts.
Note: if you use Jupiter as the testnet, please make sure the
types
is the correct json.
If we assume the node is running on your machine, now you could deploy the myerc20 contract by doing yarn migarate
:
$ yarn migrate
yarn run v1.22.4
$ Redspot migrate
👉 Running migration: 1_deploy_contracts.js
===== PutCode erc20 =====
WasmCode: 0x0061736d01000000015f1060027f7f......000006000000070041b080040b0102
➤ erc20 codeHash: 0x9e05d9d5119b97343e69ed8ca68182639242c278ba04a753c36eeb44ba760fb1
===== Instantiate erc20 =====
Endowment: 50000000000
GasRequired: 100000000000
CodeHash: 0x9e05d9d5119b97343e69ed8ca68182639242c278ba04a753c36eeb44ba760fb1
InputData: 80,65,230,145,252,0,0,100,167,179,182,224,13,0,0,0,0,0,0,0,0
➤ erc20 contract address: 5D2z2wBACmwVCFBzSGjWbEhtQnxQuFiJNXoEJZeMyzeDd1rk
Done in 1.73s.
Please notice that this command would automatically find the WASM file in artifacts
directory, find the deploy script in migarations
directory, and executive it. The node where the WASM would be deployed is the endpoint
in Redspot-config.js
file.
Test your contracts.
The most important thing in contract development is testing. ink!
has already provided a way to write unit case to test contracts. However, simple unit test can't cover many complex situations, like multiple contracts project, the contracts related to block height, and so on. Thus, there must be a way for integration testing.
yarn test
is the command for contract integration test. It would execute all scripts in tests
directory.
Please notice that the default logic for contract address determiner is currently dependent on code_hash
, data_hash
and origin
(refer to SimpleAddressDeterminer
), so that using same code and same init data from same sender could only instantiate
once for a contract, so that the testing scripts should be careful to handle instantiate
(meaning deploy a contract) , like using different sender in different tests or using same deployed contract address when the contract could call more than once.
Redspot hasn't implemented the same feature yet, which is like migration.sol
in truffle, so Redspot can't automatically distinguish whether current contract has already been deployed. In the future, we would support this feature to help testing and instantiating (deploying).
But now, if the tests are not complex, developers could start blockchain node using --tmp
parameter. This parameter would start new chain without old data, thus developers could restart the blockchain node each time when they test.
objectified way to operate contracts
Developer could use an objectified way to operate contracts in migarate
and test
scripts. In the future, this feature could be used in interactive console. Currently, we show an example like this:
// load contractApi from artifacts, this would auto parse information from contract abi file
const erc20 = artifacts.require('erc20');
test('contract test', async () => {
const Alice = config.pairs[0];
const Bob = config.pairs[1];
// call put_code in low level (note currently if upload same code would not cause extrinsic failed)
const code_hash = await erc20.putCode(Alice);
const erc20Api = await erc20.deployed(
Alice,
code_hash,
erc20.abi.constructors[0]('1000000000000000016'), // instantiate parameters
"50000000000", // endowment
"100000000000" // gas limit
);
// call rpc `call` to run contracts and get value
const totalSupply = await erc20Api.messages.totalSupply().call();
// create an extrinsic and wait to block to pack and return the result of extrinsic result.
const transferResult = await erc20Api.messages.transfer(Bob.publicKey, '100000').send({
from: Alice,
gasLimit:"100000000000",
});
}
From the example, we could see that developers do not need to care about how to parse ABI files and build call parameters, just operate a contract like an object.
As we described above, we have implemented all features required in the proposal. Except some issues due to the unstable ink!
. Redspot could achieve a basic contract developing framework like how Truffle does in Ethereum. Maybe some features need to be improved. But currently, Redspot is a complete tool framework which could help developers to improve developing process for contracts.
We hope all contract developers could benefit from Redspot!
We will apply a new detailed proposal for Redspot v0.2. Briefly, we will add a migrations framework to control whether a contracts has beed deployed. We will find a way to solve repeat instantiate and do not need to restart the blockchain. We will provide an interactive console for directly interact with contract.
We will apply a new detailed proposal for Europa v0.1 (firstly introduced in Post #15). Europa is a sandbox of Substrate runtime environment, which would be used to simplify the developing, debugging, and integration test when developers develop Substrate runtime applications and test pallet-contracts. We will provide an independent runtime execution environment, allowing developers to use some special operation to operate the blockchain, like "jump to height" and "revert to height". We will provide an independent database for blockchain to establish other indexes, like index for extrinics. We will export stored key/value directly.