Staking¶
Welcome to the Staking guide, your essential manual for leveraging the power of smart contracts in the Koinos ecosystem. This guide is designed to help developers and users understand the intricacies of creating and deploying staking smart contracts, which automate and enhance the staking process. By utilizing smart contracts, you can ensure secure, transparent, and efficient staking operations that maximize the potential of your tokens. Whether you are a seasoned developer or a newcomer eager to explore blockchain technology, this guide provides the knowledge and tools necessary to effectively utilize staking smart contracts on Koinos.
Before embarking on this journey, ensure that you have already setup your Koinos AssemblyScript SDK environment by following this guide.
Note
This guide does not create a new token, it only allows to you stake a pre-existing token. For a guide on launching a token you can folow the guide for that here.
Setting up the project¶
Let's begin by creating a boilerplate smart contract project using the Koinos AssemblyScript SDK.
koinos-sdk-as-cli create staking
Generating contract at "/home/$USER/Workspace/staking" ...
Contract successfully generated!
You're all set! Run the following set of commands to verify that the generated contract is correctly setup:
cd /home/$USER/Workspace/staking && yarn install && yarn build:debug && yarn test
Change your directory to the project directory and install dependencies.
cd staking
yarn install
yarn install v1.22.22
info No lockfile found.
[1/4] Resolving packages...
warning @koinos/sdk-as > @koinos/mock-vm > multibase@4.0.6: This module has been superseded by the multiformats module
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/ci-detect@2.0.0: this package has been deprecated, use `ci-info` instead
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > libnpmexec > @npmcli/ci-detect@2.0.0: this package has been deprecated, use `ci-info` instead
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/arborist > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/arborist > @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > cacache > @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > readdir-scoped-modules > debuglog@1.0.1: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
warning local-koinos > koilib > multibase@4.0.6: This module has been superseded by the multiformats module
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning "@koinos/sdk-as > @as-covers/core > @as-covers/transform > visitor-as@0.6.0" has incorrect peer dependency "assemblyscript@^0.18.31".
warning " > ts-node@10.9.2" has unmet peer dependency "@types/node@*".
warning Workspaces can only be enabled in private projects.
[4/4] Building fresh packages...
success Saved lockfile.
Done in 93.97s.
Defining methods and data¶
Constructing a smart contract typically involves defining both behaviors and data. The behavior is specified by the smart contract itself, while the data is defined using Protobuf. By generating data structures with Protobuf, we enable seamless integration of the smart contract with other Koinos tools. We have outlined the arguments and results required for our staking operations, following the convention of using *_arguments
for contract function arguments and *_result
for contract function results.
Let's begin by defining our entry point arguments and results.
vi assembly/proto/staking.proto
We can remove the boilerplate code and replace it with our standard staking arguments and results.
assembly/proto/staking.proto | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
Now that we have our Protobuf definition, let's generate our derived AssemblyScript code.
koinos-sdk-as-cli generate-contract-proto
Generating Contract AS proto files...
yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/*.proto
yarn run v1.22.22
$ /home/$USER/Workspace/staking/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/staking.proto
@protobuf-ts/protoc installed protoc v26.1.
Done in 20.43s.
❯ koinos-sdk-as-cli generate-contract-proto
Generating Contract AS proto files...
yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/*.proto
yarn run v1.22.22
$ /home/$USER/Workspace/staking/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/staking.proto
Done in 0.68s.
Note that after executing this command the file assembly/proto/staking.ts
was automatically generated and contains code that will assist us in serializing and deserializing data in and out of the KVM.
The implementation¶
Now, we have defined the data in which arguments come into our contract and also the data which is returned by our contract. All we need now is our implementation.
Because our smart contracts utilizes disk storage to keep track of tokens that are staked, let's create a new file called State.ts
that defines how save and retrieve data from disk.
vi assembly/State.ts
And we'll add the following implementation.
assembly/State.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Let's use the tools to automatically generate the boilerplate implementation.
koinos-sdk-as-cli generate-contract-as staking.proto
Generating boilerplate.ts and index.ts files...
yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/Staking.proto
yarn run v1.22.22
$ /home/$USER/Workspace/staking/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/Staking.proto
Done in 0.94s.
After invoking this command, we have two newly generated files. The first is assembly/index.ts
which is the first location our smart contract codes begin executing. This file acts as a router to call the appropriate method on our class based on how the smart contract was invoked.
The second file that was generated is assembly/Staking.boilerplate.ts
. This is where our implementation lives. We should rename this file to Staking.ts
and begin our implementation.
rm assembly/Staking.ts
mv assembly/Staking.boilerplate.ts assembly/Staking.ts
vi assembly/Staking.ts
Finally, let's open our implementation file and write some simple arithmetic to complete our Staking's functionality.
Note
The TOKEN_CONTRACT_ID
is a variable that defines the token that can be staked in this contract. To launch your own token you can follow the guide here.
assembly/Staking.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
|
And finally, we build it.
koinos-sdk-as-cli build debug 0
Compiling index.ts...
node ./node_modules/assemblyscript/bin/asc assembly/index.ts --target debug --use abort= --use BUILD_FOR_TESTING=0 --disable sign-extension --config asconfig.json
Time for tests¶
All code needs tests. The most basic form of a testing is, of course, unit tests. Let's use the built-in unit test system to exercise our staking code.
Let's open up assembly/__tests__/Staking.spec.ts
and write some tests.
vi assembly/__tests__/Staking.spec.ts
Let's add the following test code.
assembly/__tests__/Staking.spec.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
Ok, let's run it and see what happens.
koinos-sdk-as-cli run-tests
Running tests...
yarn asp --verbose --config as-pect.config.js
yarn run v1.22.22
$ /home/sgerbino/Workspace/staking/node_modules/.bin/asp --verbose --config as-pect.config.js
___ _____ __
/ | / ___/ ____ ___ _____/ /_
/ /| | \__ \______/ __ \/ _ \/ ___/ __/
/ ___ |___/ /_____/ /_/ / __/ /__/ /_
/_/ |_/____/ / .___/\___/\___/\__/
/_/
⚡AS-pect⚡ Test suite runner [6.2.4]
[Log] Loading asc compiler
Assemblyscript Folder:assemblyscript
[Log] Compiler loaded in 193.08ms.
[Log] Using configuration /home/sgerbino/Workspace/staking/as-pect.config.js
[Log] Using VerboseReporter
[Log] Including files: assembly/__tests__/**/*.spec.ts
[Log] Running tests that match: (:?)
[Log] Running groups that match: (:?)
[Log] Effective command line args:
[TestFile.ts] node_modules/@as-pect/assembly/assembly/index.ts --runtime incremental --debug --binaryFile output.wasm --explicitStart --use ASC_RTRACE=1 --exportTable --importMemory --transform /home/sgerbino/Workspace/staking/node_modules/@as-covers/transform/lib/index.js,/home/sgerbino/Workspace/staking/node_modules/@as-pect/core/lib/transform/index.js --lib node_modules/@as-covers/assembly/index.ts
[Describe]: staking
[Event] staking.stake / [ '1DQzuCcTKacbs9GGScRTU1Hc8BsyARTPqG' ] / ChkAiCtotTmdMTyQZ/OEFgfmKMEtVCA8jEc3EAo=
[Success]: ✔ should stake tokens RTrace: +101
[File]: assembly/__tests__/Staking.spec.ts
[Groups]: 2 pass, 2 total
[Result]: ✔ PASS
[Snapshot]: 0 total, 0 added, 0 removed, 0 different
[Summary]: 1 pass, 0 fail, 1 total
[Time]: 26.635ms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Result]: ✔ PASS
[Files]: 1 total
[Groups]: 2 count, 2 pass
[Tests]: 1 pass, 0 fail, 1 total
[Time]: 3574.229ms
┌─────────────────────┬───────┬───────┬───────┬──────┬──────────────────────────────────┐
│ File │ Total │ Block │ Func │ Expr │ Uncovered │
├─────────────────────┼───────┼───────┼───────┼──────┼──────────────────────────────────┤
│ assembly/Staking.ts │ 54.5% │ 42.9% │ 75% │ N/A │ 39:66, 60:71, 68:39, 74:66, 60:3 │
├─────────────────────┼───────┼───────┼───────┼──────┼──────────────────────────────────┤
│ assembly/State.ts │ 100% │ 100% │ 100% │ N/A │ │
├─────────────────────┼───────┼───────┼───────┼──────┼──────────────────────────────────┤
│ total │ 72.2% │ 63.6% │ 85.7% │ N/A │ │
└─────────────────────┴───────┴───────┴───────┴──────┴──────────────────────────────────┘
Done in 3.78s.
Excellent, you have written a simple staking smart contract with custom data types and methods with unit tests! Well done!