Skip to content

Commit

Permalink
Merge pull request #165 from realiotech/add-asset-spec
Browse files Browse the repository at this point in the history
feat!: Draft asset module spec
  • Loading branch information
catShaark authored Jul 9, 2024
2 parents 021d825 + cd7a9a2 commit 4fee34b
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 115 deletions.
1 change: 1 addition & 0 deletions x/asset/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier {
// RegisterServices registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}

Expand Down
26 changes: 6 additions & 20 deletions x/asset/spec/01_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,14 @@ order: 1

## The Realio Asset Token Model

The Realio Asset module is centeredd aroumd a token model. It contains the following fields:
The Realio Asset module is centered around a token model where certain whitelisted accounts can issue their own token. A token issued by this module will be managed by a set of privileged accounts. These privileged accounts are assigned by its manager (either an account or a module/contract).

```protobuf
message Token {
string name = 1;
string symbol = 2;
int64 total = 3;
int64 decimals = 4;
bool authorizationRequired = 5;
string creator = 6;
map<string, TokenAuthorization> authorized = 7;
int64 created = 8;
}
### System of privileged accounts

```

### Token Authorization

The `Token` model provides a means to whitelist users via the `authorizationRequired` and `authorized` fields
A token that has the `authorizationRequired` turned on, can maintain a whitelist map of user addresses. These addresses
are the only ones able to send/receive the token. The Realio Network is agnostic to the logic of applications that use
the whitelisting. It is up to the clients to determine when to whitelist and what to do with it.
Privileged accounts of a token are accounts that can execute certain actions for that token. There're are several types of privileges, each has its own logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these privileges from the `Asset module` logic, meaning that privileges will be defined in separate packages/modules, thus, developers can customize their type of privilege without modifying the `Asset Module`. Doing this allows our privileges system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our privileges system.

In order for a privilege to integrate into the `Asset Module`. It has to implement the `Privilege` interface and has its implementation registered via the method `AddPrivilege`. Once that is done, we can make said privilege available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process.

It's important to note that the token manager can choose what privileges it wants to disable for its token Which is specified by the token manager when creating the token. After creating the token, all the enabled privileges will be assigned to the token manager in default but the token manager can assign privileges to different accounts later on.

We have already defined basic privileges: "mint", "freeze", "clawback", "transfer_auth". These privileges will be included in the default settings of the module.
59 changes: 32 additions & 27 deletions x/asset/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,50 @@ order: 2

# State

## State Objects
## Store

The `x/asset` module keeps the following objects in state:
### Token Store

| State Object | Description | Key | Value | Store |
|----------------------|--------------------------------|--------------------------| --------------- |-------|
| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV |
| `TokenAuthorization` | Token Authorization bytecode | `[]byte{2} + []byte(id)` | `[]byte(id)` | KV |

### Token

Allows creation of tokens with optional user authorization.
Map: `0x00 | {Token ID} -> Token`

```go
type Token struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"`
Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"`
Decimals int64 `protobuf:"varint,4,opt,name=decimals,proto3" json:"decimals,omitempty"`
AuthorizationRequired bool `protobuf:"varint,5,opt,name=authorizationRequired,proto3" json:"authorizationRequired,omitempty"`
Creator string `protobuf:"bytes,6,opt,name=creator,proto3" json:"creator,omitempty"`
Authorized map[string]*TokenAuthorization `protobuf:"bytes,7,rep,name=authorized,proto3" json:"authorized,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Created int64 `protobuf:"varint,8,opt,name=created,proto3" json:"created,omitempty"`
Name string
Symbol string
Decimal string
Description string
}
```

### Token Authorization
Note that these infos are also stored in the `metadata` store of bank module.

### Token Management

Map: `0x01 | {Token ID} -> TokenManagement`

Token management holds these information about the token:

A Token authorization struct represents a single addresses current authorization state for a token
* the token's manager
* the excluded privileges (privileges that are permenantly disable)
* if we can add newly introduced privilege to the token later on

```go
type TokenAuthorization struct {
TokenSymbol string `protobuf:"bytes,1,opt,name=tokenSymbol,proto3" json:"tokenSymbol,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Authorized bool `protobuf:"varint,3,opt,name=authorized,proto3" json:"authorized,omitempty"`
type TokenManagement struct {
Manager string
AddNewPrivilege bool
ExcludedPrivileges []string
}
```

### Privileged Accounts

Map: `0x02 | {Token ID} | {Privilege Name} -> Addresses`

### Privilege Store

Sub stores: `0x03 | {Token ID} | {Privilege Name}`

Since each type of privilege has its own logic, we need to leave a seprate space for each of them to store their data. A privilege should manage its own store provided by the asset module, prefixed with `0x03 | {Token ID} | {Privilege Name}`

## Genesis State

Expand All @@ -51,7 +56,7 @@ The `x/asset` module's `GenesisState` defines the state necessary for initializi
```go
// GenesisState defines the module's genesis state.
type GenesisState struct {
Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"`
PortId string `protobuf:"bytes,2,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"`
Params Params
Tokens []Token
}
```
```
12 changes: 7 additions & 5 deletions x/asset/spec/03_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ order: 3

The asset module contains the following parameters:

| Key | Type | Example |
|---------------|-----------------|------------------------|
| port | string | "ario" |
| InflationRate | string (dec) | "0.130000000000000000" |
| BlocksPerYear | string (uint64) | "6311520" |
| Key | Type | Example |
|------------|----------|-----------------|
| Privileges | []string | "freeze","mint" |

## Details

- Privileges: refers to the privileges that is enabled for our privilege system. Everytime a new type of privilege is introduced, we will update this param to include it.
37 changes: 0 additions & 37 deletions x/asset/spec/04_events.md

This file was deleted.

90 changes: 90 additions & 0 deletions x/asset/spec/04_messages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!--
order: 4
-->

# Messages

The asset module exposes the following messages:

## MessageCreateToken

```go
type MsgCreateToken struct {
Creator string
Manager string
Name string
Symbol string
Decimal string
ExcludedPrivileges []string
AddNewPrivileges bool
}
```

`MessageCreateToken` allows a whitelisted account to create a token with custom configuration.

## MessageAllocateToken

```go
type MsgAllocateToken struct {
Manager string
TokenID string
Balances []Balance
VestingBalances []VestingAccount
}
```

`MessageAllocateToken` can only be executed by the token manager once after their token is successfully created. It will allocate tokens (either vesting or liquid) to the list of accounts sepecifed in the message.

## MessageAssignPrivilege

```go
type MsgAssignPrivilege struct {
Manager string
TokenID string
AssignedTo []string
Privilege string
}
```

`MessageAssignPrivilege` allows the token manager to assign a privilege to the chosen addresses. This message will fail if the privilege is in the list of `ExcludedPrivileges` specified when creating the token.

## MessageUnassignPrivilege

```go
type MsgUnassignPrivilege struct {
Manager string
TokenID string
UnassignedFrom []string
Privilege string
}
```

`MessageUnassignPrivilege` allows the token manager to unassign a privilege from the chosen addresses.

## MessageDisablePrivilege

```go
type MsgDisablePrivilege struct {
Manager string
TokenID string
DisabledPrivilege string
}
```

`MessageDisablePrivilege` allows the token manager to disable a privilege permanently, it will also unassigns all the accounts with that privilege.

## MessageExecutePrivilege

```go
type PrivilegeMsg interface {
NeedPrivilege() string
}

type MsgExecutePrivilege struct {
Address string
TokenID string
PrivilegeMsg PrivilegeMsg
}
```

`PrivilegeMsg` allows privileged accounts to execute logic of its privilege. For that reason, it has different implementations defined by each types of privilege instead of the `Asset Module`. These implementations and the logic to handle them are registered into the module via `RegisterPrivilege` method.
26 changes: 0 additions & 26 deletions x/asset/spec/05_client.md

This file was deleted.

13 changes: 13 additions & 0 deletions x/asset/spec/05_gov.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!--
order: 5
-->

# Gov proposals

The asset module supports the following types of gov proposals:

## TokenCreatorWhitelistProposal

This proposal allows the community to decide on what addresses are allowed to create token via the asset module.

These types of proposals is implemented as sdk.msg with respective handling methods following `gov.v1beta` standard.
63 changes: 63 additions & 0 deletions x/asset/spec/06_logic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!--
order: 6
-->

# Logic

This file describes the core logics in this module.

## Token creation process

This process is triggered by `MsgCreateToken`.

Validation:

- Check if `Creator` is whitelisted. We only allow some certain accounts to create tokens, these accounts is determined via gov proposal.
- Check if the token with the same denom has already existed.

Flow:

1. The denom for the token will be derived from `Creator` and `Symbol` with the format of `asset/{Creator}/{Symbol}`
2. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store
3. Save the token management info (`Manager`, `ExcludedPrivileges` and `AddNewPrivilege`) in the x/asset store.

Note that here we prefixed the token denom with the manager address in order to allow many different creators to create token with the same symbol, differentiate their denom by including in their creator.

## Register a privilege

To intergrate with the `asset module` Each type of privilege has to implement this interface

```go
type Privilege interface {
RegisterInterfaces()
MsgHandler() MsgHandler
QueryHandler() QueryHandler
CLI() *cobra.Command
}

type MsgHandler func(context Context, privMsg PrivilegeMsg) error

type QueryHandler func(context Context, privQuery PrivilegeQuery) error
```

This interface provides all the functionality necessary for a privilege, including a message handler, query handler and cli

All the `PrivilegeMsg` of a privilege should return the name of that privilege when called `NeedPrivilege()`. A message handler should handle all the `PrivilegeMsg` of that privilege.

When adding a `Privilege`, we calls `PrivilegeManager.AddPrivilege()` in `app.go` which inturn maps all the `PrivilegeMsg` of that privilege to its `MsgHandler`. This mapping logic will later be used when running a `MsgExecutePrivilege`

## Flow of MsgExecutePrivilege

This process is triggered by the `MsgExecutePrivilege`.

Validation:

- Checks if the token specified in the msg exists.
- Checks if the privilege is supported.
- Checks if the `Msg.Address` has the corresponding `Privilege` specified by `PrivilegeMsg.NeedPrivilege()`

Flow:

- Prepare store for the privilege of the token via `MakePrivilegeStore(privilege name, token denom)`. That store is the only store accessable by the privilege's `MsgHandler`.
- `PrivilegeManager` routes the `PrivilegeMsg` to the its `MsgHandler`.
- `MsgHandler` now handles the `PrivilegeMsg`.
Loading

0 comments on commit 4fee34b

Please sign in to comment.