-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from Wire-Network/edits-1
Added a few articles
- Loading branch information
Showing
12 changed files
with
934 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Deposits | ||
|
||
Before users can transact with tokens on the Wire network, their tokens must be ‘shadowed’ from the origin chain. Shadowing, also known as token wrapping, is creating a digital representation of a token from one blockchain on another. For example, Ethereum (ETH) on the Wire Network is represented as Wrapped Ethereum (WETH) to enable its use within that specific ecosystem. | ||
The deposit process involves *transferring the ownership of the tokens to a special escrow contract*, where they are held until the eventual recipient decides to claim them. This contract serves as the foundational mechanism for managing the *deposit root*, which is essential for tracking and verifying the deposits within the network. | ||
|
||
## Deposit Root | ||
|
||
The deposit root is a dynamic cryptographic hash used as a cumulative verification point within the escrow account on the external chain. | ||
|
||
- **Initialization and Update**: The deposit root is initialized with a deterministic value. Each transaction updates this root by hashing the transaction details with the existing deposit root value and incorporating a sequential identifier to ensure traceability. | ||
- **Proof Construction**: This updating mechanism facilitates the creation of a verifiable proof that includes the initial deposit root value, detailed transaction information, and all subsequent transaction hashes. | ||
Below is a detailed diagram of the deposit flow of operations: | ||
|
||
```mermaid | ||
sequenceDiagram | ||
autonumber | ||
participant User | ||
participant External Chain | ||
participant Validator | ||
participant Wire Network | ||
User->>Wire Network: Intent to deposit | ||
rect rgb(255, 210, 128) | ||
User -> Wire Network: amount/kind of token to be deposited <br/> the current deposit root on the origin chain <br/> the user's account on the origin chain <br/> the next sequential nonce for that user's account (if applicable) | ||
end | ||
%% alt Proposed deposit is valid | ||
Validator->>External Chain: Verifies | ||
Validator->>Validator: wait for acceptance | ||
Validator->>Wire Network: Acceptance | ||
User->>External Chain: Perform deposit | ||
External Chain->>External Chain: on_received() | ||
External Chain->>External Chain: Hash transaction details | ||
Note over External Chain,External Chain: - The sender (depositor)<br/>- contract address for the token<br/>- Token ID (for ERC 721 & 1155)<br/>- Amount (for ERC 20 & 1155) | ||
External Chain->>External Chain: Hash with existing deposit root | ||
External Chain->>External Chain: Take 32 LSB from existing root<br/>Increment and update new deposit root | ||
External Chain->>External Chain: Write new deposit root to contract state | ||
External Chain-->>User: event with new deposit root | ||
User->>Wire Network: Perform 'report' transaction | ||
rect rgb(191, 223, 255) | ||
User -> Wire Network: Signed Transaction, deposit root, and chained roots | ||
end | ||
Wire Network->>Validator: Send report transaction | ||
Validator->>External Chain: Verify deposit | ||
External Chain-->>Validator: Is deposit valid? | ||
alt Deposit is valid | ||
Validator->>Wire Network: Emit ratification | ||
else Deposit not performed | ||
alt Nonce used | ||
Validator->>Wire Network: Write denial with transaction data | ||
else Nonce not used | ||
Validator->>External Chain: Perform signed transaction on external chain | ||
Validator->>Wire Network: Emit ratification | ||
External Chain-->>Validator: Transaction executed | ||
Validator->>Wire Network: Write denial showing chain <br/> from proposal deposit root not including deposit | ||
end | ||
end | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
id: wns-trx-flow | ||
slug: /introduction/wns-trx-flow | ||
--- | ||
# WNS Transaction Flow | ||
|
||
Below is an example of a diagram that visualizes deposit, swap and withdrawal for two hypothetical users - Bob and Alice. | ||
Bob possesses $100 of ETH on Ethereum and Alice has $100 of SOL on Solana, both stored in their respective UPAP-enabled wallets. Upon successful deposits, Bob and Alice have respectively their wrapped tokens WETH and WSOL. | ||
If they wish to swap these assets, the WNS system can perform an atomic swap on the Wire blockchain via the swap contract. | ||
Either party can initiate this transaction using their UPAP-enabled wallet. For instance, Bob proposes a transaction to exchange his $100 in ETH for Alice's $100 in SOL. Alice then finalizes the transaction in her UPAP-enabled wallet, resulting in the updated ownership being confirmed and reflected in the WNS system. | ||
Bob and Alice then decide to withdraw their assets - Bob would now have $100 of SOL in his Solana wallet, and Alice - $100 of ETH in her ETH. | ||
![wns-trx-flow](../../static/img/wns-2.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# Accounts & Permissions | ||
|
||
A Wire account is a digital entity on the blockchain that identifies a participant, which can be an individual or a group. An account also represents the smart contract actors that send and receive actions to and from other accounts on the blockchain. Actions, which are the fundamental units of execution, are always encapsulated within transactions, allowing for one or more atomic actions to be grouped together. | ||
|
||
## Public & Private Keys | ||
|
||
Every Wire account is ultimately controlled by a key pair (public and corresponding private key). While the public key is used to identify the account on the blockchain and can be publicly known, the private key which is used to sign each transaction must be kept secret at all times. | ||
|
||
If you lose your private key, you will lose access to your account and all of its assets, smart contracts, and any other data associated with it. | ||
|
||
## Permissions | ||
|
||
Each account has a set of hierarchical permissions that control what that account can do and how actions are authorized. By default, each account comes with two base permissions - `owner` and `active`. These two permissions are mandatory and they cannot be removed. A permission can only modify its own controls (keys or accounts) or those of its children, but **never those of its parent.** | ||
|
||
### Owner Permission | ||
|
||
The `owner` permission is the highest in an account’s hierarchy, usually reserved for recovery scenarios when lower permissions are compromised. It can perform any action that lower permissions can, but keys for this permission are generally stored offline in cold storage to avoid misuse. | ||
|
||
### Active Permission | ||
|
||
The `active` permission is the default for all actions, sitting just below the `owner` permission. It handles typical account activities, but cannot alter owner keys. Custom permissions usually are created under the `active` and linked to specific contracts or actions. | ||
|
||
![account-hierarchy](../../static/img/account-hierarchy.png). | ||
|
||
A permission is linked to and controlled by either a **public key** or another **account**. This allows for the creation of complex account control structures, where multiple parties may control a single account while still having full autonomy over their own account's security. | ||
|
||
See the diagram below as an example, where the account `jack@active` is controlled by both `nick@active` and `daniel@active`, and on the other hand, `daniel@active` is also controlled by `katey@active`. | ||
|
||
![account-complex-structure](../../static/img/accounts-complex-structure.png) | ||
|
||
### Permission Mapping | ||
|
||
It is possible to create custom permissions scoped to specific actions within a designated contract, also known as *permission mapping*. That permission will then only ever be able to interact with the contract action you specified. Such setup allows for very granular access permissions across accounts and hierarchical structures tailored to your needs. | ||
|
||
![account-custom-permissions](../../static/img/accounts-custom-permissions.png) | ||
|
||
### Permission Evaluation | ||
|
||
When determining whether an action is authorized to be executed, the wire-sysio software: | ||
|
||
- first checks whether the signatures provided in the transaction are valid. | ||
- then it proceeds to check the authorization of all the actions included in the transaction. This is where permissions are evaluated. If any action fails to be authorized, the transaction fails. | ||
|
||
#### Authority Table | ||
|
||
Each account's permission can be linked to an `authority` table used to determine whether a given action authorization can be satisfied. The authority table contains the target permission name and threshold, the factors and their weights, all of which are used in the evaluation to determine whether the authorization can be satisfied. The permission threshold is the target numerical value that must be reached to satisfy the action authorization (see `authority` schema below). | ||
|
||
#### `authority` schema | ||
|
||
Name | Type | Description | ||
-|-|- | ||
`threshold` | `uint32_t` | threshold value to satisfy authorization | ||
`keys` | array of `key_weight` | list of public keys and weights | ||
`accounts` | array of `permission_level_weight` | list of `account@permission` levels and weights | ||
`waits` | array of `wait_weight` | list of time waits and weights | ||
|
||
The `key_weight` type contains the actor's public key and associated weight. The `permission_level_weight` type consists of the actor's `account@permission` level and associated weight. The `wait_weight` contains the time wait and associated weight (used to satisfy action authorizations in delayed user transactions. All of these types allow to define lists of authority factors that are used for satisfaction of action authorizations. | ||
|
||
#### Authority Factors | ||
|
||
Every authority table linked to a given permission lists potential factors explicitly used in the evaluation of the action authorization. A factor type can be one of the following: | ||
|
||
- Actor's account name and permission level | ||
- Actor's public key | ||
- Time wait | ||
|
||
The potential actors who may execute the action are specified by either **public key** or **account name** in the `authority` table. Time waits are special factors which are satisfied by publishing a transaction with a delay in excess of the defined time. These carry weights as well that may contribute to satisfy the threshold. | ||
|
||
#### Authority Threshold | ||
|
||
Authorization over a given action is determined by satisfying all explicit authorizations specified in the action instance. Those are in turn individually satisfied by evaluating each *factor* (account, public key, wait) for satisfaction and summing the weights of those that are satisfied. If the sum equals or exceeds the weight threshold, the action is authorized. | ||
|
||
**Example:** | ||
|
||
The authority table for `jack`'s `release-code` named permission is shown in the diagram below. In order to authorize an action under that permission, a threshold of 2 must be reached. | ||
|
||
Since both `katey@active` and `kyle@active` factors have a weight of 2, *either one can satisfy the action authorization*. This means that either `katey` or `kyle` with a permission level of `active` or higher can independently execute any action under `jack`'s `release-code` permission. | ||
|
||
Alternatively, it would require two acounts each with weight of 1 to satisfy the action authorization - in this case account with public key `SYS7Hnv4iBfcw2...` and `nick@active`. | ||
|
||
![account-weights-example](../../static/img/weights-example.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# Actions | ||
|
||
An action is a specific function or operation that can be executed on a smart contract. Smart contracts are self-executing programs with predefined rules and conditions, and actions are the entry points that allow accounts or other contracts to interact with them. | ||
|
||
## Defining an Action in Wire Smart Contracts | ||
|
||
- **Action with specified return type** | ||
|
||
If you want the action to have a return type, you must use the `[[sysio::action]]` syntax followed by the desired return type. | ||
|
||
```cpp | ||
[[sysio::action]] std::string myaction() { | ||
// ... | ||
return "Hello"; | ||
} | ||
``` | ||
|
||
:::warning | ||
Return values are only usable **outside the blockchain** and cannot currently be used within Wire for smart contract composability. | ||
::: | ||
|
||
- **Simple Action**: A shorthand method that always returns `void` | ||
|
||
If you don’t need to specify the return type, you can use the `ACTION` macro, which is a shorthand for `[[sysio::action]] void`. | ||
|
||
```cpp | ||
ACTION myaction() { | ||
//... | ||
} | ||
``` | ||
|
||
## Inline Actions | ||
|
||
Inline actions allow a contract to call an action of another contract from within its own code. This is useful for building functionality on top of existing contracts. | ||
|
||
Let’s demonstrate this with two simple contracts: `seller` and `buyer`. In this example we will define an inline action `notifysale` on `seller` contract which would be called within `buyitem` action on the `buyer` contract. | ||
|
||
```cpp | ||
#include <sysio/sysio.hpp> | ||
using namespace sysio; | ||
|
||
#include <sysio/sysio.hpp> | ||
#include <sysio/asset.hpp> | ||
using namespace sysio; | ||
|
||
CONTRACT seller : public contract { | ||
public: | ||
using contract::contract; | ||
|
||
ACTION notifysale(name buyer_name, uint64_t item_id, asset price) { | ||
require_auth(get_self()); // Only the seller contract can call this action | ||
|
||
// ...business logic to process the sale | ||
|
||
print("Item ", item_id, " sold to ", buyer_name, " for ", price); | ||
} | ||
}; | ||
``` | ||
|
||
```cpp | ||
#include <sysio/sysio.hpp> | ||
#include <sysio/asset.hpp> | ||
using namespace sysio; | ||
|
||
CONTRACT buyer : public contract { | ||
public: | ||
using contract::contract; | ||
|
||
ACTION buyitem(name buyer_account, name seller_account, uint64_t item_id, asset price) { | ||
require_auth(buyer_account); | ||
|
||
// ...business logic | ||
|
||
// highlight-start | ||
// Notify seller of the purchase | ||
action( | ||
permission_level{get_self(), "active"_n}, | ||
seller_account, // Seller's contract account | ||
"notifysale"_n, // Action on the seller contract | ||
std::make_tuple(buyer_account, item_id) | ||
).send(); | ||
// highlight-end | ||
print("Buyer: Purchased item ", item_id, " from ", seller_account); | ||
} | ||
}; | ||
``` | ||
|
||
### Inline Action Constructor | ||
|
||
The action constructor takes four arguments: | ||
|
||
```txt | ||
action( | ||
<permission_level>, | ||
<contract>, | ||
<action>, | ||
<data> | ||
).send(); | ||
``` | ||
|
||
#### Parameters of the `action` constructor | ||
|
||
| Parameter | Type | Description | | ||
|--------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| `permission_level` | `permission_level` | Specifies who is authorizing the action and at what permission level. Constructed using `{actor, permission}`. | | ||
| `contract` | `name` | The account name where the target action is deployed. This is the contract you are calling. | | ||
| `action_name` | `name` | The name of the action you want to invoke on the target contract. | | ||
| `data` | `std::tuple` | The data to be passed to the action, packaged as a tuple containing the arguments required by the target action. Use `std::make_tuple` to create it. | | ||
|
||
:::success[TIP] | ||
|
||
- To convert a string into a `name` type for parameters like `contract` and `action_name`, use the `name()` function. | ||
|
||
- Use `std::make_tuple()` to package multiple arguments together into the `data` parameter that matches the target action’s expected structure. | ||
|
||
- `std::make_tuple(arg1, arg2, arg3, ...);` | ||
|
||
::: | ||
|
||
##### Setting Up the Permission Level | ||
|
||
The `permission_level` argument specifies the permission level under which the action will be executed. It consists of two components: | ||
|
||
```cpp | ||
permission_level( | ||
account, | ||
permission | ||
) | ||
``` | ||
|
||
- `account` (name type): The account authorizing the action. | ||
- `permission` (name type): The permission level of the account (e.g., "active"_n). | ||
|
||
:::danger[IMPORTANT] | ||
When you call an inline action, **the contract initiating the call becomes the new sender**. For security reasons, the original authorization is **not** passed to the called contract. This prevents the called contract from performing actions on behalf of the original sender, such as transferring tokens without explicit permission. | ||
::: | ||
|
||
###### Setting Up Special Permission (`eosio.code`) | ||
|
||
To allow your contract to call inline actions on other contracts,**you need to grant it the special `eosio.code` permission**. Without this permission, your contract cannot execute actions on other contracts. | ||
|
||
This permission is on the `active` permission level so that it allows other contracts using the `require_auth()` to verify that your contract has the authority to perform the action. | ||
|
||
###### How to Add the `eosio.code` Permission | ||
|
||
Add the `eosio.code` permission to the contract account `active` permission to enable calling inline actions by the contract account's `active` permission. | ||
|
||
```sh | ||
clio set account permission yourcontract active --add-code -p yourcontract@active | ||
``` | ||
|
||
Example of post-update permission's hierarchy: | ||
|
||
```txt | ||
owner | ||
• YOUR_PUBLIC_KEY | ||
↳ active | ||
• YOUR_PUBLIC_KEY | ||
• <[email protected]> | ||
``` |
Oops, something went wrong.