Account Authorization using Soroban AssemblyScript SDK
darkvallen
Posted on March 30, 2023
Hi! In my previous posts, i already covered many things such as storing data, logging contract, and defining error code. In this post I will take it to the next level, authorization. Authorization is one of security measure used in smart contracts, it can be used to various things such as allowing specific verified users to call a function, allowing specific users access stored data, and many more.
In this post i will explain Account authorization smart contract example that implements authorization control and updating account values stored in chain state.
The Contract Code
The contract code will be similar to my previous post with additional code to do account authorization. Let's dive into the code:
import {AddressObject, MapObject, RawVal, fromU32, toU32} from 'as-soroban-sdk/lib/value';
import {Map} from 'as-soroban-sdk/lib/map';
import * as ledger from 'as-soroban-sdk/lib/ledger';
import * as address from 'as-soroban-sdk/lib/address';
In this section, we import the necessary modules from the as-soroban-sdk
library. The ledger module provides functions for interacting with the blockchain's storage. The RawVal
, toU32
, fromU32
, AddressObject
, and MapObject
type is imported from the value module. Map
imported from map module to act as stored data format. ledger and address module imported for any operation regarding ledger dan address operations.
export function increment(user: AddressObject, value: RawVal): MapObject {
address.requireAuth(user);
var counter = 0;
if (ledger.hasData(user)) {
let dataValue = ledger.getData(user);
counter = toU32(dataValue);
}
counter += toU32(value);
let counterVal = fromU32(counter);
ledger.putData(user, counterVal);
let map = new Map();
map.put(user, counterVal);
return map.getHostObject();
}
The purpose of this function is to increment a counter associated with a given user's address in the Soroban ledger. The address.requireAuth(user)
call at the beginning of the function ensures that the user has authorized the transaction before it can proceed.
The next block of code checks whether the user already has data associated with their address in the ledger using the ledger.hasData(user)
function. If the user has data, it retrieves the current value of the counter using ledger.getData(user)
and converts it to a 32-bit unsigned integer using the toU32
function. If the user does not have data, the counter is initialized to zero.
The counter variable is then incremented by the value of value, which is also converted to a 32-bit unsigned integer using toU32
. The updated value of counter is then converted back to a RawVal value using fromU32
and stored in the ledger using the ledger.putData(user, counterVal)
function.
Finally, a new Map
is created and the updated counter value is added to it using map.put(user, counterVal)
. The Map is then returned as a MapObject
using map.getHostObject()
.
Next, create contract.json
file in your project directory, this file contains metadata for the contract.
{
"name": "Store and Retrieve Data Contract (Account Auth)",
"version": "0.1.0",
"description": "example",
"host_functions_version": 29,
"functions": [
{
"name" : "increment",
"arguments": [
{"name": "user", "type": "address"},
{"name": "value", "type": "u32"}
],
"returns" : "map[address, u32]"
}
]
}
Before compiling the contract, we need to edit the asconfig.json
file of your project. Replace its content with the following:
{
"extends": "as-soroban-sdk/sdkasconfig",
"targets": {
"release": {
"outFile": "build/release.wasm",
"textFile": "build/release.wat"
},
"debug": {
"outFile": "build/debug.wasm",
"textFile": "build/debug.wat"
}
}
}
The asconfig.json
file is used by the AssemblyScript compiler (asc) to define the configuration for your project.
Compiling the Contract
You need to compile it into WebAssembly first. To do this, you'll use the following command :
npx asc assembly/index.ts --target release
Now you should see two new files in the build/ directory: release.wasm
and release.wat
.
We will use 2 different account to invoke this contract.Let's run the contract to see if it's works, we're gonna run the contract using soroban-cli
on sandbox using the following command :
soroban contract invoke \
--account GABGWMODVCF3VQS5BYCJBWMJUIS466Q3WT3AKGZZAKLBW2NYHIWOEYQT \
--id 1 \
--wasm build/release.wasm \
--fn increment \
-- \
--user GABGWMODVCF3VQS5BYCJBWMJUIS466Q3WT3AKGZZAKLBW2NYHIWOEYQT \
--value 10
You can run it a couple of times with any desired --value
. And invoke the function using another account :
soroban contract invoke \
--account GBYXXOAIKZJHZKGR4W7ERYWLAJDEYIPQJNETH6FGFIJUUB4PBVPISTNL \
--id 1 \
--wasm build/release.wasm \
--fn increment \
-- \
--user GBYXXOAIKZJHZKGR4W7ERYWLAJDEYIPQJNETH6FGFIJUUB4PBVPISTNL \
--value 5
And after couple of times invoking the function with 2 different accounts, you can check all stored data on that contract using this command:
soroban contract read --id 1
You should get similar output to:
"""GABGWMODVCF3VQS5BYCJBWMJUIS466Q3WT3AKGZZAKLBW2NYHIWOEYQT""",15
"""GBYXXOAIKZJHZKGR4W7ERYWLAJDEYIPQJNETH6FGFIJUUB4PBVPISTNL""",25
Closing
Overall, this code provides a simple example of how Account Authorization works using the AssemblyScript SDK. By using the address.requireAuth
and address.requireAuthForArgs
functions, this code ensures that only authorized users can modify the counter associated with their address. Happy Sorobaning!
Posted on March 30, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.