Authority¶
Welcome to the contract authority guide. In this guide, we will explore how to use Koinos smart contracts to implement custom authorization logic for a smart contract or a wallet. Understanding the authority system can help you better secure your smart contracts by defining the exact logic you need for authorized access.
Before embarking on this journey, ensure that you have already setup your Koinos AssemblyScript SDK environment by following this guide.
It will also help for you to be familiar with the Koinos authority system, which you can read about 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 authority
Generating contract at "/home/$USER/Workspace/authority" ...
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/authority && yarn install && yarn build:debug && yarn test
Change your directory to the project directory and install dependencies.
cd authority
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 62.51s.
Generating the authorize stubs¶
Because we are creating an authority contract we will invoke the koinos-sdk-as-cli
in order to stub out the implementation for us. We do not need the boilerplate "Hello World" implementation in assembly/authority/proto/authority.proto
and assembly/Authority.ts
.
We will start by removing it from assembly/authority/proto/authority.proto
.
assembly/authority/proto/authority.proto | |
---|---|
1 2 3 |
|
koinos-sdk-as-cli generate-contract-as --generate_authorize authority.proto
Generating boilerplate.ts and index.ts files...
GENERATE_AUTHORIZE_ENTRY_POINT=1 yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/authority.proto
yarn run v1.22.22
$ /home/$USER/Workspace/authority/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/authority.proto
@protobuf-ts/protoc installed protoc v26.1.
Done in 5.07s.
In the following code snippets the highlighted lines were added by the previous invocation.
assembly/index.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 |
|
assembly/Authority.boilerplate.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
When we originally created this smart contract, we were given an example implementation of Hello World. We no longer need that, so let's copy the boilerplate over the original contract.
rm rm assembly/Authority.ts
mv assembly/Authority.boilerplate.ts assembly/Authority.ts
Now we move on to the crux of the matter, implementing our authority override!
The implementation¶
For this guide, we will implement a 2 of 3 multi-signature wallet. The wallet will look for signatures on 3 keys and authorize the transaction if 2 of the 3 keys have signed the transaction. This is a simple example, but explains how more complex authorization schemes could be built using this system.
Open up your implementation file.
vi assembly/Authority.ts
To accomplish this, we will check the authority of each of our addresses. By default, this will simply check if they have signed the transaction. If they also have authority overrides, those will be called automatically on our behalf.
This example contract has certain addresses hardcoded. You can replace those addresses with addresses of your own.
assembly/Authority.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 |
|
Building the contract¶
Great! It's time to build our contract.
First, we need to generate the assembly script from the proto file. While the proto file does not define any new types, the generated files still expect this file to exist. Skipping this step will cause the build to fail without further modifications.
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/authority/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/authority.proto
Done in 0.21s.
Next, we can build the actual contract.
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¶
We need to start by cleaning up the tests given to use with the "Hello World" example. Go ahead and delete all of the contents of the existing test at assembly/__tests__/Authority.spec.ts
.
Now we need to test that our authorize()
function works in all cases. Testing a 2 or 3 multisig is not hard to exhaust all cases, which is what we will do.
vi assembly/__tests__/Authority.spec.ts
assembly/__tests__/Authority.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 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 |
|
And finally, let's run our tests.
koinos-sdk-as-cli run-tests
Running tests...
yarn asp --verbose --config as-pect.config.js
yarn run v1.22.22
$ /home/$USER/Workspace/authority/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 182.741ms.
[Log] Using configuration /home/$USER/Workspace/authority/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/$USER/Workspace/authority/node_modules/@as-covers/transform/lib/index.js,/home/$USER/Workspace/authority/node_modules/@as-pect/core/lib/transform/index.js --lib node_modules/@as-covers/assembly/index.ts
[Describe]: contract
[Success]: ✔ should not authorize with one signature RTrace: +677
[Success]: ✔ should authorize with two correct signatures RTrace: +511
[Success]: ✔ should not authorize with one correct and one incorrect signatures RTrace: +511
[Success]: ✔ should authorize with three correct signatures RTrace: +172
[Success]: ✔ should authorize with two correct and one incorrect signatures RTrace: +514
[File]: assembly/__tests__/Authority.spec.ts
[Groups]: 2 pass, 2 total
[Result]: ✔ PASS
[Snapshot]: 0 total, 0 added, 0 removed, 0 different
[Summary]: 5 pass, 0 fail, 5 total
[Time]: 67.959ms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Result]: ✔ PASS
[Files]: 1 total
[Groups]: 2 count, 2 pass
[Tests]: 5 pass, 0 fail, 5 total
[Time]: 2506.885ms
┌───────────────────────┬───────┬───────┬──────┬──────┬───────────┐
│ File │ Total │ Block │ Func │ Expr │ Uncovered │
├───────────────────────┼───────┼───────┼──────┼──────┼───────────┤
│ assembly/Authority.ts │ 100% │ 100% │ 100% │ N/A │ │
├───────────────────────┼───────┼───────┼──────┼──────┼───────────┤
│ total │ 100% │ 100% │ 100% │ N/A │ │
└───────────────────────┴───────┴───────┴──────┴──────┴───────────┘
Done in 2.61s.
Great job! You now have a contract that implements a 2 of 3 multisig!
Note
It is not enough to just implement authorize()
in your smart contract. You must indicate that you are overriding the authorize()
function when uploading your smart contract. For details and examples of how this works check out the Authority: Uploading the contract section.
For more information on uploading contracts, visit the Deploying a contract.