From c50f209eb8ccd1868c967afb4baf96db05818c39 Mon Sep 17 00:00:00 2001 From: Trinity Date: Mon, 6 Jan 2025 11:36:19 +0700 Subject: [PATCH 01/53] specs for new asset module --- x/asset/spec/01_concepts.md | 43 ++++--- x/asset/spec/02_state.md | 37 +++--- x/asset/spec/03_params.md | 9 +- x/asset/spec/04_events.md | 37 ------ x/asset/spec/04_msgs.md | 159 ++++++++++++++++++++++++ x/asset/spec/05_client.md | 26 ---- x/asset/spec/README.md | 67 +++++++--- x/asset/spec/imgs/asset_evm.png | Bin 0 -> 152790 bytes x/asset/spec/imgs/asset_module.png | Bin 0 -> 283301 bytes x/asset/spec/imgs/asset_precompiles.png | Bin 0 -> 119166 bytes 10 files changed, 256 insertions(+), 122 deletions(-) delete mode 100644 x/asset/spec/04_events.md create mode 100644 x/asset/spec/04_msgs.md delete mode 100644 x/asset/spec/05_client.md create mode 100644 x/asset/spec/imgs/asset_evm.png create mode 100644 x/asset/spec/imgs/asset_module.png create mode 100644 x/asset/spec/imgs/asset_precompiles.png diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 76bd9677..8005cec7 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -6,28 +6,41 @@ 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 aroumd a token model. It contains the following fields: + +### Token ```protobuf message Token { - string name = 1; - string symbol = 2; - int64 total = 3; - int64 decimals = 4; - bool authorizationRequired = 5; - string creator = 6; - map authorized = 7; - int64 created = 8; + string token_id = 1; + string issuer = 2; + string name = 3; + string symbol = 4; + uint32 decimals = 5; + string description = 6; + []address manager_addresses = 7; + []address distributor_addresses = 8; + bool single_representation = 9; + bool is_freeze = 10; + DistributionSettings distribution_settings = 11; } - ``` -### Token Authorization +The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). + +### Role -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. +In token model, each token has 2 roles which can execute different functionality. They are whitelisted address that is defined by the issuer of the token. While the `manager` can execute the `freeze` and `burn` functionality, `distributor` can control the `mint` functionality and custom the `DistributionSettings`. +- "ROLE_UNSPECIFIED": 0 +- "ROLE_MANAGER": 1 +- "ROLE_DISTRIBUTOR": 2 +### DistributionSettings +```protobuf +message DistributionSettings { + string max_supply = 1[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; + string max_ratelimit = 2[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; +} +``` diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index bcc1e164..f2bee85a 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -11,39 +11,36 @@ The `x/asset` module keeps the following objects in state: | 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 | +| `Params` | Params bytecode | `[]byte{2} + []byte(id)` | `[]byte(id)` | KV | -### Token +### Token Allows creation of tokens with optional user authorization. ```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"` + TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` + Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` + Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` + IsFreezed bool `protobuf:"varint,9,opt,name=is_freezed,json=isFreezed,proto3" json:"is_freezed,omitempty"` + EvmSinglePresentation bool `protobuf:"varint,10,opt,name=evm_single_presentation,json=evmSinglePresentation,proto3" json:"evm_single_presentation,omitempty"` + DistributionSettings DistributionSettings `protobuf:"bytes,11,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings,omitempty"` } ``` -### Token Authorization - -A Token authorization struct represents a single addresses current authorization state for a token +### Params ```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 Params struct { + AllowFunctionalities []string `protobuf:"bytes,1,rep,name=allow_functionalities,json=allowFunctionalities,proto3" json:"allow_functionalities,omitempty"` } ``` - - ## Genesis State The `x/asset` module's `GenesisState` defines the state necessary for initializing the chain from a previous exported height. It contains the module parameters and the registered token pairs : @@ -54,4 +51,4 @@ 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"` } -``` \ No newline at end of file +``` diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index 06f1e439..6389a1c7 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -6,8 +6,7 @@ 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 | +|----------------------|----------|------------------------| +| port | string | "ario" | +| AllowFunctionalities | []string | ["burn","freeze"] | diff --git a/x/asset/spec/04_events.md b/x/asset/spec/04_events.md deleted file mode 100644 index be929e92..00000000 --- a/x/asset/spec/04_events.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# Events - -The `x/asset` module emits the following events: - -## Create new token - -| Type | Attribute Key | Attribute Value | -| --------------- |---------------|-----------------| -| `create_token` | `"amount"` | `{totatl}` | -| `create_token` | `"symbol"` | `{symbol}` | - -## Update token - -| Type | Attribute Key | Attribute Value | -| --------------- |---------------|-----------------| -| `update_token` | `"symbol"` | `{symbol}` | - - -## Authorize address - -| Type | Attribute Key | Attribute Value | -| --------------- |--------------|------------------| -| `authorize_token` | `"symbol"` | `{symbol}` | -| `authorize_token` | `"address"` | `{sdk_address}` | - - -## Un Authorize address - -| Type | Attribute Key | Attribute Value | -| --------------- |---------------|-----------------| -| `unauthorize_token` | `"symbol"` | `{symbol}` | -| `unauthorize_token` | `"address"` | `{sdk_address}` | - diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md new file mode 100644 index 00000000..f2198ff4 --- /dev/null +++ b/x/asset/spec/04_msgs.md @@ -0,0 +1,159 @@ + + +# Messages + +## 1. MsgIssueToken + +`MsgIssueToken` allow issuer to create token. + +```go + type MsgIssueToken struct { + Issuer address + Managers [ ]address + Distributors [ ]address + ContractAddress string + Symbol string + Decimal uint32 + Description string + SingleRepresentation bool + } +``` + +```go + type MsgIssueTokenResponse struct { + } +``` + +CLI: + +```bash + realio-networkd tx issue-token [token.json] [flags] +``` + +Example token.json: + +```json + { + "Manager": ["realioabc..."], + "Distributor": ["realioabc2..."], + "ContractAddress": "0x...", + "Symbol": "riel", + "Decimal": "rielio", + "Description": "", + "SingleRepresentation": true, + } +``` + +## 2. AssignRoles + +`MsgAssignRoles` allow issue to set role likes manager or distributor for the token. + +```go + type MsgAssignRoles struct { + TokenId string + Issuer address + Addresses mapping[Role]([]addresses) + } +``` + +```go + type MsgAssignRolesResponse struct { + } +``` + +CLI: + +```bash + realio-networkd tx assign-roles [privilege.json] [flags] +``` + +Example privilege.json: + +```json + { + "TokenId": "asset/realio1.../tokena", + "Issuer": "realio1...", + "Assign": [ + { + "role": 1 (manager), + "addresses": ["realio2..."], + }, + { + "role": 2 (distributor), + "addresses": ["realio3..."], + } + ] + } +``` + +## 3. UnassignRole + +```go + type MsgUnassignRole struct { + TokenId string + Issuer address + Assigners []address + } +``` + +```go + type MsgUnassignRoleResponse struct { + } +``` + +## 4. ExecuteFunctionality + +After setting the managers, the managers can execute their allowed functionality. + +```go + type MsgExecuteFunctionality struct { + Manager address + TokenId string + FunctionalityMsg *types.Any + } +``` + +CLI: + +```bash + realio-networkd tx execute-functionality [contract-address] [msg.json] [flags] +``` + +Example: + +```bash + realio-networkd tx execute-functionality 0x... msg.json --from mykey +``` + +```json +{ + "FreezeMsg": {} +} +``` + +### 5. Mint + +```go + type MsgMint struct { + Distributor address + TokenId string + Receiver address + Amount math.Int + } +``` + +### 6. UpdateDistributionSetting + +Distributor can change the max supply and mint ratelimit of the token. + +```go + type MsgUpdateDistributionSetting struct { + Distributor address + TokenId string + NewSettings DistributionSettings + } +``` + +### 7. UpdateParams diff --git a/x/asset/spec/05_client.md b/x/asset/spec/05_client.md deleted file mode 100644 index 71de1325..00000000 --- a/x/asset/spec/05_client.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `x/asset` module using the CLI. - -### Query - -The `query` commands allow users to query `x/asset` state. - -```sh -realio-networkd query mint --help -``` - -#### params - -The `params` command allow users to query the current module parameters - -```sh -realio-networkd query mint params [flags] -``` - diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 23b4d990..6950cb96 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -1,33 +1,62 @@ -# `mint` +# `asset` -## Abstract +## The Realio Asset Token Model -The `x/asset` module enables the creation and management of on chain assets in the Realio Network. +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 two different roles, manager and distributor. These roles can be assigned to arbitrary accounts (could be either user accounts or module/contract account) by the token issuer. -With this module, you can create assets that represent digitally native and real-world assets such as security tokens and stablecoins. -There is functionality to place transfer restrictions via whitelists on an asset that help support securities, compliance, and certification use cases. +Each token can choose to enable functionalities supported by the module. Currently, there are four functionalities supported: "mint", "freeze", "clawback", "transfer_auth", each handle a completely different logic. We wanna decouple the logic of these functionalities from the `Asset module`, meaning that they will be defined in separate packages/modules, thus, developers can customize new functionalities without modifying the `Asset Module`. Doing this allows our token model to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we integrating new features. +The token manager's task is to choose what functionalities it wants to disable/enable for its token; and only the token manager can trigger those functionalities, except for the `mint` functionality which is handled by the `distributor`. + +![asset_module](imgs/asset_module.png) + +## Asset Module and ERC-20 Precompiles + +ERC-20 precompiles are offered by evmOS for better interacting with Cosmos SDK. Instead of changing the state of evm, with ERC-20 precompiles, modules now can represent ERC-20 token in the form of normal bank token and therefore can be managed by SDK modules (single token representation). Utilizing this feature enables the evm contracts to interact with the asset tokens via erc20 call, opening lots of defi usecases for the asset module. + +### Link Asset to Precompiles + +To link an asset to ERC20 Precompile, user have to create a gov proposal so that Asset Module can interact with ERC-20 module to registerERC20 and change their params (`Dynamic Precompiles` field). After linking, all call to the token contract will now redirect to precompile instead of the evm. + +![asset_precompiles](imgs/asset_precompiles.png) + +### Mapping functions + +ERC20 precompiles come with a limited number of functions which are: + +- Transfer +- TransferFrom +- Approve +- IncreaseAllowance +- DecreaseAllowance + +These functions can be called from both AssetModule and EVM side (by metamask for example). + +Other functions like: + +- Mint +- Burn + +can only be called from Asset Module side. + +![asset_evm](imgs/asset_evm.png) ## Contents 1. **[Concept](01_concepts.md)** 2. **[State](02_state.md)** - * [Minter](02_state.md#minter) - * [Params](02_state.md#params) -3. **[Begin-Block](03_begin_block.md)** - * [NextAnnualProvisions](03_begin_block.md#nextannualprovisions) - * [BlockProvision](03_begin_block.md#blockprovision) -4. **[Parameters](04_params.md)** -5. **[Events](05_events.md)** - * [BeginBlocker](05_events.md#beginblocker) -6. **[Client](06_client.md)** - * [CLI](06_client.md#cli) - * [gRPC](06_client.md#grpc) - * [REST](06_client.md#rest) + - [Minter](02_state.md#minter) + - [Params](02_state.md#params) +3. **[Parameters](03_params.md)** +4. **[Messages](04_msgs.md)** +5. **[Client](05_client.md)** + - [CLI](05_client.md#cli) + - [gRPC](05_client.md#grpc) + - [REST](05_client.md#rest) diff --git a/x/asset/spec/imgs/asset_evm.png b/x/asset/spec/imgs/asset_evm.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7843d2e56d3d408913fbe63a86b0b44b1698a9 GIT binary patch literal 152790 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�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
Rf7EVQbpvp8Y* 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

K^c(^slMBgioNzDDX)bV*~*$Vg1ZE_#P$%uhd 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 z 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

1{t}HMRA$dWNPiF zTmY;hH|@T#ojDQyV3=n+`g6EWk5_gOr;1F+Nt+yj^{?dA=^XcWQnQE$Zj}aUZJIi4 zjW=&TZ@HYXwd~!)S(_iyUEpFX<@|~Dwv@p!&*epzQ0yJGZvkTq%0$U+3x=B8BOa87 zBj4`d6D4bJI(|)-HNYdc8jI(7`l;J2L-L}xsPl|#QRIEDG53yY*c%UbtE$#rGB8Tg z?>#;n%k1e(;m3OC$ePRd%F5laU@7NJ{TT!YIF*v_;fP0(;vXd2Bt#Uo;Ndt@Uv;R| z?n@Y+DPv-k`d8*7T;yx=!|cz5OZs1BTw$R=DYG0;pJtyd*5Z2O>_bLsO`N=yqnn~> zDqVTlDDIoZn#5|UK}+liSB5MvE6fTKT|M)?uW8=4>F6Wp_SL8IiuvLP?;kZWhS=MH z#JP;@S=P>mvk&pa@mbqv`bNGT^OP6vh&$2>Pi(xNAML)~6xnTvdM*-(wnV2Xx~){r zkFG}=P2ICHoXiutr~T<9SKMpHIB#QfwmSTpV~9g?F@lFGhzr1YqkfU(YwfQkAD^&2 z|D(%`W$Ep6#nWQ6zdd3tIe7I)bkZ{dBbL7Ft8aDQGHy=vA}(AQy4s0xE?(&{Yu&p4 zI2C<8>9SYS0lwMg5P%r2k%lsnaHBJybLSVmIdSeZQ`BbW3|_i)$tdDhg{1v$?~4Q-~ng4HuQ=a-stX6o-* zDh4QCuN1dp!|v(<=*A{(D)ubhPJI9J7oRWGHf8R8&pA3mLl;74QFZy6BONatB-=}E z&EA;NaZN-sIXJyE)CAD*MN#)!i{bJ%4)MEInr!R%fo+pWJdNmep|QfKV5*77f06rt zCbPCrUKG5}7WE<__GR8iLw0>$X<~Y7@w?2AlX%3(Ra)6}65gFA^>Ulc|CApcZTj#+ zPI+Okn)3S7KKk2qVX5h^4iRX3yGvAA$mNh2x4DU}Ao^3n_C$bMqNXV{l)|XKvwo=B z%-`I|Oj3BlQ#O?98IkuH?gcj;aUNu)kbmD?<*|W#DkZunbM~=^BHEIJmYX7HW&W^N z?VZ$Ar?o|yvR7*XDxEk6DyUY8SkxCgJBrz4QbJqih7%Skir1&V^;WbUzol_VfjEYa zQMz2+VSKYRb*sYH#UvsmCeDgJB3{wzW6}(vZn3qA+I8u{9G-#%FXej{t-^7IC+UuG;nIIx3eTy%(O^qmoqL z@(7O&r~dOYwkQJpO&^INr$M=H)E@3!-(q8QxI}GiDRF!w{ZRGR%3$n`IaHg~Hi~!z zmr^F!UE)@0~Y*uK7U%B^6EJU(uufH+QO@oBklO8@&Q09;wN=8mXy-f|Z2mp7-~SUI0u{G}`;e#~ zp?Lc12=1}Mzoy^T-VY#^?>;INF0=1c4qy~K1Dt}bSS|3-Pe4iP8k{D!!~E$}7&qY+ zdb$OFR>|Y9XHNXfQ#eQ9JSeD?NU!!6ZCtOnjsPDE5Hy{rkHs3;XNRIeu!- zy&@fNPp{O`FX_yh!JUg5OD@Wzz05kSoenT2f;iE zaiPDpVET#oTelAChEm4bPO`8+

B~jQ@Xj=~o6{*)#%rvYeOZr5- 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 G?*9izA8$DT literal 0 HcmV?d00001 diff --git a/x/asset/spec/imgs/asset_precompiles.png b/x/asset/spec/imgs/asset_precompiles.png new file mode 100644 index 0000000000000000000000000000000000000000..db9af39b49a0c72f31054bcb8c8cba810c18ace2 GIT binary patch literal 119166 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

;RIrJbNPjbo{FzZBq6A&}g&cw;&5E$&hH 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 Date: Tue, 7 Jan 2025 11:32:58 +0700 Subject: [PATCH 02/53] update spec --- x/asset/spec/01_concepts.md | 11 ++++++++--- x/asset/spec/02_state.md | 36 +++++++++++++++++++++--------------- x/asset/spec/04_msgs.md | 20 ++++++++++++++++++-- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 8005cec7..67398090 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -20,14 +20,19 @@ message Token { string description = 6; []address manager_addresses = 7; []address distributor_addresses = 8; - bool single_representation = 9; - bool is_freeze = 10; - DistributionSettings distribution_settings = 11; + bool evm_enable = 9; + bool allow_new_fuctionalities = 10; + []string functionalities_list = 11; + DistributionSettings distribution_settings = 12; } ``` The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). +When creating a new token, `issuer` can define that they accept new functionalities or not by setting `allow_new_fuctionalities`. If he allow it, the new functionality when upgrading chain will be automatically added to the `functionalities_list` and the `issuer` can adjust the `functionalities_list` by his will. + +By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. + ### Role In token model, each token has 2 roles which can execute different functionality. They are whitelisted address that is defined by the issuer of the token. While the `manager` can execute the `freeze` and `burn` functionality, `distributor` can control the `mint` functionality and custom the `DistributionSettings`. diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index f2bee85a..95fc2075 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -8,10 +8,11 @@ order: 2 The `x/asset` module keeps the following objects in state: -| State Object | Description | Key | Value | Store | -|----------------------|--------------------------------|--------------------------| --------------- |-------| -| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV | -| `Params` | Params bytecode | `[]byte{2} + []byte(id)` | `[]byte(id)` | KV | +| State Object | Description | Key | Value | Store | +|----------------------|--------------------------------|--------------------------| ---------------------|-------| +| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV | +| `FreezedAddresses` | Addresses bytecode | `[]byte{21} + []byte(id)`| `[]byte{[]address}` | KV | +| `Params` | Params bytecode | `[]byte{3} + []byte(id)` | `[]byte(id)` | KV | ### Token @@ -19,20 +20,25 @@ Allows creation of tokens with optional user authorization. ```go type Token struct { - TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` - Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` - Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` - IsFreezed bool `protobuf:"varint,9,opt,name=is_freezed,json=isFreezed,proto3" json:"is_freezed,omitempty"` - EvmSinglePresentation bool `protobuf:"varint,10,opt,name=evm_single_presentation,json=evmSinglePresentation,proto3" json:"evm_single_presentation,omitempty"` - DistributionSettings DistributionSettings `protobuf:"bytes,11,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings,omitempty"` + TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` + Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` + Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` + EvmEnable bool `protobuf:"varint,9,opt,name=evm_enable,json=evmEnable,proto3" json:"evm_enable,omitempty"` + AllowNewFuctionalities bool `protobuf:"varint,10,opt,name=allow_new_fuctionalities,json=allowNewFuctionalities,proto3" json:"allow_new_fuctionalities,omitempty"` + FunctionalitiesList []string `protobuf:"bytes,11,rep,name=functionalities_list,json=functionalitiesList,proto3" json:"functionalities_list,omitempty"` + DistributionSettings DistributionSettings `protobuf:"bytes,12,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings"` } ``` +### FreezedAddress + +List of addresses that is freezed by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. + ### Params ```go diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index f2198ff4..40c2117e 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -17,7 +17,9 @@ order: 4 Symbol string Decimal uint32 Description string - SingleRepresentation bool + EvmEnable bool + AllowNewFuctionalities bool + FunctionalitiesList [ ]string } ``` @@ -135,6 +137,8 @@ Example: ### 5. Mint +This function only can be executed when the token's `FunctionalitiesList` has `mint` functionality. + ```go type MsgMint struct { Distributor address @@ -156,4 +160,16 @@ Distributor can change the max supply and mint ratelimit of the token. } ``` -### 7. UpdateParams +### 7. UpdateFunctionalitiesList + +Manager can update the `FunctionalitiesList` of the token. This only can be executed when the token's `AllowNewFuctionalities` is enable. + +```go + type FunctionalitiesList struct { + Manager address + TokenId string + NewFunctionalities []string + } +``` + +### 8. UpdateParams From f7161a0f5bfbdb37080b7067a37fd1892993ee5a Mon Sep 17 00:00:00 2001 From: Trinity Date: Tue, 7 Jan 2025 11:40:23 +0700 Subject: [PATCH 03/53] Add whitelist addresses --- x/asset/spec/03_params.md | 1 + 1 file changed, 1 insertion(+) diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index 6389a1c7..aaa226ad 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -10,3 +10,4 @@ The asset module contains the following parameters: |----------------------|----------|------------------------| | port | string | "ario" | | AllowFunctionalities | []string | ["burn","freeze"] | +| WhitelistAddresses | []address| ["realio1..."] | From 14820d8bd01b2b1569a57fe9f772eb87b2d316c4 Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 8 Jan 2025 10:15:09 +0700 Subject: [PATCH 04/53] Add logic for asset module and rewrite concept --- x/asset/spec/01_concepts.md | 36 +++++++++++++------- x/asset/spec/02_state.md | 31 ++++++++++++----- x/asset/spec/03_params.md | 6 +++- x/asset/spec/04_msgs.md | 24 ++++++-------- x/asset/spec/05_logic.md | 66 +++++++++++++++++++++++++++++++++++++ x/asset/spec/README.md | 10 +++--- 6 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 x/asset/spec/05_logic.md diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 67398090..7899af76 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -18,29 +18,43 @@ message Token { string symbol = 4; uint32 decimals = 5; string description = 6; - []address manager_addresses = 7; - []address distributor_addresses = 8; - bool evm_enable = 9; - bool allow_new_fuctionalities = 10; - []string functionalities_list = 11; - DistributionSettings distribution_settings = 12; } ``` -The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). - -When creating a new token, `issuer` can define that they accept new functionalities or not by setting `allow_new_fuctionalities`. If he allow it, the new functionality when upgrading chain will be automatically added to the `functionalities_list` and the `issuer` can adjust the `functionalities_list` by his will. +The token id for the token will be derived from the Issuer and the Symbol with the format of asset/{Issuer}/{Symbol-Lowercase}. This will allow 2 tokens to have the same name with different issuers. -By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. +The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). ### Role -In token model, each token has 2 roles which can execute different functionality. They are whitelisted address that is defined by the issuer of the token. While the `manager` can execute the `freeze` and `burn` functionality, `distributor` can control the `mint` functionality and custom the `DistributionSettings`. +In token model, each token has 2 roles which can execute different functionality. They are whitelisted address that is defined by the issuer of the token. While `distributor` can control the `mint` functionality and custom the `DistributionSettings`, the `manager` can execute the other functionalities like `burn` or `freeze` and could modify the `functionalities_list` - "ROLE_UNSPECIFIED": 0 - "ROLE_MANAGER": 1 - "ROLE_DISTRIBUTOR": 2 +### TokenManager + +```protobuf +message TokenManager { + []address manager_addresses = 1; + bool allow_new_fuctionalities = 2; + []string functionalities_list = 3; + bool evm_enable = 4; +} +``` + +By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. + +### TokenDistributor + +```protobuf +message TokenDistributor{ + []address distributor_addresses = 2; + DistributionSettings distribution_settings = 5; +} +``` + ### DistributionSettings ```protobuf diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 95fc2075..d0671ac1 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -8,11 +8,13 @@ order: 2 The `x/asset` module keeps the following objects in state: -| State Object | Description | Key | Value | Store | -|----------------------|--------------------------------|--------------------------| ---------------------|-------| -| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV | -| `FreezedAddresses` | Addresses bytecode | `[]byte{21} + []byte(id)`| `[]byte{[]address}` | KV | -| `Params` | Params bytecode | `[]byte{3} + []byte(id)` | `[]byte(id)` | KV | +| State Object | Description | Key | Value | Store | +|----------------------|--------------------------------|--------------------------| ---------------------------|-------| +| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV | +| `TokenManager` | TokenManager bytecode | `[]byte{2} + []byte(id)` | `[]byte{token_manager}` | KV | +| `TokenDistributor` | TokenDistributor bytecode | `[]byte{3} + []byte(id)` | `[]byte{token_distributor}`| KV | +| `FreezedAddresses` | Addresses bytecode | `[]byte{4} + []byte(id)` | `[]byte{[]address}` | KV | +| `Params` | Params bytecode | `[]byte{5} + []byte(id)` | `[]byte(id)` | KV | ### Token @@ -26,11 +28,25 @@ type Token struct { Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` +} +``` + +### TokenManager + +```go +type TokenManager struct{ Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` - Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` - EvmEnable bool `protobuf:"varint,9,opt,name=evm_enable,json=evmEnable,proto3" json:"evm_enable,omitempty"` AllowNewFuctionalities bool `protobuf:"varint,10,opt,name=allow_new_fuctionalities,json=allowNewFuctionalities,proto3" json:"allow_new_fuctionalities,omitempty"` FunctionalitiesList []string `protobuf:"bytes,11,rep,name=functionalities_list,json=functionalitiesList,proto3" json:"functionalities_list,omitempty"` + EvmEnable bool `protobuf:"varint,9,opt,name=evm_enable,json=evmEnable,proto3" json:"evm_enable,omitempty"` + } +``` + +### TokenDistributor + +```go +type TokenManager struct{ + Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` DistributionSettings DistributionSettings `protobuf:"bytes,12,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings"` } ``` @@ -55,6 +71,5 @@ The `x/asset` module's `GenesisState` defines the state necessary for initializi // 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"` } ``` diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index aaa226ad..ddb8c53d 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -8,6 +8,10 @@ The asset module contains the following parameters: | Key | Type | Example | |----------------------|----------|------------------------| -| port | string | "ario" | | AllowFunctionalities | []string | ["burn","freeze"] | | WhitelistAddresses | []address| ["realio1..."] | + +## Details + +- AllowFunctionalities: list of functionalities that the module provides. They can be update after the chain upgrade to enable new functionality add-on to the module. +- WhitelistAddresses: list of the address that's allow to create new token. diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 40c2117e..1461d418 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -6,7 +6,7 @@ order: 4 ## 1. MsgIssueToken -`MsgIssueToken` allow issuer to create token. +`MsgIssueToken` allow issuer to create token. The issuer must be in param's whitelist addresses to be able to execute this msg. ```go type MsgIssueToken struct { @@ -117,23 +117,19 @@ After setting the managers, the managers can execute their allowed functionality } ``` -CLI: +### Flow -```bash - realio-networkd tx execute-functionality [contract-address] [msg.json] [flags] -``` +Validation: -Example: +- Checks if the token specified in the msg exists. +- Checks if the functionality is supported. +- Checks if the `Msg.Address` has the corresponding `Functionality` specified by `FunctionalityMsg.NeedFunctionality()` -```bash - realio-networkd tx execute-functionality 0x... msg.json --from mykey -``` +Flow: -```json -{ - "FreezeMsg": {} -} -``` +- Prepare store for the functionality of the token via `MakeFunctionalityStore(functionality name, token denom)`. That store is the only store accessable by the functionality's `MsgHandler`. +- `FunctionalityMsgRouting` routes the `FunctionalityMsg` to the its `MsgHandler`. +- `MsgHandler` now handles the `FunctionalityMsg`. ### 5. Mint diff --git a/x/asset/spec/05_logic.md b/x/asset/spec/05_logic.md new file mode 100644 index 00000000..a5ac770f --- /dev/null +++ b/x/asset/spec/05_logic.md @@ -0,0 +1,66 @@ + + +# Logic + +This file describes the core logics in this module. + +## Functionality + +### Register new functionality + +To intergrate with the `asset module` Each type of functionality has to implement this interface + +```go +type Functionality interface { + RegisterInterfaces() + MsgHandler() MsgHandler + QueryHandler() QueryHandler + CLI() *cobra.Command +} + +type MsgHandler func(context Context, funcMsg FunctionalityMsg) error + +type QueryHandler func(context Context, funcQuery FunctionalityMsg) error +``` + +This interface provides all the functionality necessary for a functionality, including a message handler, query handler and cli + +All the `FunctionalityMsg` of a functionality should return the name of that functionality when called `FunctionalityName()`. A message handler should handle all the `FunctionalityMsg` of that functionality. + +### Upgrade Priviliges + +All functionalities are located in a seperate packages, for example: asset/functionalities, therefore the exentsion or upgrade of functionalities is unrelated to core logic of `Asset` module, all the modification and addition happen in only asset/functionalities package. The core Asset module does not need to be aware of the specifics of functionality handling. It interacts with functionalitys through defined interfaces or protocols. + +Each Priviliges has their own proto to define their state and execute/query messages. By assigning a distinct proto to each functionality, you ensure that the logic, messages, and data associated with one functionality do not interfere with or complicate the others. This also makes the design easier to understand, maintain, and scale. + +When adding a `Functionality`, we calls `FunctionalityManager.AddFunctionality()` in `app.go` which inturn maps all the `FunctionalityMsg` of that functionality to its `MsgHandler`. This mapping logic will later be used when running a `MsgExecuteFunctionality`. + +### Message/Query routing + +The message we pass in `ExecuteFunctionality` is `msg.Any` type. This type refered that it could be any type of message. +After receive this message, we will unpack the `msg.Any` type to an interface which implements what we want: + +```go +type FunctionalityMsg interface { + FunctionalityName() string +} +``` + +As we defined the `AllowFunctionalities` in Params. If the message name is in the list, they will also exist there own interface in `FunctionalityRouting`. + +`FunctionalityRouting` acts as a centralized hub for routing messages, making it easy to manage and audit the flow of messages in the system. +It will route the `FunctionalityMsg` to its `MsgHandler` - where the msg is executed. In the `MsgHandler`, the message is further routed based on its type to the correct execution logic. This additional layer of routing within the MsgHandler ensures precise handling through message types, enabling fine-grained control and execution workflows. + +This flow will also work with `QueryHandler`, as long as we can unpack the `msg.Any` and get the name of the functionality. + +## EVM interaction + +### Enable EVM interface + +The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module, where the token’s core state and functionalities are managed. + +The token itself exists as a coin within the bank state, maintaining its own logic and functionalities independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. + +### ERC20 Precompiles \ No newline at end of file diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 6950cb96..8871d2d7 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -52,11 +52,11 @@ can only be called from Asset Module side. 1. **[Concept](01_concepts.md)** 2. **[State](02_state.md)** - - [Minter](02_state.md#minter) - - [Params](02_state.md#params) + - [Minter](02_state.md#minter) + - [Params](02_state.md#params) 3. **[Parameters](03_params.md)** 4. **[Messages](04_msgs.md)** 5. **[Client](05_client.md)** - - [CLI](05_client.md#cli) - - [gRPC](05_client.md#grpc) - - [REST](05_client.md#rest) + - [CLI](05_client.md#cli) + - [gRPC](05_client.md#grpc) + - [REST](05_client.md#rest) From 64fedb7463c042fdb2fc578238203e85e53b9683 Mon Sep 17 00:00:00 2001 From: lacsomot Date: Wed, 8 Jan 2025 17:04:11 +0700 Subject: [PATCH 05/53] asset module spec --- x/asset/spec/01_concepts.md | 57 ++---------- x/asset/spec/02_state.md | 58 ++++++++---- x/asset/spec/04_msgs.md | 26 +++++- x/asset/spec/05_query.md | 102 ++++++++++++++++++++++ x/asset/spec/{05_logic.md => 06_logic.md} | 4 +- 5 files changed, 178 insertions(+), 69 deletions(-) create mode 100644 x/asset/spec/05_query.md rename x/asset/spec/{05_logic.md => 06_logic.md} (96%) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 7899af76..dbf44cb6 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -6,60 +6,19 @@ order: 1 ## The Realio Asset Token Model -The Realio Asset module is centered 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 role by the issuer of the asset. -### Token +### System of privileged accounts -```protobuf -message Token { - string token_id = 1; - string issuer = 2; - string name = 3; - string symbol = 4; - uint32 decimals = 5; - string description = 6; -} -``` +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. -The token id for the token will be derived from the Issuer and the Symbol with the format of asset/{Issuer}/{Symbol-Lowercase}. This will allow 2 tokens to have the same name with different issuers. +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. -The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). +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. -### Role +### EVM enable -In token model, each token has 2 roles which can execute different functionality. They are whitelisted address that is defined by the issuer of the token. While `distributor` can control the `mint` functionality and custom the `DistributionSettings`, the `manager` can execute the other functionalities like `burn` or `freeze` and could modify the `functionalities_list` +While it is useful to represent the token in bank module, enabling the token to be in action in evm environment is very convenient and pave the possibility of integrating new features into the ecosystem. -- "ROLE_UNSPECIFIED": 0 -- "ROLE_MANAGER": 1 -- "ROLE_DISTRIBUTOR": 2 +Each token can be enabled to work in the evm environment by the token manager, which means user can interact with the token through evm side like metamask or anyother evm wallet and more other protocol integrated in the future. Note that, token manager can disable or enable the token to be used in the evm environment. -### TokenManager - -```protobuf -message TokenManager { - []address manager_addresses = 1; - bool allow_new_fuctionalities = 2; - []string functionalities_list = 3; - bool evm_enable = 4; -} -``` - -By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. - -### TokenDistributor - -```protobuf -message TokenDistributor{ - []address distributor_addresses = 2; - DistributionSettings distribution_settings = 5; -} -``` - -### DistributionSettings - -```protobuf -message DistributionSettings { - string max_supply = 1[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; - string max_ratelimit = 2[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; -} -``` diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index d0671ac1..b65ab168 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -8,13 +8,21 @@ order: 2 The `x/asset` module keeps the following objects in state: -| State Object | Description | Key | Value | Store | -|----------------------|--------------------------------|--------------------------| ---------------------------|-------| -| `Token` | Token bytecode | `[]byte{1} + []byte(id)` | `[]byte{token}` | KV | -| `TokenManager` | TokenManager bytecode | `[]byte{2} + []byte(id)` | `[]byte{token_manager}` | KV | -| `TokenDistributor` | TokenDistributor bytecode | `[]byte{3} + []byte(id)` | `[]byte{token_distributor}`| KV | -| `FreezedAddresses` | Addresses bytecode | `[]byte{4} + []byte(id)` | `[]byte{[]address}` | KV | -| `Params` | Params bytecode | `[]byte{5} + []byte(id)` | `[]byte(id)` | KV | +| State Object | Description | Key | Value | Store | +|----------------------|----------------------------------------|--------------------------| ---------------------------|-------| +| `Params` | Params of asset module | `[]byte{1}` | `[]byte(params)` | KV | +| `Token` | Token information | `[]byte{2} + []byte(id)` | `[]byte{token}` | KV | +| `TokenManager` | TokenManager info of a denom | `[]byte{3} + []byte(id)` | `[]byte{token_manager}` | KV | +| `TokenDistributor` | TokenDistributor info of a denom | `[]byte{4} + []byte(id)` | `[]byte{token_distributor}`| KV | +| `FrozenAddresses` | Frozen Addresses bytecode | `[]byte{5} + []byte(id)` | `[]byte{[]address}` | KV | + +### Params + +```go +type Params struct { + AllowFunctionalities []string `protobuf:"bytes,1,rep,name=allow_functionalities,json=allowFunctionalities,proto3" json:"allow_functionalities,omitempty"` +} +``` ### Token @@ -31,6 +39,10 @@ type Token struct { } ``` +The token id for the token will be derived from the Issuer and the Symbol with the format of asset/{Issuer}/{Symbol-Lowercase}. This will allow 2 tokens to have the same name with different issuers. + +The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). + ### TokenManager ```go @@ -51,19 +63,35 @@ type TokenManager struct{ } ``` -### FreezedAddress +By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. -List of addresses that is freezed by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. +### TokenDistributor -### Params +```protobuf +message TokenDistributor{ + []address distributor_addresses = 2; + DistributionSettings distribution_settings = 5; +} +``` -```go -type Params struct { - AllowFunctionalities []string `protobuf:"bytes,1,rep,name=allow_functionalities,json=allowFunctionalities,proto3" json:"allow_functionalities,omitempty"` +### DistributionSettings + +```protobuf +message DistributionSettings { + string max_supply = 1[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; + string max_ratelimit = 2[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; } ``` -## Genesis State +`max_supply` defines the maximum number of tokens can be minted. + + +### FreezedAddress + +List of addresses that is freezed by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. + + + diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 1461d418..484518e1 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -13,7 +13,6 @@ order: 4 Issuer address Managers [ ]address Distributors [ ]address - ContractAddress string Symbol string Decimal uint32 Description string @@ -40,14 +39,26 @@ Example token.json: { "Manager": ["realioabc..."], "Distributor": ["realioabc2..."], - "ContractAddress": "0x...", "Symbol": "riel", "Decimal": "rielio", "Description": "", - "SingleRepresentation": true, + "EvmEnable": true, + "AllowNewFuctionalities": true, + "FunctionalitiesList": [], } ``` +Validation: +- Check if Creator is whitelisted. We only allow some certain accounts to create tokens, these accounts is determined via gov proposal. +- Check if token has been created or not by iterating through all denom existing. +- Sanity check on token info like decimal, description, + +Flow: +1. The denom for the token will be derived from Creator and Symbol with the format of asset/{Issuer}/{Symbol-Lowercase} +2. If `EvmEnable` is true, create a dynamic precompiles for the token. +3. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store +4. Save the token management info and distribution info in the x/asset store. + ## 2. AssignRoles `MsgAssignRoles` allow issue to set role likes manager or distributor for the token. @@ -90,6 +101,15 @@ Example privilege.json: } ``` +Validation: +- Check if token exists +- Check if caller is issuer of the token +- Check if manager doesn't exist in the current managers list of token +- Check if distributor doesn't exist in the current distributor list of token + +Flow: +1. + ## 3. UnassignRole ```go diff --git a/x/asset/spec/05_query.md b/x/asset/spec/05_query.md new file mode 100644 index 00000000..16f2d486 --- /dev/null +++ b/x/asset/spec/05_query.md @@ -0,0 +1,102 @@ + + +# Queries + +## 1. QueryParams + +The `QueryParams` allows users to query asset module params + +```go + type QueryParamsRequest struct { + } +``` + +```go + type QueryParamsResponse struct { + Params Params + } +``` + +CLI: + +```bash + realio-networkd q params +``` + +## 2. QueryToken + +The `QueryToken` allows users to query a token related information + +```go + type QueryTokenRequest struct { + TokenId string + } +``` + +```go + type QueryTokenResponse struct { + Token Token + TokenManager TokenManager + TokenDistributor TokenDistributor + } +``` + +CLI: + +```bash + realio-networkd q token [token-id] +``` + +## 3. QueryAllTokens + +The `QueryAllTokens` allows users to query all tokens related information + +```go + type QueryAllTokensRequest struct { + } +``` + +```go + type QueryAllTokensResponse struct { + TokenInfo []TokenInfo + + } +``` + +```go + type TokenInfo struct { + Token Token + TokenManager TokenManager + TokenDistributor TokenDistributor + + } +``` + +CLI: + +```bash + realio-networkd q all-tokens +``` + +## 4. QueryFrozenAddresses + +The `QueryFrozenAddresses` allows users to query all frozen addresses + +```go + type QueryFrozenAddressesRequest struct { + } +``` + +```go + type QueryFrozenAddressesResponse struct { + FrozenAddresses []address + } +``` + +CLI: + +```bash + realio-networkd q frozen-addresses +``` \ No newline at end of file diff --git a/x/asset/spec/05_logic.md b/x/asset/spec/06_logic.md similarity index 96% rename from x/asset/spec/05_logic.md rename to x/asset/spec/06_logic.md index a5ac770f..4984abb3 100644 --- a/x/asset/spec/05_logic.md +++ b/x/asset/spec/06_logic.md @@ -1,5 +1,5 @@ # Logic @@ -59,7 +59,7 @@ This flow will also work with `QueryHandler`, as long as we can unpack the `msg. ### Enable EVM interface -The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module, where the token’s core state and functionalities are managed. +The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module's predefined precompiles, where the token’s core state and functionalities are managed. The token itself exists as a coin within the bank state, maintaining its own logic and functionalities independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. From 833a1f06a192a281a786c817d0bd03dbc43d3e53 Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 8 Jan 2025 20:17:45 +0700 Subject: [PATCH 06/53] rename priviledge to funtionality --- x/asset/spec/01_concepts.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index dbf44cb6..785ed571 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -6,15 +6,15 @@ order: 1 ## The Realio Asset Token Model -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 role by the issuer of the asset. +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 `manager` and `distributor` accounts. These accounts are assigned role by the issuer of the asset. -### System of privileged accounts +### System of functionality accounts -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. +Functionality accounts of a token are accounts that can execute certain actions for that token. There're are several types of functionalities, each has its own logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these functionalities from the `Asset module` logic, meaning that functionalities will be defined in separate packages/modules, thus, developers can customize their type of functionality without modifying the `Asset Module`. Doing this allows our functionalities system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our functionalities 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. +In order for a functionality to integrate into the `Asset Module`. It has to implement the `Functionality` interface and has its implementation registered via the method `AddFunctionality`. Once that is done, we can make said functionality 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. +It's important to note that the token manager can choose what functionalities 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 functionalities will be assigned to the token manager in default but the token manager can assign functionalities to different accounts later on. ### EVM enable From 2bfccc3195458b79bad21c34e95fe55e81c06b7c Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 8 Jan 2025 20:23:09 +0700 Subject: [PATCH 07/53] arrange state spec, nit --- x/asset/spec/01_concepts.md | 3 +-- x/asset/spec/02_state.md | 23 +++++++---------------- x/asset/spec/03_params.md | 10 ++++++---- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 785ed571..cc596e99 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -18,7 +18,6 @@ It's important to note that the token manager can choose what functionalities it ### EVM enable -While it is useful to represent the token in bank module, enabling the token to be in action in evm environment is very convenient and pave the possibility of integrating new features into the ecosystem. +While it is useful to represent the token in bank module, enabling the token to be in action in evm environment is very convenient and pave the possibility of integrating new features into the ecosystem. Each token can be enabled to work in the evm environment by the token manager, which means user can interact with the token through evm side like metamask or anyother evm wallet and more other protocol integrated in the future. Note that, token manager can disable or enable the token to be used in the evm environment. - diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index b65ab168..1be8178e 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -57,7 +57,7 @@ type TokenManager struct{ ### TokenDistributor ```go -type TokenManager struct{ +type TokenDistributor struct{ Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` DistributionSettings DistributionSettings `protobuf:"bytes,12,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings"` } @@ -65,26 +65,17 @@ type TokenManager struct{ By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. -### TokenDistributor - -```protobuf -message TokenDistributor{ - []address distributor_addresses = 2; - DistributionSettings distribution_settings = 5; -} -``` - ### DistributionSettings -```protobuf -message DistributionSettings { - string max_supply = 1[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; - string max_ratelimit = 2[(gogoproto.customtype) = "cosmossdk.io/math.Int"]; +```go +type DistributionSettings struct{ + MaxSupply string + MaxRatelimit string } ``` -`max_supply` defines the maximum number of tokens can be minted. - +`MaxSupply` defines the maximum number of tokens can be minted. +`MaxRatelimit` defines the ratelimit of tokens can be minted per epoch (each epoch last 1 day). ### FreezedAddress diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index ddb8c53d..bd1fc1ae 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -6,12 +6,14 @@ order: 3 The asset module contains the following parameters: -| Key | Type | Example | -|----------------------|----------|------------------------| -| AllowFunctionalities | []string | ["burn","freeze"] | -| WhitelistAddresses | []address| ["realio1..."] | +| Key | Type | Example | +|----------------------|---------------|------------------------| +| AllowFunctionalities | []string | ["burn","freeze"] | +| RatelimitDuration | time.Duration | "86400s" | +| WhitelistAddresses | []address | ["realio1..."] | ## Details - AllowFunctionalities: list of functionalities that the module provides. They can be update after the chain upgrade to enable new functionality add-on to the module. +- RatelimitDuration: duration of ratelimit for `mint` functionality. - WhitelistAddresses: list of the address that's allow to create new token. From 620a7237029801cf00740dd6c235da59df6d57c1 Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 8 Jan 2025 20:33:45 +0700 Subject: [PATCH 08/53] nit --- x/asset/spec/01_concepts.md | 2 +- x/asset/spec/02_state.md | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index cc596e99..51be75c9 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -14,7 +14,7 @@ Functionality accounts of a token are accounts that can execute certain actions In order for a functionality to integrate into the `Asset Module`. It has to implement the `Functionality` interface and has its implementation registered via the method `AddFunctionality`. Once that is done, we can make said functionality available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process. -It's important to note that the token manager can choose what functionalities 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 functionalities will be assigned to the token manager in default but the token manager can assign functionalities to different accounts later on. +Currently, there are 2 type of functionality accounts: `manager` and `distributor`. Each can execute different functionalities. While `distributor` can control the `mint` functionality and custom the `DistributionSettings`, the `manager` can execute the other functionalities like `burn` or `freeze` and could modify the `functionalities_list`. It's important to note that the `manager` can choose what functionalities it wants to disable for its token. ### EVM enable diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 1be8178e..eac54ef7 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -16,13 +16,6 @@ The `x/asset` module keeps the following objects in state: | `TokenDistributor` | TokenDistributor info of a denom | `[]byte{4} + []byte(id)` | `[]byte{token_distributor}`| KV | | `FrozenAddresses` | Frozen Addresses bytecode | `[]byte{5} + []byte(id)` | `[]byte{[]address}` | KV | -### Params - -```go -type Params struct { - AllowFunctionalities []string `protobuf:"bytes,1,rep,name=allow_functionalities,json=allowFunctionalities,proto3" json:"allow_functionalities,omitempty"` -} -``` ### Token From bcfd73dca2a18224dde3bd49ffdcabc0faa46dd0 Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 8 Jan 2025 20:40:50 +0700 Subject: [PATCH 09/53] nit --- x/asset/spec/06_logic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 4984abb3..45077243 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -29,7 +29,7 @@ This interface provides all the functionality necessary for a functionality, inc All the `FunctionalityMsg` of a functionality should return the name of that functionality when called `FunctionalityName()`. A message handler should handle all the `FunctionalityMsg` of that functionality. -### Upgrade Priviliges +### Upgrade Functionalities All functionalities are located in a seperate packages, for example: asset/functionalities, therefore the exentsion or upgrade of functionalities is unrelated to core logic of `Asset` module, all the modification and addition happen in only asset/functionalities package. The core Asset module does not need to be aware of the specifics of functionality handling. It interacts with functionalitys through defined interfaces or protocols. From 4df2c1cdef6e3447f60db59136844b8f5ef67b9f Mon Sep 17 00:00:00 2001 From: Trinity Date: Thu, 9 Jan 2025 11:38:20 +0700 Subject: [PATCH 10/53] rename functionality to extension --- x/asset/spec/01_concepts.md | 8 ++-- x/asset/spec/02_state.md | 29 ++++--------- x/asset/spec/03_params.md | 6 +-- x/asset/spec/04_msgs.md | 87 +++++++++++++++++++++++++++---------- x/asset/spec/05_query.md | 2 +- x/asset/spec/06_logic.md | 2 +- 6 files changed, 82 insertions(+), 52 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 51be75c9..ed473ff0 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -8,13 +8,13 @@ order: 1 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 `manager` and `distributor` accounts. These accounts are assigned role by the issuer of the asset. -### System of functionality accounts +### System of privileged accounts -Functionality accounts of a token are accounts that can execute certain actions for that token. There're are several types of functionalities, each has its own logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these functionalities from the `Asset module` logic, meaning that functionalities will be defined in separate packages/modules, thus, developers can customize their type of functionality without modifying the `Asset Module`. Doing this allows our functionalities system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our functionalities system. +Privileged accounts of a token are accounts that can execute certain actions for that token. There're are several types of extensions, each has its own logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these extensions from the `Asset module` logic, meaning that extensions will be defined in separate packages/modules, thus, developers can customize their type of extension without modifying the `Asset Module`. Doing this allows our extensions system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our extensions system. -In order for a functionality to integrate into the `Asset Module`. It has to implement the `Functionality` interface and has its implementation registered via the method `AddFunctionality`. Once that is done, we can make said functionality available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process. +In order for a extension to integrate into the `Asset Module`. It has to implement the `Extension` interface and has its implementation registered via the method `AddExtension`. Once that is done, we can make said extension available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process. -Currently, there are 2 type of functionality accounts: `manager` and `distributor`. Each can execute different functionalities. While `distributor` can control the `mint` functionality and custom the `DistributionSettings`, the `manager` can execute the other functionalities like `burn` or `freeze` and could modify the `functionalities_list`. It's important to note that the `manager` can choose what functionalities it wants to disable for its token. +Currently, there are 2 type of privileged accounts: `manager` and `distributor`. Each can execute different extensions. While `distributor` can control the `mint` extension and custom the `DistributionSettings`, the `manager` can execute the other extensions like `burn` or `freeze` and could modify the `extensions_list`. It's important to note that the `manager` can choose what extensions it wants to disable for its token. ### EVM enable diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index eac54ef7..ac45452d 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -16,7 +16,6 @@ The `x/asset` module keeps the following objects in state: | `TokenDistributor` | TokenDistributor info of a denom | `[]byte{4} + []byte(id)` | `[]byte{token_distributor}`| KV | | `FrozenAddresses` | Frozen Addresses bytecode | `[]byte{5} + []byte(id)` | `[]byte{[]address}` | KV | - ### Token Allows creation of tokens with optional user authorization. @@ -41,12 +40,14 @@ The `issuer` is the address that create token. They can control all informations ```go type TokenManager struct{ Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` - AllowNewFuctionalities bool `protobuf:"varint,10,opt,name=allow_new_fuctionalities,json=allowNewFuctionalities,proto3" json:"allow_new_fuctionalities,omitempty"` - FunctionalitiesList []string `protobuf:"bytes,11,rep,name=functionalities_list,json=functionalitiesList,proto3" json:"functionalities_list,omitempty"` + AllowNewExtensions bool `protobuf:"varint,10,opt,name=allow_new_Extensions,json=allowNewExtensions,proto3" json:"allow_new_Extensions,omitempty"` + ExtensionsList []string `protobuf:"bytes,11,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` EvmEnable bool `protobuf:"varint,9,opt,name=evm_enable,json=evmEnable,proto3" json:"evm_enable,omitempty"` } ``` +By setting `allow_new_extensions`, `issuer` can specify whether they accept new extensions or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `extensions_list`and the `manager` can then modify the `extensions_list` as he sees fit. Otherwise, the `manager` can not chaing the `extensions_list`. + ### TokenDistributor ```go @@ -56,32 +57,18 @@ type TokenDistributor struct{ } ``` -By setting `allow_new_fuctionalities`, `issuer` can specify whether they accept new functionalities or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `functionalities_list`and the `manager` can then modify the `functionalities_list` as he sees fit. Otherwise, the `manager` can not chaing the `functionalities_list`. - ### DistributionSettings ```go type DistributionSettings struct{ - MaxSupply string - MaxRatelimit string + MaxSupply math.Int + MaxRatelimit math.Int } ``` `MaxSupply` defines the maximum number of tokens can be minted. `MaxRatelimit` defines the ratelimit of tokens can be minted per epoch (each epoch last 1 day). -### FreezedAddress - -List of addresses that is freezed by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. - +### FrozenAddress - +List of addresses that is frozen by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index bd1fc1ae..9cad431a 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -8,12 +8,12 @@ The asset module contains the following parameters: | Key | Type | Example | |----------------------|---------------|------------------------| -| AllowFunctionalities | []string | ["burn","freeze"] | +| AllowExtensions | []string | ["burn","freeze"] | | RatelimitDuration | time.Duration | "86400s" | | WhitelistAddresses | []address | ["realio1..."] | ## Details -- AllowFunctionalities: list of functionalities that the module provides. They can be update after the chain upgrade to enable new functionality add-on to the module. -- RatelimitDuration: duration of ratelimit for `mint` functionality. +- AllowExtensions: list of extensions that the module provides. They can be update after the chain upgrade to enable new extension add-on to the module. +- RatelimitDuration: duration of ratelimit for `mint` extension. - WhitelistAddresses: list of the address that's allow to create new token. diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 484518e1..53da4436 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -17,8 +17,8 @@ order: 4 Decimal uint32 Description string EvmEnable bool - AllowNewFuctionalities bool - FunctionalitiesList [ ]string + AllowNewExtensions bool + ExtensionsList [ ]string } ``` @@ -43,17 +43,19 @@ Example token.json: "Decimal": "rielio", "Description": "", "EvmEnable": true, - "AllowNewFuctionalities": true, - "FunctionalitiesList": [], + "AllowNewExtensions": true, + "ExtensionsList": [], } ``` Validation: + - Check if Creator is whitelisted. We only allow some certain accounts to create tokens, these accounts is determined via gov proposal. - Check if token has been created or not by iterating through all denom existing. -- Sanity check on token info like decimal, description, +- Sanity check on token info like decimal, description Flow: + 1. The denom for the token will be derived from Creator and Symbol with the format of asset/{Issuer}/{Symbol-Lowercase} 2. If `EvmEnable` is true, create a dynamic precompiles for the token. 3. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store @@ -102,13 +104,17 @@ Example privilege.json: ``` Validation: + - Check if token exists - Check if caller is issuer of the token +- Check if addresses is valid - Check if manager doesn't exist in the current managers list of token - Check if distributor doesn't exist in the current distributor list of token Flow: -1. + +- Get `TokenManager` and `TokenDistributor` from store by token_id +- Loop through addresses and append manager addresses to `TokenManager.Managers`, distributor addresses to `TokenDistributor.Distributors` ## 3. UnassignRole @@ -125,35 +131,45 @@ Flow: } ``` -## 4. ExecuteFunctionality +Validation: + +- Check if token exists +- Check if caller is issuer of the token +- Check if addresses is valid +- Check if addresses is in `TokenManager.Managers` or `TokenDistributor.Distributors` + +Flow: + +- Get `TokenManager` and `TokenDistributor` from store by token_id +- Loop through addresses and remove manager addresses from `TokenManager.Managers`, distributor addresses to `TokenDistributor.Distributors` -After setting the managers, the managers can execute their allowed functionality. +## 4. ExecuteExtension + +After setting the managers, the managers can execute their allowed extension. ```go - type MsgExecuteFunctionality struct { + type MsgExecuteExtension struct { Manager address TokenId string - FunctionalityMsg *types.Any + ExtensionMsg *types.Any } ``` -### Flow - Validation: - Checks if the token specified in the msg exists. -- Checks if the functionality is supported. -- Checks if the `Msg.Address` has the corresponding `Functionality` specified by `FunctionalityMsg.NeedFunctionality()` +- Checks if the extension is supported. +- Checks if the `Msg.Address` has the corresponding `Extension` specified by `ExtensionMsg.NeedExtension()` Flow: -- Prepare store for the functionality of the token via `MakeFunctionalityStore(functionality name, token denom)`. That store is the only store accessable by the functionality's `MsgHandler`. -- `FunctionalityMsgRouting` routes the `FunctionalityMsg` to the its `MsgHandler`. -- `MsgHandler` now handles the `FunctionalityMsg`. +- Prepare store for the extension of the token via `MakeExtensionStore(extension name, token denom)`. That store is the only store accessable by the extension's `MsgHandler`. +- `ExtensionMsgRouting` routes the `ExtensionMsg` to the its `MsgHandler`. +- `MsgHandler` now handles the `ExtensionMsg`. ### 5. Mint -This function only can be executed when the token's `FunctionalitiesList` has `mint` functionality. +This msg only can be executed when the token's `ExtensionsList` has `mint` extension. ```go type MsgMint struct { @@ -164,6 +180,20 @@ This function only can be executed when the token's `FunctionalitiesList` has `m } ``` +Validation: + +- Checks if the token specified in the msg exists. +- Checks if the extension is supported. +- Check if addresses is valid +- Checks if the distributor address is in `TokenDistributor.Distributors` +- Checks if mint amount exceed `MaxSupply` or `MaxRatelimit`. + +Flow: + +- Get `TokenDistributor` from store by token_id +- Mint the asset for corresponding reciever +- Increase the ratelimit + ### 6. UpdateDistributionSetting Distributor can change the max supply and mint ratelimit of the token. @@ -176,16 +206,29 @@ Distributor can change the max supply and mint ratelimit of the token. } ``` -### 7. UpdateFunctionalitiesList +Validation: + +- Checks if the token specified in the msg exists. +- Checks if the extension is supported. +- Checks if the distributor address is in `TokenDistributor.Distributors` +- Checks if current supply exceed new settings `MaxSupply` + +### 7. UpdateExtensionsList -Manager can update the `FunctionalitiesList` of the token. This only can be executed when the token's `AllowNewFuctionalities` is enable. +Manager can update the `ExtensionsList` of the token. This only can be executed when the token's `AllowNewExtensions` is enable. ```go - type FunctionalitiesList struct { + type ExtensionsList struct { Manager address TokenId string - NewFunctionalities []string + NewExtensions []string } ``` +Validation: + +- Checks if the token specified in the msg exists. +- Checks if manager addresses is in `TokenManager.Managers` +- Checks if the new extension is supported. + ### 8. UpdateParams diff --git a/x/asset/spec/05_query.md b/x/asset/spec/05_query.md index 16f2d486..8faec520 100644 --- a/x/asset/spec/05_query.md +++ b/x/asset/spec/05_query.md @@ -99,4 +99,4 @@ CLI: ```bash realio-networkd q frozen-addresses -``` \ No newline at end of file +``` diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 45077243..59a636cf 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -63,4 +63,4 @@ The token includes a field named `evm_enable`, which allows it to integrate with The token itself exists as a coin within the bank state, maintaining its own logic and functionalities independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. -### ERC20 Precompiles \ No newline at end of file +### ERC20 Precompiles From fdbd06e759faf832896dbca218633b628bb20f4d Mon Sep 17 00:00:00 2001 From: Trinity Date: Fri, 10 Jan 2025 19:50:41 +0700 Subject: [PATCH 11/53] Update images --- x/asset/spec/imgs/asset_evm.png | Bin 152790 -> 115135 bytes x/asset/spec/imgs/asset_module.png | Bin 283301 -> 399432 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/x/asset/spec/imgs/asset_evm.png b/x/asset/spec/imgs/asset_evm.png index fd7843d2e56d3d408913fbe63a86b0b44b1698a9..568a90ea39f729e304e1d870121bfb9dc4e7ed5b 100644 GIT binary patch literal 115135 zcmeFZby!wg`z_42MNv@^MFAyLkdl-(2x(~~6{Jf*x-1M*Q9xRyK|s3008~Vf5NQ>W z29fS>EMsr>ugeLxi14|N;-9ZND&I#SU7oqi*p}hP~xVqBLuOqSB z$oIsRFWtHldgA((dshNZ@E$G5FX#Kndi~0kE02z46dx;yJ$&=8wQfa~D9i9`;-DT6<0luj3nEA{5%Qy;=T=2dt*NCxvnwpzHVLH;_~uxm*2MW*4px??<1~U zF+X%t_QlmJC+_%M`TX+T*ZRkti9DLPJ!@)vPyEH7q3p-Oa(_!|4TH^I=~1D{dvc`j#DZqiNEiPnI)0%f-1izHQzpO29*S zQfjs;dU<&@$vRu(P3h0?m5`9^Cy^36q2d%V)Zy$VYrMQX=6ITw+Uz!~N%nzTS}6xk zC$7tBtk*PS%E=bjYSl7TRBhd!T*1m@*4%1tYN@Ab?&&RU!6hHhehw_^J zGynQUfY|r7E8jqK`_sQJA+-G&<;s6|Vz|n_^6%eIuhCoi_fL0;DEsGCPEYRk*FS$H zxhzTd{|4}Xe+Gokn3*Ln&GynV9y-)Jp|WDaNo;)`}-Wgp*5Lrw2mxJl^|L3+|+( zbZqDr7Z)dYD_H;0f_HJeR@CL|UCH~Ro=Xu?^1&9o;UCiV(!+SnlPy{@`Gu)hT-1v6 zSx8aeo1i0eOY@^SHr*1bx+QbD{_gBISw_@D*mUYgI*M}ec*7qvPQ8EsKE7K-M1+)- zRH@8kapL6;h4u_*+)yq`=&V+rmFm*M>}2I$>%{XfZZr=!JUX?W`q;(ef!r5A9WPm& zYC9WMWZA}>s+A`nATpO2#%=nzipF&)w~TdZ|Z(z_d(%s!1 z6E7Fe%)xPnQ6^aB_I5_!<;kfjH6^9M(uE%~cxuzeL`9c@q=b<^^K#E4lNMd2Iw@+Y z_4RQw9V2=A6{Ks|uI0};bm)-zNPB?*7VP=+=T^HlY~mE6MKrUF{E{p?3hk4%3o@(6 z187Cl<|YTjTMx=dBvR@+J?n3m31MS8c1(jeyv9VU*eT=W$&;DF3V%k6KdtzfOWPUE zo73!%Okh&nc}(h#+YdA<9zTA$xVSh|DDU)LIx2xneU?#7N=ix-i_=|4n3<)$NGX)? zB=_&%k9~1-t9e_lW&E~VMZxTPBb+mw=gLW9=4yvpvUtotu<)2Qz8bcf9&YR1>2f#r zxz{G+7USimMS06>>$j?DXgnaLV7_1`>amdDFgVcKL&A?LNjX72Su2lCW>?2*quQv{@87?-3B;#7mrhDbl9$mXqZJX-dKO|>9n7EO zb@OJ5N|MsqDSn5c2g(TRhUJCYCd;;$*YSP)3!lh3>`Rh=`#N&ZVWLX6^YI$?EB82*8w!pPw^p zJbn11r#fL1C0k!st%%(mpW|0%mF<+22{SWJvvYHu-{;iRb(`|KJj~4o>*IV1?FSt? zJZ^5Kb!b^?P!Q!`t0y0E?DLQIF3;u2m5{r?3R^>lStaq|U#r)dwCCGMXa&#+Zzys4 zxkcr|d6RWZT!O0?XJ%$hhCXHx0eapmeQ{tlP{NwA<)-5zbeLvbgfgLxRR{-@VdHNY!%GsHj zuM;~z-N2j`SkQ8t+|hOJp*YL3E3ayxy}&NGie;D2^A|6g5)^2a=dt@H+wE#QE)Jc| zG76pQa_*(>sR^GhbVo2<$kEIaDz)wsX-Za=d6VdN&zb39QDbA{-gjG9E<}xe0cksh zsi~>sg?2o|a7U54dYX0teRtO=6`$2mW3I!nX369StrpUf{21r)Z={I&HE9}Y#k=?ggY*E7~ci|Q@TPpjuyb#NoXYa#{ts(UPGR04#j9$dY4P0liiS+$V9 z8Ca=Q}n>(=boA9b@$-jh|W{^wcu zAIfM{+)^0&sT$aMpIuL+=S`15RyG!<#e!F=9-D`PhK9}B+8S7E{;B+mw~r53WZ9*D zB_{gsXC9qgn=qE9QxxyFm(Q#v(@+2rpCRjCR#vvKu%J@nV$WmUsr}bqf3q9Q%cNd(8YDJeD@qwK?cEn(A2fx0)7hflR`t+^Rxq+0uY$bNX ztvr@(xpEyvj%6dx#5N%<6$4<_JvEcbw4Vvz`56INVvH1*C5RB43*5d%t&TB4E?)J;A3FkB3gYd3qmzx)Mol<#p(#y(exUo?M5%I2(*Q9R0@^|sT$1yQFOW}fr zcq3W*`hT9VJW}F2<9bYsctgCL^83f)st=F<6)EDbiMUWwQMtc;$By(iJ^=wuA4>KQ z=IJF49pnD{_-$X*`9w!YN4fowGFbjn;X}n^cE5D?+ul4q84HUiSe)cwRxPuc@1I+? z#A#!n0vf zcjlOfD3YDtvpfQlZ`PC?WcqfrY*|-PQL&jCKqh0Q^Dpqc{YhpEmS%3ELBYDvGgUJu zqLov9$!U3UT5f)6X~_jYP*71NPfT2@sH&>&>e9o$4Pqd+HnuCTD(&mHRaJ+o&%GOH zN||i4E;Gd>GM~+iZ5Z3bWn?n;rDC8l>7L6(-}!9Mu?k9L;=l}A3W_*Zt=!#zQKd8u z?EKN+RaO?|K6N%PIr4&}re+v|SJu*feySw3`PERUan#YZdQa3+z6%#} z&NMAkjFBJ!zP(W5Te&Q96GIYaBi6kozSDKIUvzmkAj5O!`}w@IjVsq%?0dzj zHS5+5+&&a_28lCSCFwDi@0cpt-B_$-_>_Txf#2}Mhx-v%3Trp*;%+6SWU~+u<>ch7 zuB)zlbgBtdgV=LOU;;>mYELvC-QIC1>|K^-s#$YdBo_V~cQkkwGaH*cy@W4uk0|GF zdvr?O&Vng$MjB_eWZMs_<(M`|EH8`)5Hpjkrk`iqBb^X;&8o>SdH4b&NC2LuNm)Ud zQBO~g;)t3okpBJbcyA8K+i**kB(lEE?C3YMvoV;*2gwB*scNh`g^icw5w`7NZC;xw zvoC%=sjL+#U?1yS=U1U`GrJ_M^x_5?;QNU3_Z}oQyTQVLriG+kYK`8A;w~TYT9NrD zSjmK^PdP%Gl(m@@ABzQd%S8$_?R2r}0Z)*(L?#UrcFkp0PqWDGc^9dL$*8;h*XoJ6 z!F2P^VrMEYBVQXKJbbjB9)HV4eD=$iFPRYycMhCFTG64= z$}+04+*+FNvNf|lR%!=UZhHwWE|1&m0IkqCQes%}K$caR$%*ermYQFIU`W zSLjvt&@LIDipT57sPcJgF-ymCn$mQ%0>2IqgIKySadOrhb|HTx%Z75s^QJTm;}pkz``rCkL9SMBMT-v=xn*n3x3YzWGW7&_wop+_a13 zqUPhO_aH^YE^>Bu?)aWlF!(lN=C*d-CmEl*)*C61|(eHOBM{g%TA4@zLM z?lqbHWFP`%j-#D#LfE^=s^sM4n($dUON^UuF|~NA)jW*PI;z@?&yR{HFfT99&D~wD z>9Rkqs1@m{l_@i?=S}}cp;rrwi%n&oo+Zmm^Q~FN0pH$+#;EH$ivuh8C|vG-<-D*R z)kKJ{%j?vo(A5k&g_jDf`YIIXr-uD{?1nr*GgxXx@od;*B`g7>2*y)4HXqFar)Vez zXVdds?D??JZa+6++E9vwmaLYVoUEE+HaF2vfIsL*P#cwtqQvBbw?i^}#l^&qQQJLP zXD1Axw@*%N03tSc0K&O#zn)Gg1?2Gs8@Wupmz1l@On$y1{g!u}tO(ghR0WB8WgdC< zvg*~t69Y{$ot-0#%54_B4IZGqnf8lsWxmA5#~V41Aav6OKNLHU%MzeA2N>pd{&Aru zl&i{QxjR7g>)>E`s?n|R_x1KRczKaUJo_tAm+F`ceWvm@3kENR-+95o@3U; z+)x1Ub2#F3FDxvX*#50U)h33xyxrtThn8}@>|KVn>({4vE-zJ%0bNXb-$hm~y^oR1 znqIYHMe=JBX9BOapN&6Q1Zw@YQ7v6pIB#CB@Y3t-QLA$jfp`%lKD?D#?Ma`*^4li; zeY3N(KLJ)X`99WBu8K{!xNnN5-R8$vsRj?QN9)0v=5gdg!JLxWZ{hNm=_ONPTHOSe z6*-Rb=GgbwivzyxotHj6yT)VHe$0s&F*u%pk-T>TH6&Tb}=r4%WEjPbabm8g!u~GY;HxvY$1xzS|2`?>-D=;2B zIIu7~Ug$LT7zHJpUg;BT90CU!rSG3XPEjp(vI%0Gwx<@bU=X0#PIt}OVDTtW12Hd{=K9tK?rPyg~@4FS+2~kJL zY{9;LYe~zc&elsOLdm9mCm2To3LToGpQD)42@nMhf zmwUi*VlC;;{LehByL@f{HZZaRArbevOF*x8AJbKm0{fk0W#5ve-=#*y8Nc}H)2BAx zsV8T%P*BFO1oT#iC}69-&o*ty6iPtd!B;Ggsc{=Ula0!3r`S*3+|q=iX7~e-=+aC#%QgNImq{fAgPf(|oBMacwK8a_ zsfWQ)40ANC2c7)eL(QxFsk4MWl)AeD8wYL}Tu_yJ)xj8;8R*QPOtzP|z20dB(6*B@ zgGYjVbxa-AQFUv{vyO&BfKUM)LCV$*J8Ezvi2zW|5|m_~v@Mksq`v}q_hYz0y zowpbGkftM;mmV65Cn2Z?pYd=jYQ7XE<@nw6q6^=zp-2f#?a5v-pyeon>xV^zp60vQ0+~+1(dY7>z@9b<@u6<(K5YKjv9R-5bWS$1g0E*LZwb9nulf!M(@!!52 z#zSK?gpAMz$W>OQS@BpS>rkI7eyb~oZsRGL#&xOhOv%#RV5JAZEvu=ktxapkLD@6Y zBOQ}9d|f7lSn$+42CHB{(tegzGy7u7RXOZ2za9_Zzwp|1>!^ql@`h;%=H{!GPd0b&MKqQ%9pd7Mydpo5&HK}D5Ba18wa$o~EN+n&)mu35icFb7GH zwVLsf_MT%GAEK&FBxI)-TSbXEwQ|<&?Cf;uj|-7~6a$VTi~kR?-ZWeBWUtuLC-91h zdU=h3mshRJeLC{$)vJxbWFq6<9c0lf)h0+jGWg_Fn|0R@C*yY!?_08rgMx$O0WZP} z-(UQgoFs&$Ea49*G3-&%fOLEh?hT5FV3FeE2^f@;mPRog=)H?Id9-w19(zNPSgTx% zvmw<|9aboOy?uQfDfQeANF^&L_Ds|j*I_%+r$~q^jk{=Q(yTfPdp<_282HwM zSJ}&jSq>aHK_DPNd^E|M`R?7j-nVXXObK43M$hVAU!RG%ghVIDkiLQ& zcx`Qu%^SK!TE~!U&lj&f-E9?AlDX>>)6BB46BQ(nv9VuQGWM4_M-s}fcD203Z#j6B zMqxp>-6n@p&~cOg$7>vq9zCL&Z5_48D)D0xZJsEqIN~eKG$5f6bF3*gh3=B;gY)0t!RRGwo{OkA1ENdkwN+T;r6$~r@r?b z1bID-8lxwpuI>!R9I%xbRX+QLEv46Q+%Q8K%r9^VzuAAtuvAh6WYhm0k*%j`T(=!e zfx7dc?U1^>LV1H2#Q3-nUEA5JJt(s=CUboBx-Q;IygvPP!u~k^yzl{>eR8x*?~p>2 z3IuWAhdw$NF2vH&)2pUw^V2h23-69>*zuhqRC&Qc#c9P%lcZfp8wf0@yWt)^z|MEm zo81bya&eDKe{(u5#h<$ncPh6xOk36cN_WxA>}reT_X@JKVBSo2bFnW(1M<)7f+Pgt z$mi^VjbQ4*B5wd)eA~#$A0;LpR@O2xIjs7xE6Qc5du~Md1P7h{`+$g!Te?AwvtA8pbJYc9=5LR z1ims2O(7IH#mS1lo>5YAhHPB9&0jI8xWA^t?+5izL*j0 zdqqyMvSV0Y!Z2%|hF4lU8k`vF?)4uBJT8^*ccN~e>#ipHz{>l+nRymL_P#IOc z?dx!jC;Ik(zuH;dWVXHlsYDws0aBlFN*5$&ZqFq*DJ2lzMyNA+^Qh@G2;CEDf5hoK zBPXX4N-LCr4mM!mb~7y5RPTkl0qOTE!qG6UFb|XVdQ&>a8-_M4L4^|wjIALO9BCl|u z3X#SH73j@|M;C4y+@iB%ygw)Q zU^thtKT1({sX~{@WI|lKN#oMTTQl{}?Bml%VAK@U)U0}XT@g`RR@|7+&zt=Y1A1#s zAK8>*Pv_1N+`2M1FK_;A@>^9&+nz!@PyhMpQNCPgJD9>JnmN*eJNNCgxUS2XlB6Ug9f8WvE@t*2l2hl2KmX_ggowDVn zqKw7wFSZ&Nd7|tkZ#1oseQg=3C7-eWTxRBl*V~CY2bFs>8c!pw#lLUdPWvueG=0Y* z`NP7(I;bSg>KtAyULWc(9wvz%;hJynJ7%rxBXujuWF01oj_V zKoCIBEV~~Sm6mB(O{GWL?u(WJ{24{s-rQJOs3~gD3^Q|7n6NN+f~rH<%^_`QX6SqI zTDA9Ga)aXYCQ>l3ba6_{k49J%{~p2_)%GreUm2rOfrQkUW3G-rq@nEE3>MzpLQRz0 zalXAF&{H|6^E6Y@pvywQGfJU*P+}ZqLoDjlXQtlOEPxn9rh{3nd{0nzHh04kA-gzq z5%OjmAL+f=*w{XlR(v`Xm1CL#qDxM>^B7Ir$5J$n+GvYMa?$TeU}uNA)QIYxTG*wr zf8p&TO0-Q0N#)Ik4Jc@p1RaLXK#2EG+u;a#hUl&T?uhVOcd|%P@!Q4{Jt%{5j4Gc3 zGbeEI(`D#ashC~l6=H4~q2(n_;E zX94SM%LhWehi4!L`etDhyImJrJVitI?%a7Ob?=}lmO3!jWpW@1Gh)^d?>DygvS72V z_L1BZ*VZ+=yZb`}Z!B`Oh8PbGgl}_c1izic>({S;jE~z1l9xQXJf*0{@tE2-bnyd}$5_IMf!;FV zIcOLp8lI<5pAH_Ek(F&E%ogU&Z19^5CM85EAr@6i-JBa-9fS#F`tal|y{M>Yj#Wo% z|BN@q5h5QZY<(BFlbTwNFdRAgQVTkmz~zvs!Gf+@ro%|P>B5i3AhaF^{P;RKp7%iH zcn|2>xpQYM#4tl=Q6Xr$-JP$SgzuMZcDr;bo5+|bhNbpQm$v0uhcFPn4MLIr(Oc`e zSC=3AYJ|_YHmd3R#vR!%lV%CD&5-}4(u;q1qxTSDxE#nRLlvZs=Mk$dlBn!I`IT!wy99%**Ra5ns$fdkEH|b}_giX=-;HW{n2m8Lb_;|BtSJx7vPLexR z5+#WZgse}xWeYELG{^a?#CqCvSN8WOM1R0`ZOk%O=ypO6$q&cx&5>79jO(mPAHI zMwp;uT7#XU;CxAH_g2n(fq}BsdwDEdRbWjq3WZDO^89W`m#q(>3QzXEKlNtjIH%jp zMV%stnqyIX*18R|XbHIt=QN|sD!Rwg#>R%2bRs*%)ToLFf@G#(!QzQ-_TJB%qzD}f zLXceV&(I}z$+Lex`DQpCa0N^+G z4g~=E;&9U<)w_&P9O6YWVx=-uSZxl7HXP`KI z<~TaamHeTr$szq=(yOW@qdk`jD*dU=NzcEkxHbl&6@HZrsH=jyAEq6-VbA5oy#BdB zZigWa`iV^B3}_a*MAHy`w`zVXcs+Ky5LznXxPT4rRkn(P18t`k%dS+7jOW>EPq2*e zr|sOf?OZlkfQqoo#2Ek`5|i(g=i;DV{Mb_0^1P?S;rMgUuErb8{^+^K`TQgr^Ff@Q z*7LSf{-5_6-hY~RQ&+%o?k08znzqM;+vF4!_@eC8la$1fkWscokL^Pq zO%CI=Y$Xdxh1_$wm;T$ru)9Lr9&fk+4@&_` zKcEAo@7bh)DrVv-_W26`MxPhSu&8g1d#yOZ`pTokJ4FKFf%#|?2JR~KEhFR-=@o= zY`MMAJ_Xs-V1fAq8<=9e-VuU1SR>argZ=SfCn90W5-cedlyP=`ez3!_OBFmKP0O@m zZ1yYO7fOA#MccN6vIG%a(f z&~fl?3sPNJ8N^kSRfw(wVRemhM=F>@r4oeVCz+EI-5mOf$G+SAgg@%jcG-A>4Ftv_ z7l)l>C;Y0_zx=#%J9rgsxB+ z^M?o&kAauIyxbU*3hRQzg9;nnw3F<%8?uh+>IH%v$G{!ghc2{4c!|C&=q(n4Q3__k zqyA7K#@W(8_w*QE_aM5zP#OsNf+Mn-0C_+hI3};IF|1Mj5$HS(CPaHEIXUHzov^R; z-2tSyV#1QGFkUT>{=k@nxvD-07 zp%e!n4H~m(Y7$1_K{BEMBD#$r;b2z=W*u2mf(SS|Xhuh1sk!1C&Rq>9uW(8~8_ zH~csfMFu^)UF`#apnEJ)>v4Ih4Y{LhX|(3Z(1AOEKXdRIVpkPj>VF(1>2jvw70&H!@IdU=V7<)j!;Y0?8jE&nYwoE8l#l!)Q}AoyLD$VVa+Bg z^=H@C@9jqGT?XMtpm4j#B4&!e2S%96DZ5(Xgx)Aud62*+a8+3uO4uZla7EZl?{ju| zwvLhqnVLQZd*3}hg-X=Xc@Z@Lm8veJ8sCd9Zf?akTl+N5z8~|Tz(rqqBQFw}nJ`*` zw{VRZz+VT8W+FCk*G1n!Rz&-Xzm=*@Lj$K_ui%esyW+qasFjkMrcQsfjXS6tESfJ+;w#uxJ*8 z*u}vUp9F)Pe9uw4p1Cs7Zq#3|&2r2ze`rg1jh*v^>44Bc?%$oNWqxWSJmt-XhDgzf zGn}-1x$_hKF$$uKjWax!Fu`!cB)~+^aGz*_#wRnLKYw06u77wmeQ^^x>O)Ml)E)|3 zOymS6!W;`ahe|#N35FHYBq6+vbyvw5v|M9XOKIBhR=e2g{f0G!CE{3f#`A#1Yq6jz zV<*Nz);?hHEXYG&zh0mgank_7SAoD1>$|mNDlQyTX0+g{!LrM5AHNa^X5|b@{UFZd z>W@0bPKwbUb4g=^WUzuE)CJd`>x6SzxoJPLud5>J!D(+Gx?Pk7?l2*f?KQ=1Q;}mF_LzjaIWf zgkJURuBfL60Y}K-JW=z~#4!a~iYLQAzSWppjCPfYR@>0J^c{eyRXX%JTbjqiK6t$V zFzxk&h_cJQ2WD)e+rZ5U{o}eWAud8(9pr)3WY0)mcB!!kA^nqZcmM4fmsxmqa-e=<^!=bJ zsX{7l29OYXKR>JbEOD)?U090B#nyL`g7z?#vYyR+nIB^JB(1LxMw-eJWr+R0-nXVm zZ@iM49`4>;1jFebwt=^hvoes9PXFfE9Pd%RYlVxi* zQ*}l#%US*QYJpDnwh%8z0t>KsI(b(&bzci$fbXkfXW!FW15k9LUWBH80OalndJBO# z7{VZhj1W4;;R%-?kw9TeeFUrb04k?5=gvJOu#cQxVz)cyWt3YI+aA6-Nz}GM3_8c;<(K&K^*zb>h{D(X`?K|svXtQu2c0LXwZ!9BR*{mCsiFv#OXuIe|2P4K z5O@imnJ@+iV;btmhD;@F>?SZ4Zcv#RI^USfmq`+OuHRQwth55}B8uR#XI$vIPFSlw zJ$His)`fHqdMTLll!?M{&Ak|S^@tTjQ-r93-jBcw3f%7_Y$QnD5p&RcB;YFvuFzKm z$}&m;8hQL{@i@qEKfN57GE7@XA`5+gA#FC`d}QrZ9MK(!fkT~;>xrpS7JsofgI$q9 z3MQ91Y_~YyPZ`}x;{N+y)UlUL1ZFIvs7}F?KpZ3du*D@Ms_^qL(O-{%>RO`?L-OVM z4lV1FI3jHU)9VRuC=}0-UjEMB)(}O<3HbB()@o8mOC5<}o`D42_*i@s*}h|SCZlb6 z=^4Wxdtp80Og7OFYm+8I^)K zi6C5Jjg%T;yIUIXN`73uLQT8wLjk z(xKzuuw69`c~YHV%2Qa|6ktS?%IB)FLU?#y{}}B>JuVGz4ld-qlS%)&nw10u4U}-Q z%GifYpI`E~2cMf;1snLydw%D~gb)FB|3kQSX%evq&^RDk zQEb}z4~bF#b|qqFRG}vl4lRTix7U>*8&9iDU zv%zcUdEqfg!)fq15xTsfiWqoKAR7NhK5v0Y`Ko~0GT4B{+V+TP%& zG71XKu(ql^7TcJY9M(>D`}XbDr{}NX(96!G4N^r^k!X_f|D8Y1luCYJOQ_vr-U;O?Vo{}v2GZ` zqv0H803r)R6d^iBWAxQHcvbV@Xm_Cjm~|r5h-7dW{1HbKHwD}#=;V6L^&e{B{0?tn z1E#`MNVyX{1e;-FDZ-(>_tyd7avi8blD^%;AGhTtZG0Z;)#3&QE39QS_<@jt4Xk@@@voZGvF!^ zL%y<_Cf4QQiEG*CU#tsa(;<3R`Pk42oQ7{+H8-oHz-iHxa0mPg*nYi*{A6Udm5i*3 zFt8%ifcJJK^5T-0=P7^L-SRh~QJ#8bIl81MATT9ubp6uC+XwClY&z?=-RSwX^)|+d zcY_NBMOn|toG?gvZu;`()zp9-5liMdPX#u zAGYh5AGdMbf3sZQ@f`ie>kCU9c7j<&SA;A$1+&td`6Ei~Mk58gS}YDmv^$E7+SU5$ zE&T||z(OCxG&#<|fd=hre{81dgH#Za^DqKUJICuC@JdbKXPNpV9gAo^`?h_2n%eD_-RJ5-z)l7{3`qSD;OYm z32ZxkKH0Wls8^qFxO!Cmh$pMVF8P7c(E!^5mNkS-hS%FYSJ|o4XdK8*KE0mV^Z7Nt z!s8`Mu8HaCDx?>!l0WX6XCd+^(hE)R?H!;vxVX4j#FO(#*DpKIh)X-;P?HQ7`OG=> zw-TxEJ3mm?R8l!iPP-dWw>H+^#TlkV6=s{+o{-T=mtVIenY!^wW_@eR{Sc(6Q5*5s z7OLTir$ec;D8$SdMK{@LEjA}Cy~ZHJo5HH+>xNx5j+YLauJ1J_+EvgE$U zt&Vj57AhA|-IMuxGqr@t^~EF_EB-IH=)$rfe*LPKO!nq~M!BK%cz7XBA9X{Yw3_7n z0-@2rYrdq*N5SpOj#OPz*00U9zus%&dMGl0HBvPxPh@aPe} zS?MRbB?54;P(y&sDvZb7oIvu7C&RLDqRH_R>OQ_-XaD>taVN8!)`7U+6G&}E?5&~F zqLIQQZ8W&7mQ?|x?#y#a39*;c&^m@b;vmI7YnO)b%&O&a(dB!VWwSNb{)1^nY%VS? zMwU8d3q9=J=#u!sC{h7E+W?JUn^y;JzJ$Hic$nvb;6Q^%u5}j;juGCv^=g&steXgP zko3gVl*FSmx7z1|We4Fb&x6p_PUx<^U9!ulV#`8;`wl3|j ztf~rsCph%bpBU*LpE=AOX;(p^E*8je_Iq4j9-nla(%13XS3S0@ z8a%(oQ)jwH?;+XZOqHmWi`xq_zL&0D^PTzl0)X%->$cp~{xL|oU&74OZcE2)$7SEQ zwG~OGFITX89DRo_fa!d~4c%Zi9V&F4#;5yu9?b7zotvaR0JjJR3^8R$15-?1QYG1NOuy?U6#?CtM~0q*UVv-7aDu1 z0gHmrbV043u~7G(qS+A>$^vb+k<$4Q)A^Jpvs|6%iNNZf$7(4R;NzROY%x+khY>L| z{2I~6O+nIeO)@6@&nQi}_&P2r=Ptev@Zi>6o@*qv-vPIg}>{-iA6TOY1-v6 z+HTxlN!#hO*VuE)QjXHeRO^bpT{D$KGgsEr>?TMd9o-i+Mgs&#^67CJd=HAWpRq_s zx6~iKWUARgHZBQ|mkM)GqFTyPUfx|&fnp-j0cmMzx2R7%n45a}@};lp=^op&ByhD=f7dx0f!4^O<((z^2k-Os=nb>5rhh)jf1_4H_sU z#l#v0IhJuK?%Oz17aK|} zynX8!YSJt_)YVIb{4TPvg+m=F_0}zxC-u$ElmNvWH*eC*HSFHA=Qg(-e!#X+JiIeA z-Ong&l`?Zs=9}M38^oK7elK55PCho7?kU{n_}PoHl6K)4?MswOh=~Nz zMN=Y9EnPYvi!VbWh$`jigu#GV#QRrA4sr2>%@ zHkIN)RpLoh*~BZ10QUUpPS@_tYBrybN47VdjZPGOIESLpBbsW4SNjR4Nkta)eo zRfi%j zp4?1ER)Iv~S%q&XXqjl$(a~v{g31_S*@c7AEj*n+g7Yq1*(;!IZ9U2s$(KW#gp=8( zq_TkwcWZmIn8Xoo^Ly}(HfOwkGbwIzxBlZ&fr%mm98i7&AU`3kUJoI@+e9$o=)`ui zXCbJ&9z1yP>iKE~*VcwiyODz4D5nouQ52B0O?(3ajGLEVNs0u@T}5z?<-YESsqyC%1tG$*5WI>zz|mKLn2-deb|efp4QQRX+DCT9H4A;YD}2P$&uS z-y!I6P$o_ZF(8(t;*E|2DIrGV^_HHPSRiwl<#J2(;@O7oNatspbnjStj=FaFgdnLR z7=4X}=-c$R?qtz;y8jR67LU4*!XO%>Yt1bnKn0Ym?M{sGHxtnH93hav=^Iz{9?_+- zfbM!3cE4M|Kru?tW%E-VG<=xcOezoo+ zb{TLhX+TdFnoLsgQ7#@_F)Vy{iS`g4rRJq&yfV3L8!n1c|c&B z7Q+x8Ij1DSZeOl1(STX~OP9Fc@%KhpEZbC3Q(8M$YfTN5G|;^1`SCZ+j%iDZMU%s8+PQ3h;{(%8+ZMG1(>!F%nDoHA`SAOxE%Ue+G zP!GYe=Z^+|6;6US)GPt*E4i@gI|@HwFB@$x5fj^o_6!kRl>r_TF~m$GYKA6TA6c1E zDB)Xhe0_bfR{=Kv842m4YZX!^e`8Fm&!_W8cxAJrMxK(!z-9D2_bXkYT|8vU{@5GEV~n0!iu~ z*oz8tjmE#Cf&cjTxNF@0A5dArOVL$lRz%1^@n<6y>rZ<&0 z9x89F;a(fB!YmG=q0QEuIsKcbj{D(}&*Ge*1D6X}HC#z;1B`!Bo1l@Cs{8y&vci?5 zCNq%A3{ob!hWOiTlgzPLbgv8ladpp$0yTf)C0DHwmwr`^>1WDw#Mi#1nYPM+?8r28 zh1(WrBVAzOxzrA*rZf$;S9-^Q#e!8FJ$7t&2L0)n->7lf{ZZ$t7t6#ICtLj)r1UW| zFl}v**`8G0U3K4X+_-^Xo$FjUA)rj5)V=comM6N_nBp|Bys)qkDGjemW(MVRKVyjG z+!PUd5KM=@T?%Bdc}XrQ=IL41&t6UwD$o;`rp;FCQyb($QQyeK@#4h`%v+;b&a2*W zJhrZv%GOse{cFE~78CJ;#H_(W`s~+b%UQM|Q=n3l3z8%!#~Og_-)Rbbdo#SrRo}!U zu}S6u-wqxlghLq3^wdZe?)AnVrKVAjfUCax!Q$+}^xCMf{{~PIE10ugZi;_W zldHn_xKopplj5G9%h^n1lU05P9_Sq9x${)?Z7<1&vJYvZtGVPPTcRBfIdSn6XLtNn}_> zwvepb46E1$f2CbMaJR>rsS;uFcNwJA>{XUqP2!n2P$B%7bps>>m;C-d%m>wwKkkD4 z^V>JLU?StvMWauOq$Vb}sw$^Aw6=_>Y#vT3m~ed%neyMq=WV5=o&R}@D{m;R<4i5R z(lyY$UO*3zqo1)GU&>R-9BY;n7TKm@qmt63Z(+f*ZvFZ!CJyu_{{WHf0ccJ0&tz4> zRnH;k0Zdf)1M>QS*0*k%qQwLq)1x|Zn0sbsqc`>1W*&R2~h|^3R z$tF#*A@%(OgWm*!nhy-35=l*A&PpO>3aK{Sao#BTB+CBSo!v>(^n z;r7>MUZM=sV3Eksh*0xFs~b~2)Sh(j+`)qf3D^%`rOdKR^}w%eSN8$>;X^sOpMYiw z3}lc(gkZA6)V#Q1A~2v(!p^w->&*`>q5K?Qk1hL~Lq$FLImNe-hKLG%V&cM%^Vffa z0TEmz53k8at{O)Yz+%$TrR9I|wh;I=dmrsjojUcN5HbxRJ{8mBsj1D>|4z(*SmN>U zZEmJ#(p^X{%V%XV$3pSIuJQqzk&}af5`|QB?PxaX>px}DH&S9nB!6cWZaD)mCsfK{ zPRTKI%@SO4SD1pN!T9Jys&j_ie?1n5D1_>Ap{CtelYXK(ur4gVA(=>g0I1Uq+z3Mk zDWnE*1qFrs(s4l6`0`)S^t1~zQZ5wozdzwWKS2_jqE4(j+38{Jw(%p|)}T=B=QsMXFxhziL@AgskE}#N}Kx(LRf+8&NyJL%`3Tgz^o) z5tL&u*5a}b?;jM8m;1?nZoTqP`CaRr%O!5(8msHYZBP0Z4i#TNKXK&pTd%IN|6vvn zEU|0KbwdT##?!d%`6pZJq@Kj;|DM!7o!^1Ag}CL}hGQATwy~uE6GWATCH$}8;-`vz z*#>WiJ>yKPiR-%lfny zC6#bLe^IzdiVCx9#$#d6j#(sw(Y$7`iw@)FsG4c)5I*zfRYt+Jy#{czf%V}j%_7$9 z5Io5N%JG}Y72WuaNS9|%d^e;?S+DG{Yn5~6o!j3}8@EN5mCpajfvP>#l4IOpvF4Hy z*YU=Dnk%%L=hc7C8y!$f`P_iYZ%BB%6$&?zXLhaGrrj?)@1o=r9qw+xTbiCVYtF^P z(b&~R3wbg!XYj?ygCqhEk%8oP==|b|pihneNsgjEj!`Av)S3DkKcoHNWQOPw$LE)P zoDI~I^QS5;)?YVD`F3RLqUEpDzMte&b<@uj`kNRc=*h|7H#G&hv+g7XCXxTg>gVBV zu)3cdTCn7`4qHe}S(#qlHD^=3<#xyCqbaB&hsI+>{)%5xo$*o&|9AM_q7IT${#W?? z+IN-`pa5W&6{vRkyN_O>Jf}V}ImzQLzoCpnok!jRPyvX5G>hG;dvB-U!2_!QL{Y0R zRLL-=3A*pAhLYfTkSNf8C!&QVc&yDfFLeH0OC)ow3$+r`;;jdmKGd2>bCJK;ad|u4 zO#KzeqI{Nm1bf`oaz)ulNk?+jAWu(kn5!+^@51= zTW4tD`8z;_!M}|LvMC|==MtO-yC39nV3Q?dNVRx|hOd6cu~bqfsX!JIF02;96l4*) zpzwK$z&`?ID&tK3v+EG+qsQ=OrAH&1Jqncp|KPm;`|MMBM-A~fk8mF2Ak-U;pIf;S{vZLoD`IW~ zUmk4f_i*~Or=_LEu41j(bD;i}&Z7?#N)mMGYbJ0=rY|-`tOAOxSeM&9J->z?THbdZ zKQ)faV*KMvX_ni!Zx7C*XNDZePM_@#J`a|8voTVC zRiyqoB`TN)Am04}gflwA9ElsmKd_)20gTmPnb$oH7?$L8ctvdM*T1=!^tUE4>Idky zZg*Fr?{{=?1b<`#xHH~$a34Ey1C|{9Xlw_t;Dvaj{_2F;=}zNw=XPu>8Lk}%g3gox zmZmMycZKC(&jN|&Us^m3z1Moei~p6588xCnxpwGIm^Jhi3UHb{-1w~24k$UO3xL*h z*hjF`=tt*w7rv|}1VLNz(Az))quI4x-Bqzzdcb>ps%&+@)r1m65V~7=`7>xU`!wjgQhGPGJ1g{9 zR|rD`H*qe{KaHMoDr^*^S@UI2kiRL`4KK+gXCv}JWC)i8?>*wZp#PsVPI3WO7M1-j zm&P*+F=-Bw{QWAZlVCXpBN@6cv~^Fw&xJ5Aw1yu$+4)r$%<}*DX0=!lg;#=Di?x)) zIG^Hr#jVDx{|!*stoiuYuctHTwEzV+af7k27~e|Z@}G9bSrzeY?Ce*-k-ZEw7`}C; zboobXaF_fx?MIw zq(0{5MM+@%7oz$(iEZ!z_9(kMqKr-TZNvBm33_e^bMp#F0ry$8F82EGD3U%C`=9t+ z)_8J`fAn%hvTB{Y{qFAvA?{nHM<0Z|fMm`Xc47}8Lr;M=f9$h!@A1}8x&0^lU3K-* zhcftWrRVOqFz`w-ZZx=HeFomcyrTv3CRRSe3#`8L&bTBYBKj9wFzIMW<5%l==5sy`~BZjjP{sujz z1OCF#Aq(8Mv_H1c90p`r1`Bgb_>teT`w-j>D~&8;NHxzeC_gx=^|wrZvyKojfLT9@ zIhbrBU^5qLH|dGjM=I*#M{_S-B7|N}8#d=q^jpub-ixVJ+DE$$dB3jhU-3Hs;K75& zXaT0ea-#8rK^EDCr(cIff#DQxd$&mgPkjL-vJI{H zL6El}z$$CV_7LC1&)@dA^^Z*~y!7oLcYjIlXS{XxPwP*1OS?557d`Lc$h9+vx$0UmBrs<#Svl6_`a+$V+@d{E0TOWv=<|FFBl^?*sX37LuwO zz6VU|DTutF^=bo+mSCp>&%BykcM!C!w^CF2gC%;>&a?`93T##hR_nrG#hv^oo#VqG_(aHl9Iw@X6rIwBPJOq}9#egGRYCZ{co<6q+uPN(&bH{H9^Xe}QEi?(7VJRLLsPnQy`ujX7>RZCrRD3L2=0yLOkMWS zr|wyL3#S>PTKvdeGa$vcL!{ZsWfEn8H29^L(6{5Ipu6DeM|GtkaywrJgPq9onSQo! zdcV9pu!HCOX4>|ddPiTn1TDn&rKRez=Oyu4qgzKm78#MeK9Q2k-&^i2P($7koZ ztAu|6Q7{;kjnMw`Ibn^Q(KXP9B^T%D1_ksWgpAub-G|?|xQ*ooBIAV;NaabSYnHmy z=N;%>7i-^G&-+9gTjO8w&g)!?G7?T~1#)($SRjoB+Kz1nal)EFg};TZ(F&x*Dq|ly zM4zxmwV_ii@8CNZ$She>;~YQb8mGpdI~04aa*L>Rf0nJg75SseY|*TEwu=gtA;Jrl zh?&_D&I-PBuT(yoFQ_5{v8;f%qIsMq@IgCu@a#r*pRHGA+42x9&<>Jt;9%W(o?!#>#j@w=}oc_)_h^JeDHrh3K2M=K1 z>kJyF4O=h>slf{nK@N8N=;f==Z zCpJHjh8OVIJpNNcI~I}x0WyXE=KrbMghk{><74t%*WTA93#g{**9YE){UQ&R<|(FV zl)rH-U`SWn{2WJq8)1X<`=MQM0Udl@IU1ZkV3g$xS-9kz}mveGSoDht_~1@ zv5Sgb>=^03tEoOW=29uk6$7i0DE=Bwqz+-#?r0Uv<&Tem#G;@bL33VnkZmq zG6PSE1?vtylhz zIFf`0=^lKd(+pGLkRrQ;KrWp#+63aU-W1W`@Q-5grTRx@l#KI_%7TJwrp}tKK zQ`Rr~kGjaH8;2ip%xIXI)fv_Q{n;{8tK7P|!6X1MkIC4h><+yd{57KG9I?}cPJkhp zY#KkEr?}l@A!5edHJeKzwXSPzZPj{V*KyOV0>dR*&d{2^P)>?OWuI@a^3X)rGL${_ zNt(h!#}|mYh{x}oD@655=4{%?naYteS8m7HC?`Ny_Z|pJ`?)3+9itHC<;C*y2QT(G z>I7=7yqBin)AA6D?-7>lDJ(=%Ya-*a83`K=gm7oCszi4(VYmGK%j+@vwizo@A5WW-cNqU}7Sf_-B{SI6F)s$ahtu zKAjpnJoTeeA9pw$+HcI3!s*kbJ+g)N{OkId-}fJqfja=rtVB8}XUNphx+;sDg zc3}OuWUEt0&V^rv{M2L#-BPFE|2WvjHM<+NsH5vlUqLHp>*R-mQvkfC9OANu!9LFm z`f5V)fuEJ@4B4x5SHka`;YeTL81KOE=c6V<8pZ<(LaWXnL*+%J3w5K}`h`2NklIN4 zf)n!q4iJ6!kp{c=2;B-CyftBY`IV$hVPaY-J#Hk41D~8U6`Bc?^+%yS&y1Wq7OYhU zOybiP8-WhXiOGH}QF13-Zb41@=!<&xlaW%lSuRhQgSl1-dAGYQX!q35hixuMP;-ri zou4fIe%02^m}K%(E)i4juqNA}T_U=@GluS~T2Tbn6;kCGXt?{_Z$%YGc&YM??|28S zsZh2kuxD3hlhgFp9b9h?2x&;stbVK(c$$4#R?X3eqq{tZb`1vXDu$?j8w3YP_eZ;3 z(IT^+sALoZ9s4{Ti15Q1nm(tAY5sG~)&RhnBOC4jW5A!2=$#|R=D2r<4Lc8F?c{)V+(N~}G-;rhObx$~G zyFs=Pl!~R_^nlc|RDEDav=!1LNDkim2$Pzb=*b45d*IpYNtz>2w>;{}$o#&ybwU+1 zfq2O%!9V)lI`_tmwg5SzmcOj1xwcNDaqh>S^69tz)2bvpfmi}<#4m8?Gs&$l6Q+Og6Ua!+-^`|{JLOS#O3Zh%bPI~x zg^sv_gvYNawCz)jf}^VSk|&3H>UkdsiwB6kMfDpO-`LW^agf77>r8XLkPYS^5fPP{ zq%A7(FHj%NeK@+wz=lyl7PEa*#~}ZLH1%rPcwpJ9x3egBWkZ<)_M-z=I@PI6?$M8%@)pZ5e)MWRBmi4*Hu9h`u z8Y=uN+@}(h=WEV1@NQHJqdgUWm*uq>+o)EaUQ73bI@P^GBwc(#T}0^ji|_Mo;iQL?R=zkNKNLHjSvHyZGj^rh*F}Rc2p@;aX%#8$@N!K$iM*(p6ED=MxQ&B}iEK*h;zH{>7*g_H?cOV}ifgl94GuPK zzN3+DQPMi`)+t9#xy?QrZQ!QOz(KYHWq_TRt55&e>=S37&>rh*C#q%m>h0v^4MwLE zdE=+hV*Jm`wk34l@}Eiwvu90l;`Jo4%d$B(!Z)yW_|fCXd%xf_$i9)zI+bPvMQ`0G z2ib6troR+47`#H_#$n---0pE$|FXlA;#^%Ri5^Xk2-ktziZ+w*LCWCg!Hktl_+zid z4OQEEh&GpY-3rX9IV}Gidige@xPz;?WHUC%R9TbbgQIWq3-Emj|C8iZ%z7F2}CcA;wPkmd#iZ0hArgKFqY$J;yJ4j{7xI*Ra=wBKjOY)%>dG6<2jh zk4a}q_bAolbJQ)#NyAOqV93$YTyu5cXlAo96HtNgMP*q$9#b|EbEfs=MGh8%LQ)gK zx_3Fr2w(VF+pgMWxEpQc0BIO{3(p zpso}CKGizwF-^4bfI4^g<<=32v{WZB*ef5mpKK@TJYxLJlGfuTPt6g@egV0IcvRst z(xgGO&6RZ*PbS|#>W@4xg> zox{FCTlWQIYvCOG+OKPV4_IeI1dzLX?>_uaRItUkw_u`4X3|Vab3>DE$iuf1f;cuh zrM_9k+t(`D;rmhN&YJaqX^Ro~IU7=TnCY5~n&7#mV+%HU%Pz3+Rb_nOEK8eQmp;xR zpz6NNJkHQz=J}HW!J!=t>pVCXX`L0g%Pea`&-?vsvI8%x(rp%|W*OS_+WK>=Kecl8 z?rG&yIV@~ZSJgY=JT9_lkCLjYX7rEZA(tZ<6amYkqT$-Z4Yv=jB!jzPf+rv#5ccBK zdo-7mF7lxwSR0iQyCn$N4u{zk4;~=CFL1cXCB_GE9Ef?sz90S<8qR;0X(xhm{^&=#k{GUkCWAl+Ob23-K>2 zot?QLx_dROe^no>-RpQ4Gq0{EBxEDiK8|p!2A7;S&15(u20sdgyu4lNK6T^q-%bvw zg9S;8nb?MU-lT2%b}yJ=>}p+;1K*ZjXgM3oy%#mWy@wb_++EI)hkPiprV8E@^<|!( z>023pV<2cR;BGSOjaVPRf=@9FE;;F_b}e8H7M2XpQXHk{i47gY(xs$loq5fgs4-Ev zlbmpDGKt1iDOl^=#$c=C2;>ZU{P0zR)j%DNt7JU)Lt$jj5qgTcBXkYa@dQWEabfZC z{z;9d{%0_(K9hp-*XEVH&N$b9nhME*vMG)Y>x%L(r#%-vsRnZ_+htMnr^Q5aB zdv#d#&w5J(Kuh#e!G1>3`S({PA`&!-E5=BX$uZFN}6M z-rl=+{fePsv?QMjFjz(m#;^#U8UXV)z)jS`SgU=+H6lFxc5G~Hq62!qF?_-&{sK9E zk;a@;(oj;mjF-A*-MV#RLKQWz2xx)$xCq(BGlNmgrLn}SJ|_{^zKsh5>d*v#`hy^> zLRH`)MH-~BaC|@fK{9!l461}10@e07;&BN)PAt)8esW%|N1;?Rk$W@B$ka_Ex*v;y1K z``#@3LGQrQAkeba_Up*iB_c_X&RxeG4(x|6ybj_Nsh7WOc9kT&1Br_ailBQ=t?s(S znFCGf#C;wXoQm)$)P^suWpUj6lNVFK!Ay}k8hTfOA(n2x&?-4N1|1@RXO_(d%+!Lf zO#Q3S4IA=Lgu;HcUm$xOmK%V%JE{e9*a4bXQ*JdaHe4vU7C+|&uX^C=v_nFx>Wt<; zfpT_dwKURSie<_@t5CVrCyah`r8>SqW;59Yi6440Shfrl&DYuZ58P|W17x(rWoami z^UNUtUIAXhr^%09zKHx+wN8B4568#VuE`G@cn802ApeQ{k{P0QAJ%71rYY>O3FQ8( z8peO9J3!hJ<+Zh~Lf0?`q^GfLIm;e|%6snn@ZMxhO-&!ptP&wVza~*Whh>Yslx1j5 zJ(*l2frX24KDSG@%zt_PQtIVD$*>U$lS_GWNsmuVlmshce$~|H2QCnu*;Dq;RB%`J(T#_K>JejGpi8q_T;(un~Wu~Wc)=*Ur% zPB;QFi0r#gcv0_(Q-wj^yvT+^QK6$=JD*yhU&=PDhOqh^lf!6QEU0|@_QuP$(8k_~ zmu=fqIcOQ;e16zVm=rX(+e@^c-5oVAucep|Q$K&xWqiI##ZYyWk$zq(z=36 zpRj2ftzWTN`!6Je%M2lztvO4Yf}AGC)8Qxm!0&T~KJj%n1$)m>D*DH&+6G^>4PMWb z0|QB8H2?6f60H@b=4ZXGP#Du@Mp?Fc-|{UY+aeFcrTe#QNr!w?h8B;BiOD>>fUixX zcKBBtoM_;sr8C4Qy2BG07Tz~n`?GbJHBiJBZV^#U4eu2E`yq)>sBN)~yc&6m-gQR! z4zc=VhAm=UCNzdCxTM$n&vA12YMFL&(-bYKOmqMa@mmRwt_K?ZFSmtGy68#n-q zocgz2d?x!>#efZvO}%D$MLw(0Ac~JSzBw;ihX>Rgj?gOHV^Sam;?`}t*57F<6hP(9P)BQ$jjBk>s1sL6X#n5C~B$H zPpc0{t+v)XQpPM(VaKK_MnBnP8dYzXkp|rn1fA$eho2v}cNO!9)kH)@{L^kkk%=S1 zObR2dHjvD!DpA3Zw>p8R{Z8VIoFFRZn%qeE?e-$lXlKYV#4T*Y%6!;__0&5t|HvpH z|A_K*xeU48s&srOyOeA0nVrXL>Tmu0d8WO+{dND?;;eO()8anDj*sK!WtJ3~Eb6*3 z_sY-+JWaDiAQLe~4Ubx0!-yGTM-4~Ed`ZrbVuNf+&LjThP4A4k`hR`%SAh%#hUHIb zKJfbAVp-xKBtp|RG%>d^v~LUWrIh2+sJ}9(-SjdWR!hX)$> zQ>~q}734j${%7+uQ=f8;U%j?aEuQ6)QnB+`XR=Sydj7LfG?>F$`y&wvUbfAvCa{#| zK2YUovSp~3;$rM@hAp)Y)*_oS8`vXW z&WF%TE2vjqt>s`D3hNW5ygvCMBP||(h($Kjtd^jy=(ex4DX7vL_e+}B0^o1HofY}Z zAtEtaLj4KX-f9Ha!+3eKHFIVs;-RoEUbGL~%xyhRHy1&pWG-}+(Jk91m zceX{>A2Eo&{O>!FS&eQ1{Mn2oOy;(7w~6nH5;5z)RRW4eL0hq@sR`>cytRL&-o9Lh zErNo9^I9WH4GncHhD@9UHuQ@1yA$Ec)pILwn})u=e(tVxgP*NshOlL>Mb0*YIf(*0 zckcWYQ_tt8>b>1Z*dV*0Rv;Pt)HzKfs-BWN4AK5p32D5MfvlTc6_XROO~&kX(9`#b zO-N!Du^a~G)kX9ppGF%lBL7ed`#bX4vfOLI`!C6x_(gKR4^6xUmnlIzui!%@o~CZo zL>+Raq+^I&HAxMTz-!@Zo{l)dACTk*C|O2|;@%IV3rqgO>S)RTJXja%EBDfSU0GQR zhD^uC1rxb38z3=W>Ouyl5@M!X9ay%cprB=WFu@jRW*5S|hEP628lsrcK-Sj)tNdeI zZ>!G|2rotnZm=Lk4YZ`@!J;}vi zUE^ur_87H_1AcBM8pB75BSt#mV?umQavnacHi5@aSTej)5*=W9vj`km=9hv8h4jmw zjJrv@NXA=g^N{1Q&k_IJvwlTN`QOizSv2?H^TIIiAl?HQCz_R(~P^!}&gg*cmc zaE&IzMe@!Z%Zn`9xN)PvmM!VOCnK7Wpb zQ0d%;Bt``v{s9o(O4tj2DaMd^V^`p2xfq_VRLkM?`6Qj;p~Ht!m2M>y5;`U^8Bs6i z^kv8qvQX+8qTHk}>IWNRiHbb91?{#`u&)X%xmpaKMT z?b3zpE1qr{TOx`P4dNq-Y6D2?Dsp0n5z4^|R^w(ZAqnoIH&IEfSrgw>MP z>6T449J5`djp4?`D6*{8@U}qm-Md>;%5mf5m(2CKn3F{lAT|TZ*yE=oe+MAMVeSEj zP1K-Le0DD~CML6Wx?`6s6cjLS6-1S3h?Zy=<|XiT7xmt&1HNW^Zx&qtlVv4Acw1%Y z=ZlDo%YriCC>{f9jv`nKR*$s04OOGUgn>XB#0&?Kv4oK+1UH|sW;a?%m%^xsZ}T|p z!ZJt{3B!8Ypi~5Fp6mEgD9bm4U5@qAj8GE7=s?r17ifJ%!rIe{In@~D4BLEd^x^W2 zYaF!H^T&t~0~>~AJbxRJDQSjtZ(H!2+=2keipY?YNwkutp!mF5bp-BNuq8`$Kpvcq z<(83{D1+|I8cct%M-ks!Q1&OQ@GaU^_qKpr>X;xS5W(IA@^vGhXX}IctvdSjoz{8T^QAlQp$wnL~EG+D>NUd9&TS8_-ti7@%R@E3N zVIBPE1vYQ4fiJ#blke;x7>TH)NLXX<$9}lRH_}~q5OWH&&z$**mzu|lgi%7%=$}4d zuSo@Jn9uu-ZABLsg5U`+XfeC*&(AUM55VKQe*6PA6PY4HW=SFf5MI|FTc}DL&Vq?1 za0A;t)M-J@G zqEk6mTy&X4*)WN(Gmp1LYv9M17F+jWzS_sCQMS+A{Xa*<%-{9N7NLNLgW^1foG~|qtVVY{^qid`v19}_ zZcG)i&?WO!2{>C*_Nej#M%y3U+MCiNz&xM*{rwf|JF*qX80jipG zzz_i~_Z~fZlz6rZyX+QRiK99(bBB4j~Orlpx6u&`z-4> zlfwRF{~`xrdxjt;w?WsEhI?`-?U4pycDuUE*12s)si~)?hB8@fPteC+)D?UF?R#S4 zrlplkEYb$PJtJogsprUWA3UB01=bVEn0lawm9|Z{wQbOO7?Tocg@&g7z-;Vn;nyk< z>qhZkNF_frX$A0awidt-xiR=~JM@2%>XHCGdrxcUNfV$Ah}7A`57sgtz-A;M6>%*l zm=#*QWqXm)`j>dX74F>m^HnNzH>KT+@F#J=2RM<^)6x{f?BPn-4O502$RtfoQxMA0 znQ{kFyK%R&-z$dL&qxq5PWb=7>%6?@shxNXY0S5K$ovNQiyn!{9s`qS3Ghzim_rSY z(-HjN=t#`I(gDDtfu%`MG!R3FVJMgfjF87)S=|N2rMOAun&oSEB-c)@2XunSDx?&R z5f{Ya4!ju286?~%bMd0JwY2zPFH0uAz+1D!0sGA3D%*BBpzk;MT5!}5tcUn@T7M}% zhM7jYe8mIcMSCa=u+jPRO&G!w5fdY*WGd46zd((=5(qMnPV9c$dL~dFO9B-Pwi_h9_T+xO2_yGyJ z&xgx_fts)fwg()U4*WJOdC&QdG=x}JaPMRg6a;|#$y^mJmf*Fh0m-Nz60koTKgM)- z09XP_3>gPuCQ1gqudOWvL2BRP&}e}hAdiw@+eq+wKpEEn(B)in|8htO|9GtzZGaIv zDNqIGWn4p+{vSxBfl(8+F?-+DODRZ!>EezkDXCjpTGr zS-%}HrP;c4hU(?l)|Tnex@XUxXl&qO1KW>PaGL}&X%C(*!=&nWVSiZIs)*~?afef8wZ(*c~5;h7V!BRV&;kP8HnU;nxWt7$E#2R z>mn&p>+8Fl1$$JXqxZ`t%kVgmSAUpt6gzO>QTrKfMY@=37BOliM$N-NOy#3@B=MYg zg79PgZ8(N@WHjS1yi(pdFE7G3w;(s@=#Z zK=Ast5Bjbo!w*x}r3FcG%eg8cha#y<@t?GK{tcvY(-3$H;n57Eu2x*!kKfxO1=AQ_ z_c=x`El=A@6CNMGt)Q7h%m4X&_h6#St2b|gMmLEmQg;%C`-)uVwN3&I32*?e~$#axG4u~Agyfy|(4lc81JVERvD*iNcP`(s%;qT_O;p+e@5 zU7C<{%P&(-qIpeJ&A(s`^Nhb2d7a5;Ni5}74tLP@ zc_76=p|S1 z&!5sKGYNRc_Js9ui|XI@5kQPrsnubP{4z`@S$3bTPDWtW(aXsU1fQ$hO*0egCT)lv zduHdle_%;=KtOmbGOM>EtGSb$tcVew8){au+b?0hM?ha?bLWN2HIp;0{j>u?Nu80LuP{&oFug|KGOo=7M(>Vgl2C#3y`kiS z6N=3FCSeNu*1wlv>Zge};rn#Cw`^3;2VMvVH*eUmACsu?qZWGeuqC|X4|#e1!~b~C zxO$3Lz??HyU14r z*QhL>^kXDtRzey^i~)Md0a-Z$ zdA1d-P_$)xiZffC!KNeeTY+~9 zX{=^O-Ei$1H);`8Kj28lG_gUQbaOA8-A8f#So-1Ol?P5_X101ibmuu_k}x)~ez6+l zxPGr*y;6fLEO*y_hViduDM5?q-+!i?xdy0ROa(g{?L#L4CSombPv*s~t^kt=SmgKA zAG0hu{PVZ7B!0JNTmyEy?=ZPqhsxcL`oTGLN2HZ};uMs75&i7EJ@i{07Hw7Hyo`&u zpW;)y5MAzYy=_eWH1iiKX99pJHdx)q0IqZSS-@Ek(=}OHmI_D-Y=z<(E#egnq|och=#wf5WYe6DW7r za+wVW2R0I!i9Ew2@AT?-x3>6svQPcsl9pUVNt{>`S9@x`$S#9Ot&Q}W$MC^dn6kxh zZPI7ffVLMPwbGFzkqwr27}A*#yMC<8kr9oAh4i41K1F7cPQ(4c!KVDd0-;*Z#-1JA z29en>u8w^St(dy_D&yCKn;D!dGk*2ybdGHrcH%u-Y5S=2B9q^-`$pb4+yK3$J%~c- zR%>o6FE;YCNwlkYFvJq4XqL^cT48qQ2VNZlpPq1SnxRkzxG)V!*83~5G9T~P|Jv1^ z@qw3?VOgnKVEtJ?)rtQEmyaXXWRoxVv#XIQ9-~q7E)N}E59pf&@s8Fb$bE@W??SlO zroJ=YtZlX|-&C|ViHe4I9$d5brIFy|cb7wl7|Nc>Y}_F#>VU)Put~yux_FznWoT{@ zpf43$9IDFO*swU+Ayl&CnZ6jy`@568!;2{NYhHgnoEVLZy2X4!~kR;JxtsOgz8CDc^T>A3$<>%+<~RyvM`5hY`7QtP9mGm2X!nlBV(l$vG!>_6#H z7HVa#nvk%-Z2tgl8khExVvL_0kY+SLEwJ>-K=f*QIMO+5aflm-dVJs2X~@UKcV*oA z`@UPpMjE25N^fyYZWkN#WL=Ob(38n>nOorx!{=7%gzQRfMUXA#3_;j=)uu2czgoM& zB3fXtIpbyZfrt~S+YGqk`bv(f7_c_}a9`aY*rTgr_^|OuiQI``pOE|->*Z30@4YXf zqd+8>lcHuTS9Xc%Qu)%FM{Bb;q9OK}%V`nSA=lM1+9HE@)*f+Nz@Agob-;S-NnUA@ zgC@Mpl}ogm6V()WOS0U&7Rc+KP;uK6qu9XfujG;`CaB^5=&Q+N!vo}&C63eb$id^ z%j{M1w~9W#?U=DW-bfbx_CcA4e%9WNY=Jx_90 z*R1qT2*`S%%x4+QbL$h$CHCLmndKHD3`?GB<*~eW4yL6Oh@#W<{1*w)h;u6_A-&SW z^w_au%HDedYZle5zedNn1(50?6_xhpNBH!^hYv4(99y%rrZ_nz1r~F(wBImyLne#c z>psZ_yeuv5C2^%pCrXPaE6E?QmNiz>%~L#Z_7b;pONP=sALnN@voeX5GLm%5w(ZKm zQc5D7oZ&Ne`VvaDCj9OZD&BaqezqyFDQstXDom-QG8k&K)#3viQl`Z&ke|BxwH{yF zY&~y70=mqR=_N6A@5A?}9r45I6RM`(QV)>HPS z59%Wpm`}^CR80GsNOK!=Zp^}O+|aREi$_7?BYu9O+}!CICBR@Q)~>Vz=a2M1=g(ib zqPY)cz`5P)9e#@r;y9Z61N35q^FAg+FLk|l?mk7veW?`plg+La8EwCq(Wk8|DBj35 zB2Z9hxm>?_^L1n}Wj+~2XT?>>vhdaepM6UU7f62dMw!&4IFJDoZy2CSJhpw)dD;L& zOU*WViut5K^yorL5{&z+w5@iG&;qe0=bubFNHncuj43&Kd>hX4_=x1O0PccwB#<4> zkb|5dsrrOd%WzQJ2+#;n-L>Yv510!e2Eb|0`e1s=%1RScQ#yCbt6Wyf`y9+*#Mw|M z`L4ij0VQHd-00KZqxko-V?z?Fy}YSuA4N-DAx|+$Hi{eybcR7S3Xi5_N7%F#lQfM$ z0z@E@ECa~74ket^+mtQ3 z;L_Kn(P4mFtWY3Ru};+b2QQq*fNkk7JZ_*wMXJVj;S^qb{>I))|$sQH&>ivT8w zXJB9^GYd<`{rf}(fG3VT63YT4c<}f;k>Qvepa@JQ?v%94HMVU#0yrs*0{YcVl-T9? zSU=uzAH6-mVIWi*M$c+5GJngKqP$quRHRyWF%%)&pr9R)dmX@iGOiI#DF;z(YL>J( z?fRV=ew~tQ7Muw*4z9^rwptGCapi z)@G6z@o&6I!SSjAIZ9-;sb7Fw?k7a#0 zS3stw-@3(1*zo?bm~WBzvr4?=u@x6L@P@o_mS)>+L`meKm*QSPkx8s6Td8~jNujvH zz#S$sldhGF+cD_dfj)Aw9B(&voi?>7y85j z1<6BC`2Gu=sJ%@2MG{xB`H^-Ul&dI(u;0PJt(|K5cJ}&GF8l?-=n=rkSPbASYyFT( zk=+TD(2~Prfmguh0WUN$c*~`-{Pv)gu|92T`n#XL2KcRoA9da%B=M$B)LS?O(5Gn_r;@*MPu0fp_y`wi!mMcBV*f)bT_j$b>CGWY_A%p^K1&pMx zM?V60L30)~`Ak(oTr{1WP3O`40k?iQsDi6AQJVj+8YKWeuVGW4IxO6d6^Y z8xM57qAybnd)cOb@?_GqM_E{Sc;=t;MqvxR0??y8Xv>Tn=G`{n(19WYGjc1y_M=`$UIwA?7#>fyD&)KO~oW3boX$n6*kUD^jlUAxF)&UQi zvxJN@0xK)RbpcXs2ulXht*W4)K!VSw0{A~tq?ULR<5^WZdvEB7ihu6?#~QllI& z;fVt4p6K2JD-^(A0-~aI`mLQqTTpt3S+2oqt9aVyIJApSg=K+oVh@%ad;fk)qC{E) zjS=^FEluv3i3BcVDDTBFIb8~}Wj&1gA`_bd2e+U}pGuZO0C{k_w9oOvbK8e0n67Fa zzf*22sNh;C0zr*g8<+sB(d&&tLGS?s!m=G$q zC4`ym(dUr?MO<=3R181H_Jus6rf+J{Ie*ONPfg8X&=^p^XtCsgiY2sUHY7WH;@(Pp znY==_)}8&*5^ZB#{CKJb_Jj<=n}mXwHf@#rx;3ND6iP!ayT$9*^Qw_YZ$$@4`WV{aPfdo$J@9} z(3^y&o=cpS?XepoVKSx$e{)mQbs2$*!5%;46(uk!`*y8E z0nly?5F@(guw*jc8e|bxNhBsnJq6jM{9N)i(>vf5oAHeQ40a_ZLq=oUBAi8MzcG_gF;R%Fc(kI zEgxg_QztWu5xCE1IjOehlcYRKRpj-Dx1RI~^$CzU%#44?a(eoJ477-fC zw8nG-9vaEIhVI($q^Is~d;D`p2|N{w@W1LRkQ7-~_X;<4cpIHq;_0ER_&>@e1P%tuDq7xm>g z``jCXwYw%#ydp$UG3!raM3+h=7JFPe5KPF7^uigl1osru1K+iiD7>LACWH(W!fICw zxB#xDXWnH|T2Obw5@I;NQ}T=zYvvMoau&dzoEz^EQanM_%{rNR2IO1trpeK;{RAWB zNo2}bq$L`(Pgo=T4aqiwYN5TOqX%O2<QZwUi5Y4>D2!UJE({9kr z94CYgL<~gQ6P2|38JTTu-Mn+i4Uqu^iu50}xQX#QoCeR0M|6_^Hc0D(pm&qtElhX5 z2|aDL>1VzmvR*tSGc4kjZuM$!^u|9^}F}aI6z;4UI5hsAk&|_B!1I7;hP0 zfPr=(sPJgp#_!|Wc1kRNr ze5rLVAO5`Nqoph-ZT~l@q6;-MBb5;4RPqiZv&hVNqS`=?bO+`<%3)+? zGSMZ#bEuIV#Mod*uqtI`L!r#;iNEkm{oJ`6Yzq_k#GrKqEW<;MR7fsR1Ws=Xebmb^7SQ)GjrLvHb{t)x9g$?%?an4_?3L7T)2ZFbt4nw7>b_4@x7a z7Kg|}NpuE4ECan{1IcO`lJHg0Ns-XbSYca|orrb-G0cL7WER9p93P}uKoVq+sghucw{~sE-*;g% zi1!APk?eSAM+KHr)-Ex31j6#{bmPjUk{yauF4R)@l&Dh3pTofas!5a%Jf^-qTwrxM+2}F~; zKKL`31aRQBjKDHu3l1PW!5z=|kr^&8iUWgA9Xt;QCPGi6O;t}IX7>=p7+aufLdRJs zd2#3==qjE16;38$Dj@sVxt|*}t*pUL}Ex&jR_Jtb^>um0TZ4`_8Wi zf=1s}zUIgr;I4?erg^-fX(bUrxs=p=ts=st`ymHSlGv17p%|z(A;I%rQI7zXgdYY+ z-UYL#biQuPn2oG_%7-3oLqch%Z~gHb&4n3hX|MEINLP=fJ1Qz9qdMb{u3oD~JkZk6 zI7N4x4B>>lhlp`7DpTy4n7~pFDfs-8#Ri7*9w`1T$TGlCil#osh&e0B1;dh&P)H5E z5ryQ1ObWbBG$veM4bdS(nA>>g?@QdF4kYCUkzEkI8=lPdy6(GYn^DZEIpkprp5VO4 zlD_?jF9B#K+&Wkp!Ghf}Jdk#&!BQL9*qxj)MS%Dxp9vqJS2CIU&_5=Kl0_#oBJ?eV zop~XdyK^ZSLjEtTi;#G(83w10P9`XkP+A%mF4+<`j5*JU2Mv;~C^eL7F<+zF1oXLV z(ki7xsJ)O-SGB}5S<>H4-h+-GW*qzIbNxpu5kV`tkUyaq;j6bsCZHPOQ!4o4YE@IZGhbXJXw@tFhiPYK*~H~B)$%r( z-Ag)z$-$+?a%#I9#N$24{%Z0K(S6PQ#_h~)DV9m*?2;OIOj#583<-kayjsSO<)sDOG??oS1m}~ z1D@lI)-2(fu$QDsegeowQj9wi-AIFrO8Q&UrW(GIyx&#ApKf(Q|bl61(o6+tvc zQ-PGySujBAl32WwQ|!n(&BFqd_xIp?@y6S?CH$AhM|;v)PTOH0jSgGimy+Wpt|PTL znXCGIvCNTWe~LY~`lysW)R{f#trmH=l1o}23++>>`(reonhsGz5lZ2@T#LG=s!n^F zN10h!W1f(~PDJiTK#h-ItH`-3I(`m==eH!D6R3yQ)Ys=Qs4=Q6=KL{S&~Rkg^owO% z)@oV@`3fYFoC2L$L`y+3d2BzD$&f?|n&JWvq`h=1%RouX{E*LJQR1mHS|id^%)`Yd zv~}xsu$Ft{?%ab43LIc~IU%swg?c0w$RGMz#!rbB4yNC=0H%iF(7)ZoTgA0sm_)B` zmT>8~9NOtE)XvHwa|$D3R8hWD%H7V$en^Z-uk?+~{%S!=g4EW>t!H_!ZZ{~F$SC514~S`i1`)Cl31YwJ>|?}V z(qmbTF|5SbY@^a790^Gy9O?b)5QE41E&h0C-n6h+^s8t&l@-x!2(5JruE65?C8i>5 zSn<=Z7?Cb2k(3>!ej-Xwyt^Y%)1|wVAl$Y}mY~Ewfe|-gg&Qz+Wn%=b#xiK*f+0pl z*z=YCfy5*i8BQu%;Es_|9S#uCWFQ?RS~H@W0p$}FVup2EghuJ)YXh~A9IspR^g(l< z#xY74WK11vVhB8ey1x$C3OeU9*V#Ohg<3ie9r2!|3yvUQ$aOOCF}*O?$>=yj5QGNi zbOPF6O=5XX-^rGJIq=FApNx=o*1K3K-PH$8^2ezXIC$3MJs?T7#JeWNoy*M@n?}@csd(czWv^gF&1RhIB)X7= z2mRJfZ`KIyKc7J={>>24khc@b4N+k{3WMhM>C>l)6#s=!IY>l+W!NwZ+8FWuaI7GZ zMCLeHEA5t*kem=fP6~zyBXuE@K|e3{#Do_gfjIK)F(Mkr*?|*9_UaxUrJU$6KgSiY zZiI+Xp~=lAN;9H!nndw8f{a2b%)os_n@j?4&rgL3ovfzTLSJDbJtj(S%)}-Qt=E&! zolFD!Y=x{#c4{0)cpX+IpAwwnW>0*RJ`NDW<(iDiVkN$AbS>B5mHK=@?sI!$dIFkd z;*_CJRvV`Fier;qWfwn0AVRto>(h`@pMbw#5gw=5$)_~!5OBg8NfT_z9$8{^GID!Q zJud__4+FGJ(8(h>E+;iN9HL!4bBP#4zU(CV>VZR9nmxzkmU{^^!>Q;8LpO^Ezlk3a zI1vbfyd?lTt_W&GI4FSUL#EYZEUwwT3&6e3PhLU6ilCH>l}~bjM;u71YViuLgK0&E z995MHg<^fZ7MV03mTUB6A(8fBI&COq{s)P=4-#-93&W70G-%E?<6vEONf|Ak!e!Gr zNXC(KZ3fIv;1@D}Y(s?q@p}-EC0ZBGOUr68aOq7u3IO!MFO5#o(8jA4Sn7ykMh84L zhJQzyLadD1`b+T_QvMKoHPT+SQ3)AhJ)jk*5*!;OCpP#sino)3!tn?yRFP+gh_Z_M zma+Ru#kp30`*7F${TPILL=0OY5uHgYXptsU0LasVMzX2+CnnYS6PJ#}5q@;dk_<+6 zvl8hDB?5P#=(HycO;#IwAf2)VrqV8*=n3N!vbrAL+ft7-TnrIXG#2Z`N_5!}4z8%O zr4{x`HCqk>MLB6pHtI+!-Yr1&L?bsb8oD>geDKSwgEu7?x~)&^m{jng%On!Q!tmhh z)2xqZla?5yzK;-D>mQmOA!jFPs)NL~9(68>SU~XyYHxap+vwkQD+D;;g$Qm(`F$Cubo4qKr2_Yl$9)l$oQu)DIFa^Uo#4b22W zLOLa6d(i+vJsA049sRE+-c0+1Z(2_Kv|y@u5G8J90s7uDaI75KzY9>0jDTAZx7SU%% zJDf;D6pnWvJx0)oydv9qorC*pVzuE~Ls9YFzI;<|M_R`1cUSKp+@G$1>~X}SwW2?@ zs-0wcy(6XI`Egg(fUMXTs#FtVak!`*D=WBXlyX(!>jh;GTS`4$w)p$cG}4`A&>M^P z*L+TxRR&;=2|d~;@2IPw(@7R?7qgk<5GDPlq%R0a%z1`aL}^E-jreT~L+UFJ{r5n^ zy>`??;2h@R+{mm@0+l|%N*WlktfRLZ2LSfc`_`6mujkjr%3++RdcC?EYcv{O?mqKT z1f*UMk}-9}o$4h5%;`UWgH`CkbhEp)e{>YOjDc_ZBJU(?jnF34poT$zuPpO2@I;|K z4#DAk;04fjnGH49Eknu63=K^J6-4Sn%WvxdDgoGiI3vPB79XPvjiC{#bpZQw^;M^x z$Eh0(<=s(414}I~X$Raj>~bPdUu2luGT=LSlkZuE2B`)0h|r@S2VDr;lnBTV;!9sR zJNxQOG-UM{%E`$^@Hde4okl$G$*<)a<|gW2#n`k#0DKl>Yd9%H#G5DZK==9ly>zWsb9@M90>wEV9%KO!n%gX-HQ9bc#3v3{FGlQ2-cutV~Zl zZx?qYWR|dhCO;zab*2im3)czj3iv#_ioB4>NV6|G$dsUl;u=^~{Sjd~4^1{w80`jH zhspx=FgG{>p$MD*gcf48G4zX0dlHW>Q>0tjYQ8q zcNgLLDCm9udlkn>5|83YX@{=}+U|Bf+v)veZCg%xw@8Dwx=iX82>`ojg|DZ!^&KkN zjqHH{spyP2ctKNbF%|2^86Gm4LVhkfh^azwT%ZgeR>SN?+#Gm((}%R$mOsJFI+e{X*SNgUL$JA*uEjpWYhTHOzM|y}!i1m@Qz3ho{^5c*7M- zj`NlOf$y`_YZuU<Eu7*t3=$+PjKRVx4R{F%pb8I$&=oIlb=>r3cP!nnv!w~1qFptsK3I>%IeD` z$fJ`u8C*Csr<3p8Ir-~zA;k;hB<`Mg%z`sO0hrH8TiX!ObgV8h$$^1SN)%gcZK_`$tt6CIS(Phe)m$jbWi_&(D& zYA z2ZR4Yh`IeAKYsjaCzkft&d!%M$B!N@fA(wIN}Bl_3OA%5>_E!&5VlZETn#qdfko|pwlx@#Kc6U7S|M>H;T|n0^MzflY?Gm7zv=&=qV_)=O zC88rmL{xM?HX!rK^$0oJ^&vhXjPi5xwyDkBrO{6ah$QX-tIhL#J6b^FE@AMQ67$l z$_=n~WfeAf4!fm6r2k)kHa)x)6huQoDo0({=m-#jdkF8ol?yl}oy%{es>B4~jD67h zI)rQALW(7B(RAwI-0tV`)1q19Hov0e4#}SU#LJVwz07GJ9+Lo1)MuV`))oF*yE!>I z*>;{`ix#uEwe!Q6j%^BeI)DJeVYibxjeE2}Wa%HFgX)RR!hF&|a{l?9wmFQql1HRuF=p6<&JV9Eb z4lxODAHS{z4FwSFiX=69{KgAWPLSrvHY}@vZ{7okULE+i8X+-to*ESbuX{APlcyZ8 zz##faa%3728;%aNW1-7z$(N{n{aSr$>_1OT{$Ee5l%irCdQFf%To-|cCklY~NpMVt zIK6g!eEj}PvOmD>-Cgy@6DGKK8#6L90})9{@J9@^>=hLi zZR&l+VeY*n?JVFNnYD`V#pozlKuy1KBZ2GPKmq(8s=fo9%QtNMAxfyE%p^qFBPlYn zGaB|vW=f<;iHsy8AtR%mS!PjYWF!<76%mq=lrlmYQQvv%|9;>59mjk0e&72qe!u6r z?`xdrd7anMG8EJ<-@diwgsJ$?B_D3Sbw$Q;sibvjAllv(+}Qkw56^1~sJXa^!b7LS z(WWXO3P?;Vj(GFXo;`a)kXfwwgozOT*{fHQQ{HX|j~uSRxW z)B-H~zc*T;&h%)kUIwR%pFGoJ9YNMB*RFl;TB$3Vka*oiit<)V#3{+i!`PuR5)Z@G z-JuwaLZGj1ZC$%^<;tVG@tWVCFfwArXIw@}Z`tw$9h^Z`fd9dR2YUf{b(Ei$TK8>u zxG{0xEv4lM%~VI>ku_4%OPr|iG^^Da@>s)5@hK_Y7&%{5RMa{5<%=`B-dA)8x4Q1{ zFOl58S6^Rj;*WB`{1u7o*RDNCeg&CRY)nib1VQA-`{mqWm;K0#i_eUaX_O>&|@1ipR@JUat;p!6h} z8spzDv)5$3fkimygf|{q%&xkmRGtzvPU8EEnQ(u{*QU?A{o~gY| zSzAjV^lK`<-YvD5V~uWkwCz73<@zYk>h<9Jhlgh`wLR_Wxpi}AQc1JImaEM8ALvPA zbOcNNX1CxVY`t^nx8W?DZVEhVBOYdvmNdB zjY<8@IQl>4XFa_>B7RGsnQ~_TeD1-u-8cv6|1aTGi(5XR3tPFqKW}<+Qp3Q2<(_p} zD*H2e|GBM7N=n|-kXqQy&-{=FrzAB$(O0`H7X~m`Pslw@E)htOW!#u`9COvz(^JRe z!f&&DCW`lfgVBKD#MgK~Ju{$3=iw?{vCT?NO^t`yAs z_A={BKvE~NXF57Ml5rI?fe_=u+%34sir}2O=c$8?|IXc_dH5#kDF(gJ=rzfz?qlFj zw_EEcvTI^aUAF3KpjOS#NU0UKT{kSBjYGAQwKHru_f2zn*Xg-x9TM)1cBC7Lxayv_ zrb$etvz zaFW|g*DqVPthBs*Qna2@MFOP8J10MV#^uRjT|%K)tOhp0m!M~uV8G@CbXE*fea8Ei^&_w>|&dpu;+h@) zd+F&hUJwnWvcv@U@0+L^c6z5IshwY%f-;YRnVBxWPe^iRqPJ$r?kmzXTdqb%l@u3; zqCgUWX+5?};L^w|DA=PSsW`hG^XrgcH!u+SvSVIvtl5YAakHh^Me zVP{{8IQ(k{j>$G(LedO`dojcdl4F%j|d;-w&|!9Yy``-iU>_-$V$&1^TfYVP~?EywFNJl(14rluT|TbD_# zoW5l_Gjpr=D^t!g4TL zc$Z}yCb4f+UK zNkt|>-Efm*(<}gY8CXbAun5~!@%S-~lj?IAaibR7e!S-?v~uVr!k{TiL8+DN(v07> znw2#OugVczlIp#WN7`bH4WqB45kcS9^$`QDb^tnOfD2B}bFt!uXu|xpg45pKKJbD6 zK}=h>lzKRVnx^~w`LlCdc7mBdZ%5VHolk0OUxNk&{8^cMdMJXCfkD;6f)lDwlm1?& zU2-$~F5cO?`PUlt##M}!&NAVePv#D-QPU8z7zbGkUu3TZj&BIl|yG#Mj?maWkuM#kS0WKV$W;@VF zI6|lK{TJdS7V~VeaaS`1y+t`$5KwNQ6s7G(*mP1C+u}rIW!J!AfTFM%T%ft7t*vd4 zUINd*Oap>DTr}!=V6RJI1voYOVI2|`IP60;9Bo6NvY)$y2e<@`tj8Y~1NKcg(;I#( z-`IYf7q5;=Mmp|zcz6{UKpLuoeK+>9sorzh*F9D^JlD@t0-&HD&v5+5j~c`SzRS<0 z9qXC#5bUA#{__6eW_mk3erKU;Uvl>Td1H+EpslU#%-kHhh`>(%#pZu)E#QAf=B!UPwyQNH zLTV0tKYi*{9kPzSv-6e1;~S+wCRRAX?*0o3Pb9+pf`S^{V0@)~V9#jX91#(vw{ATc z4NKLh!OPdUkN2u!w+k;msXB;nrk~v#wIi!9tloIBunL7u2fB8UL=B^!*iQpKD`sq< zRGO6kfG%2txKZuGD|dA=vuY%_T(-_{dg^#jg?*E?erhTN7Qmds41`TwSI|4v-NI^T zFGc7oL3n(MdQaYQl&Ym9Z=;>bsFw-W_PQjvndHn&VPt(E0OGhc$Z#>w4`Pv6NatMl z&S*#|Nk425dXX?ESUj>C_C^klygLJ4B%0>rt6C}_#>Dar3}E0Ep0aJPIQv7@%fo*T zA3nUKPU#qBhl&^VoI_*02ul4WzzkWiR1|~R)s2me@QwTOp?v$|Th8pue(Cw~$3;zn zxqJD{U}%=(d8ne51~4Cm42wB=c{KFAWq!y*_{N3H%d@KwqU9Jhw56b&Y2%`S?mbe9CKOA4T7tKRO@wT$8 zz2f7)ercl&%ejcOnGc=SyPm@U9Z(}3ik*&iy-P>o8VFAe(DdfqucW0Qe=~7x<82$k zC0~cay$19W%Z3fB5W@h@?vg_fY zm)?C+quy*orCBcT9|!>f4Ffk!wk^#39;;f7g8*mbKB!)6h_LL*4&-Ff?I=M0oY$*! zcDZV^4eJyv<$Y1kQ-MHT2>60)<~=_n1O0Fm1YuZKObcbeQ@}AKz1e*Et=|_URi}Jc zJQAkwj_hfd?C7>G65N9_Z z9?Qo02r-c|F;-+nDsX13MjTK_VpnOwk*|oHj$b?zCMMQ7X?XRHxVj+$-6*5$gZQ%Z zPHs)0u*p&W#3u$^rSnJ)0-~afPz^spYh&5+6g?IyTTa53kO6d09N zh+SVg3O3F!EUd@*HvYkUkx6+x{|TR z&!hSF&Sg}^*}uF7X4MZ13!j3)mGS*`lr)G~j(x3aZ&mDj9+PAU@bne0qL#0Z^SZw0u-G23b5n67~$_<>jIHZ93G!o-iEQ zT@fTk-E}w zeXNW^WDnz>FJ4Qz>kHdkm&@Y%K&#oGuTYiczX!{Cf~7PWlu5ipqByK*){wmWIL~j^9vuR#}V-O@GV7g)S%oF|xUMH-QI4xKL_xwXyH&))nLr_FIV* z$P%u}sc=FtCTD`l)c+s4nBfFtI{7nG!ec7fv)A$deGRfDJ3BjydHc%2_lhUKP`HYC z6JOqFFXh%K`UJmD$gA9mM_HJ%bptmOKkKzA}J9hA4-opnEC<@<%bb{EG z!fNw{@Z{t>_^e^VIKcB;mtEgtM{hK~8o#tO3r=zaVs3(}v(aRTdTE6{W-^w)4mTFj$L zH1b{92A0nH@fkJ%7FvK+azYsb%@ghyW-WdG^2G~p{=wA#R}yM@m-K?OnON0<%8zJo zjtq`zeu)A(2Y+`eG1V;I}wUsN<-n~#@@VnbEx?P04&eX zFKU3ygEU%(Hd@2noC7JMY5Me0WQdumuWOh_urksSxGr}?XIIxoNy$r5g8_HR-F9}q zfOq@^t1|IdHBfv_G7F8of4B_rwu5XM4QU?d9#l9KHp@}rS53Yb*0IfCRt zZX8T-VaO6k@jMRu1>iW~`idyxs8Q+yJbl-3-f{I z89#i3_YYjeG)+;P04h0H()7UU!krfE5m*UI?mX}eP@yY7pRvQuRSvZ$x6>UUn@3L(4Hn{`4SN!8}2q z?^DCUSVMBlYi2z}lnOk{R6I+ePHn^5EwdpuTW5JV=uz%R;>2^v?-gF_0K>}JOK`-a z519LUmv!v&CeTnqXDV=3tq&Yv;%NueenZ)p-JyV!KqjykGeFqGu}VfpamEF%RNHjm zzz6leJg#W}zcA6Dnbpd^mbN3YYeU;dj&rKX1&?Axk(Rf*v|cz(=6hry-76{pU_-7Z zkZAlG{#YGUoYBB}lYuD#SPsg{5&;fqNGgD;L+Xv7xo+{x%X1`a~_gRVmBvQHnXfT~5!4{xb^i+eeOzEp3}*ZZnfN2$ek6 zQxT4uksnnNB^@w7(U=`@|>R9*eeogJWpJ0N`MmG2JaCpCA;m zwZM{LQ;a)db?!H~%38%~qZJ#mcH#Q=UqCr@^z|K0|Cr!AF@m`uP`a{? zgTV?vTr6&A-L=mzT@eE{nc4DDEWLb+PrUWmX5hN$$#;Q~8vBFtq>mVruGwufmP^gf1AsYCM+y(ql zlPJ4oOYfI2gg!(ofP{LnNOG5w{RA5y)8@cvv$ddEtz3MACxTA;~j zE&T{o*wS!Zh(nKkjk@R(UteFKtn2|PqQ=27smWaNThGVEH0p>ZJZW!F@;}m4bc-g$ zjv>n=GAasHnQfKiw*&ma!c|Sm5WRISz&jrSNdvtBGV@X-JR~KgpZsTRHI0g+3&SAZ zNM8y5kz5d3G1Jv?w^L2dtq#|$@H}j^b+$<62H;$T+l(I`h{p{`ir#Em@;yC0ndbLz zS;5<#n`tE*fyVQE?5Mf4No zQDs+t?=HI>HA%-ezlvK)OS`-=gp~`-eKVPN#Tm8Pa`LP z<()fs0M9uM?L+Oh=SFYkv!Qylk&?(?sy;OWii+iL4ybO{?D}*pX&XSJ(z3D?^g1rz zV6_lC8H?)eX?S{fMmu2``Uk68=;<1DWdC+V1Xo^Z+6}ZNuXsh8>Nsv~JG) zRuI*WsB^eb=MdG$8MhtLPo^-{1u3UA0JfHXe%>?}0EfNXYly&$txgz2Tm~o%DBKSm zUd-UiL2!UFJ{EjQ=h3w%vC=ZoM^3kYtt5|Khss8WZBS~KK$5n#BhY#A>Ai(Pt zzSAoSSrng_2g&CXUuA(<255}DCq6CjI)=_u>geSwSDx__U1QHT>~>@P?UQZhWw^kV z^GBR^$&&X!dLB425#0s#rMpZPfG_1dvkp8-!g_k!!VAN?f-gA*og{!hg7O3z0ACQ% zYzX%d5gk#ovIVf8by6FX4UTz&Yx4iz8%lv-loaK5F^Y7KE-s9CXW4WbI`sAQw&;&h zLuci&@H_23CD05NhK$d|Cndt`W)|HPUP0ith$P~6r0wP9mC`UYgu)Vyb!2DAi9H;z zARLGv8%ls{hu{3nYD8YC9{~wPZx~~eBh>}dCqRaP5`k!91#0M}NL)m?fPx4&9Ty`Q z2oKo96~M5t?3o6^MFa4TD`7x`lau+(3MA1V6per(Ccz&)#CuQpy-;>=DNy2|86ZmH%uke1S0u_yODPH_m=rWEW($Y#cp#;493X%iQ{{hc4@&(G zJn%8)Jvc+C8t{3sKu(09X8_I-_XaR|^8GQ^m2v>{|L&1ZBZ;sEHVBLuMd6k@T3Mc6B9f{bZ>F8hJv3?2&bkTt1wSOepCFI{Bq9*!a3m%s%AX#+Q6Ce5(Nw^e=W%FiJ3F~S z8~E%s^PZg$!v4BTXcB2DGEiUo=+Tq5wxa6gD{#- z-@a9NT~r{9tE-Xy5eI6)$dOov)TbtyXlIs6x0gOVFM0G4Uh9I7Xf@A>{ zABrtIR2vlyVWFWDe>SOdWgD(2A+H>I{O{Y^Rn}3U2-A!Ap|}W%q4)#^gBKnLZfQy5 zPDiIYah8B(nJ-t15YH&w=7T9H2CEwPxIumWq)|xTb*3)qpG$t9Rul z*_l5neyzK1vcks3#`bo0sN^UHO>n)s2xK**P#{K`6}o+65SYNK@?dm($lGowp?0%WkxRU`J=wTmdU z`vGuL6!MH$tnB8^%fNs2x$Va}Yi?cztg95U4z9E>_n!p@;_dA{J{kdG42(KGu=IdE z;Q6y>fdCEHGSXvc;_ffYZ}=}dyLUeY`)+sSNI39M2lV@(s!3Qx)}x`Y%&PZ5>B}bc zxa6qz3|-I9mktgI=|gh4qT+w1GWzd$-xA=tmc5fPZ;ao3V-z|Pa&NACwn&aOT$4mZ z^po_qjMemJ6FWYFF?b5vXEiVHC1A+|=;#)YQfeyYG?R++esmtZ35F4Nju#WB3vugG z7Emm?*CY-@IQD%Z6UbD4aj`Z~02Fl=;~`A$nU!N;Bm02)Sv)=?H#W=k4Moru&^6_# zODuZMfaB=~)WwnOaq{F-M8PN=7JEWJ{eiP4U$nt0if9edPJQ2Io)MzRo}EC9dCmh@ zy!Bz*zbYAsn3A$`N?Ka&AFpSFCzQ_qA)vgDj!rcy4)5mQh&si&JF>px7Xv*|Mfyo* z*19F{LA!eO>e4emMInhHycyoxT}`)iG(xE;0N7LB`)IC1(hUv^TS9@h^x0gCk{w5E zwPJw~TLg4Cc6N4_W7=8$jdA9J*@KEr4==LniQd1z2*`77$u4wSI*9W?Tu*R@)P&cX zHKKrE8PVkDR2RLC=h%<32CUOz(rmG52aGsFez-M&UF{yr9Q65DhPEM%L%DeoEjQA1 zKZI1=4N$>4;QJH01`ZnTkRuZ01!o_?b3IVf_cMTa1$OMXRuV<5A>fvV9vdPJf`Yw& zgeLwx#~H4z&MZXKR2lug0g0Vx!sjCclrb{h!9R=2mCJIe94eVaEU^#TT-e6E&MnCJzeI8ld_OAF>A zTH&$`;C2_VC9t!WP6;?ZX=u`^>PtWI(q3a$0sv)AZSDE>-$>911~no_ws~ z`UjkT%C2v?+8 zTCFdw;ggzaB^qNQjy4T*C&J%8@M&oR;xV$ZZNTfDWKL6MI%FXEPh#URAoh(}55g>D zg0(YB8Cpe;FW>1J{5f4!F}nTr-q{elbfY7c{G5+iRCQ(zu?Y_>|J~fv=S>V|=~Wri zNaFv5^!Gu)w`1Ry7tu<#-Ml8_8=uny`C0S@cVj^tpIFd`V3nf98F> zeSOoAvu3bawByQueVbzmrs9IpN#!WtcVXJvc6A;)d-v0)m&J2QiYo?KX1vklvRDty=&8De#l_~ z{2uJvE;-+hv9))JAXnr4Pt#CHr9^WCWT-=MGs|{${Q{wmfHu@& z`!?m|$|u~l1+Y8mOo5s_#XX~;peO)!&(MFv^{q#YD%(yffDf^60x%j95y3>+ zL5mHM_UH8*_K?%m^E**TP#q8j0xe0&JsrRk?NKzfynbzOY73z~1CVf1B!KUMFp89p z2M-D+&tE!<0yCF;Rs7l0Ah2KkRvE?FC#nrJ@E!h0@^!dQi#3of#1y;`sTOZXD_!LE z3GFDC;dlrO8_m?|19d5r-@P|a5;_OLV@~LOOKhifee#x?^#nx^j!X}DewQkVLNSsC zv3iVN2JnCU={+}VG==7hP7z1PVLL zFZ5JJMTIodnwi_bsyMOi*E$2UV4_$oceArg_SjkayR4DMCp;?3=`ss`F8+ogUN=f#;5HY9IShC0JC@ef^e;fZg4IvcgOby!E z)oa%VqiBA}va$hmDU7p%b8>R5x{~qy`Gtiqn4Uj3q5Pq#iOKlRZhQVU&^Zu^C9rCz z0d%PL4h}&mzN?|OM!B(TQRGtdzyN&F4P z#l_B@g(A09{2N94-2wSQ8)5OqaW?}$!oO{yfv%oNTq?5v8fXWD@O>u_>8}mFQ&=z@ zZtHUySec{}{6@-iPlx%b8D$kdDNzszUK?HfBAI9VF&@yiM7GqLw?8Q=YqzYh)0V4d z2Q1W2YIm8Fl?$M!bGBPy))0#fW2nNT@Lm{D;^UC$vkYTInhLDAo zC$TEY=iUJAG~`G?EC76kRR;X1oHz!26e74lqOAOl)IW}cl!`D|QGn2%dr|dR_s|7A z*-261Zjk5(X4cRASMRrl*7rGsdP)q(F$MH~7_aFV0hHk4$J735+w>fA3E{>`sRdPE zjk?qgWW63YkUB-#E$I^}X4)D1A2;U@$&U^uw6K4epru|A<2X^7zNf8?>4Cc-1< zz~9vbXz4xhePm=c8(W?4ZAgpifREh&;cpC-9`*yO2xh-|^=xf7;MCLti}$wIMbW(# z`+cXzDgyiR)jt5sv+0<^4x&7GZlRteC)JF#JAJvYr1%juYpr+YMSF6e^THfn-?Gz zp%N%~N1NcbRER&jvFo>!PuIr>aqS#r2~#}^z{;6Fz|W7QNV!a!ThYX&9xG9@e)>5` z>L1C&h(0+sE-nZ_V};)=E0MuN?-Uaodk#zvDLH_!@uCpSW>=}gViO|MDVHMCKem-7 zOqG5!xGxiA!b=fefB9h~41r zlJ_UYfdm2uDr$_vi$$lQiPO^uOa}u(s_$73LPmq)5mA(+%bdLi-O{T?KH}H(%F@|j zd}Be`ps&9_2n*Sjd?x512~yM3V?UV(@PQoo{JcL{)ed~KVQ5;!)5Aw{MEM4i3Vv_4ei z0wk+BR4rWYM94$gR*WxCvKxAGD9kV5JoZC_qK>7kEkF}#&sHLDy>HZT-2L8FvTtNb@o?^J#i58#n*m8d?yQLvD|fHGen8_-G$^1H{auOM zPp0JAS?{zl+S1ATOY~AjPf3cFtnfg8e?A-@Gy>Br`h(`sD}(eBo*E##Z_FgN0M$TiiLE{xI_ALt@awpFI5MHF!$22IO^v}Caeh=|E@PY*oIwki_E z3+V0dH+okN($Ok9NGjb3@{k(fWrY5~G7<*hvyCNfs%p!Jk^RV^7edw()S?A2N9xhq zfy+NXKiTXO?F-dB>SXv}tgx9$=R*+F1~UMDSQ@iBJ&*9=h%y)`vZ?P4+zE(gz?|c~ zVO`I9Fc%$HQVadg{DWp*9U3FPJ?^JYh2-Rj0YmkOUM1oWs4La-X@Z5%%A?MgC;WIO zuk)v_kQGK!i$V$Ai|FxhmclgSh8hHLzTRifu*;8nwoF~~EUClX66b+PsZESLiMxFQ zss=I4r%wOk%M)7ubTBTO;}a7>NlE6hVtj9Z^FNPLY?ovPF#(>70ro3wIV-Qm#|Pt7 zKX7S*L?6E`7$X~i>3aM6YO=SDc9pC`k4lmvMgr~s$tTQ2c9h`4Yieorp^4z!8K8u* z+-M|<0g$OwAnbU0K|gbE5JSt7uDb?+bqydfgbmy&y7&=Y=;2=G*!eHaoho9yMm_|Y zw%|cUNrrQnUI78jZ??m`QMa?>JGh05OoSoJ_Z)`!$V7A3t^rbAzRSJZIT>@&5y%g> zM!0oH^eg@4L^}Txc#cqJy6yX~5MKf)LaG|9P66Bx9v)h8-LD;1NLU2MhxQreO@2|47PvYC82>4G zj|Xx<n4l}H1w!Rhlk|jl z1L9Ao#yYge|4Vmtw#j*^(|gv4x+!{R8PnF}?j)mImo{*C`OHm;5K&^H=RnYjU%!5R zuX<9sckVQpiu5g>h#J81uz&<37xqVvTs>3RzfLJ!xoIW)N^X>H7KeONf`s4~v+IJ#tg( z_KPFA@#YwuOJ^v(DCE<3D8Ms?#O|K&Uc&o#K=&NyEBf7~P?JGRo8N+MYOBy6OMCQd7QG+70goOo zPzAM!<4_Ahf=cibw1^Lx&YmdaAs9Qbm=>%?hv4R1hz$YN7ZrVdvf|>q^XjzhFRelZ z8A+9p6$YPzd4iQhWCAefE&gjDt|4z8LJ~chvCn>&GXq-q{V*VQASgH>C-c2RK zF(A!!fFFxm^zFAE@8N-mM-7x?9sbZS2BKz!UtJ(l@?h6HYjg9Y_DvO;$SUuLlDd&R ziPQ_|Z7+a|#R0;$+@DiZ(uZI15H1%Ow0{me;!j3JL|0LqKHOoCDPGxoS z5#3dzEMp~$5!E&x>e5BOhbZ6^A}!01$5{-YmIhrFMFsh>1NgI>Q; zasupIau|_=sF|;u0^rpsbZuV=p&pq+fLb{pR*zIQ5)njNVPu*CrbXOKq*0A(CczUO%K&+}bJBP)G5Lc(C62=`NEJjzMBTM)x$?^oWq1XX9@JFj->C0@Ww-bi(i-mXU$MLDP5Ts(4K-Mh@gGQrQnB;eR~2zUig(xf5Qy zfNl7E!zJ(_Q_$52d6*a>`4%VW`!7@*ub3)PKF5_vppS=^fXCn!bApZ_If+2@C@M5G z6ax{}fN2V_{fe+NIA?ggb$I8}m>q$XKwE;UJ@CThCjW6~X9k=MlG}ctX#O*FsKOJP zoHj`T_LF}2fX;Ux+*0$wCRo73q&LH4l`1N}BdGp0T{DYiAAy*C>QGSck==Gc<#dOZ zAnV|41qprRt>X`qlZ)TaG~2|!2}Ses)49X+IS6){d1s+D-v0+Sza1yg-;hZ+N0f*x z*iZz;EhRc~jU zsGvQ|co{VgMBmTW6;*mNb3Tl9=)ph&1I43t%;P^{J1_QS2A?p?Tcw>@4^v&ZxPHY8 zb2psv%@U05JGuP74oj{LSUkM9GzC(;Wd402Kl^_#tS<^B`=Fv(k;EHdORev6isuNj zO9B=dNq~4caKfPjXHUktg^#L6S|)>%a8L+0wS!d40`qsry%aev87`#$M$Jz|7tj=i zA&QZ4QQ|d;T9mv#(s+VD1>v^~Wj|3o48Ax+Va8YuI)_`b?KmbhPEOqatNwib|$H%jXoIF$6i6!n)db*K$-u&8XbDm`A1`)9-1;a!&WY$F1A=-{WUy&wypIrMf1#rxL(gl^{CD=qze~Uf^X&dAv>(3iaw;9fJHf05 zlyw>)_kVO9uOj_E>@I>kw_&#n8KwcfTMJHl(C)q{54g+FNAO?pap8;Q>p#V4MIZwL5hVN)yz z|24zR0G)%o`OBOr z|NrNSpe>rvkC?_?<=iAT^Q1_Bj>n!e7F$(pKQ@o+;aE%=wmBNTZuw~c??X270{mfU zPr7Lo{@?R83c&AhAj)4kxjG!Maj=E&e(4m^$Dt{8$)dN#(Z{skfKrzT8|3pT5sm-r z#Tenmup8c7uWD;XrUda{bY|^bTrL8D)(~VZ=+(!!!jJ_JO2#ac>|a+P_UguNLpMch zP@^@4cyApb0~ubkZ+#wte|xN3(~kU@nC5fj5z2jmXix+OFe0Xy#?L){Zt*av8|JkN zBN^l0Lf|EKQiyX-oJ^{szE}q}(t{p)@+0FtA?e!!6%GPE z?8)8z*q6fcFt8p?g4&+>C?_M*eT6Z@4(VoXln3Ta9 zM=vi3$SbHwmzEF}{l#znGP>~p`T{Jzs+h)5eEv|evCZreSs(thNC`G!LF25BAl`x? z=e2<&xGzYm?7Xz~PmVS{>2A&Cii(Pb$3Af55@h1LTzxEwFV1-Fq}t+l!K>Ulzw_6q zl1lbm&)*qEesNZIr^dJ_p|uVc!F<=4O_Fugm>LBb5;EAz*d7Okr*^1_vbnY~3K?b= zJD3>g3CGq2F+Ej3E-HKE{-&eL+4W?Y4Pq|P(bAop|5K_kv|aY@Gx-0*rV`%sp>=-5p~-83|zRNrck3sqyL>*~m* zquZ{dAHr&&H!W{zTb^N~)3qj`z$`lb0}`A?%>$B8#`6ix~$1R#U>awI$K&3U~M7e`q+E}LUcLy&8<#* z6XBsI2o+!Z8hAaW(>r9=tx0>LfAVA@V#Hk}*|&`hsx9uvikdzq6d zt>(CpDjd47g`gqBqzD_-ut))OdK|e+u6#Il{EGKwfN)N5_RHA>jZv3DuKNQ&l7cK^`8WtBBTG3awh?J(N zFxRrO5;Jw|{QbSw+vC`gPh!_!*3;8bG&M6*5_w*Dcn0k=ik!}maGpvrxtww5j+s?z z1k{29CN~YP+;_|~%R#y8GXR$@TC4mptBNRi%-keS(PWuQpZgb3Gm@TpZoNVZ3h(`n zbLwpHCXc)O^)>8enORel#D|foR0M^Gn@^nDYiDFgA3AKpk|lOa^m6O=0Uw6++fj3+ z!fL&6K%=AG*xLUmLz~s*M?HQprtjaOmT`LcexBP~M!xD}+K1JFs&+S;i~?^Y;csv1 zDWT1bQhn63B)N~pZ@EC>CYt%Mo$2`H^Eo?G*pEBT=c%Ym^sMFJ5Zk%a7U@n_?6G|F z%MIr^4&xAi-hBATX}aVTuKRHGOK9H+%qf6)WuN`G0FxRQHPDba!C36gn2j!GFIc`) z>@HasJrk0^G+l32J3wc{4DI0Okk7b+DylTeHS*@Z%Yzy7slaM2yLGB=EyEoDvjFQY z`->FzAs2~+sH`SCeJ9bJ38N%@3K%xMg@P?(f~gs6$y!TLOUVXr&gNV~iP{%g;d_@l zufVnWx5|{-Y7}fWeEY7b)K4~V8FD{4R+CkUGPKD(3Sl;QN9#^X;`2LqAKkWJV;_ww z^>0fjr6!CoqHUp-P{>Xe>o%3zF&3HB^|?Ev(So~Ld~Kfr&dI?dt8WtH{o;6uO0%#* zyaVdzjDjR3Un0-ihU2T!n=1G3MB;Z)EOtQ(twwEE?3fE@vf;7_Z)vQAKbBt|!4F$h zJYD$w;zFbit`0oY*VBIimMhe8a^ z)H5@VfYZ6D9nJfp<*j=GCiVB+++iw!f4{OU%tr9F!wSkkC`gi;f9_JWZE7vGm2Yub z8`Zl+U4lXTl|=NXwE+cIdDhO9fh!hk9?kk3$-axCY+>O_-1sswR$rqtaC_DF4F&*9 zZ!!gjYAt&4sb1cdNgs99u&+*GJ`N8K*)+R~%8YHKl@eX`c)XLA8Yl4#t7b>^aJBRP z?F)mgoQs-&e%Hw7=X21>>KdVa5Ak^QP08)P*k~We>OdL;ja!}ET;9qwlnK^t%ALL6 zG2)fYN;_@||I{Y8o-o=y>uL}?DM~HEfQeS?(4jjdwwrF8VP#`;l5BYT)SJ0(MwVwl zWL|()n)0(V@s2h5x_P1Ob){yhfTI8W6Kyi4p^#m_T?FE*C1 z_;mHTKl^vdRX$Wfre|Uj-&Bm2!Yafbff&R@e}TjK)q!|!cz0OgIw;_^1Ysi_43Vi}XRPr{w)x1lT$@R&Pg>C+~S0?{h z+~r3l_n2;O?RSf;DqCg-#o)^r#uRpMS?q&LQoXo3$YW(C+0G=y;~1%UW-4=bFx+>% zPMO*GGSjynT50$OZoB@{8oRv26>jP<2Q$setq5tI3es~6T5tXIi1(lQ?U}iC`}X)K zs*OqH4+KY8pk@}En z5L);RnE)l<++KaWiy?HYlFE8ZL;r=UDKDPmU4AQiO@1EVf4M;yv9R}ep(3rpfzdI? zBVA0%y31_mEw{m;oO0HKNpr&O+xs%%L+5>t(jM zoc#^H-MYH5AC7I`$7goR{sZUG$P*tOoeS7eDJs5wo80nCGXrbFqxkcUKGtlu&6zeC zDqHbsJaOmeLrNUM2jB+z-1+p{XI17jbSsCd%v~p^r335J@F~b~n?KtlS_Fcl!6_F% zU(A@rg~p|s;So;fdW@xj_VlzI+k?}H_a+CivS`DOW&3X^gwaH*YNLkZdg2k_CVfN2 z-wNc;iTC^P_fJ7{sB2_tc~!q9qaf7Aq}Ki1PRZe!@{yI?Nu6|QkrB)2@R5GjIiD8P zMf+lMoHEEls7&gru%TEMuR!vVOt;@D*!+;RfJBFAU-fQMpf%`DW1ssKQ=OaVCAG&h zHvP`g!_C>JwtQ$fvu#BVaga|q_8U&gV&AK_;E2pvy-d4zDSFOuL&C9n!`NK`*TnkP zP^!i;$j)Z|Sf4nczAaGCaD+Z^^Pg!=+E-0zX}u_CJjds#w*gLQbHNXTWqFfv`Yap-bv<%EGdZqkFvogvZk;n)21oM)b?c>yws9oc*Kdm-C^m0$X*mU2siZ}sPHUl z>Wt~v99Lr-IE*b8#h)FsBc)O}_G-V|fLMveA!X+NxZM>cG`&FxK^yyPoCx5I*W*~Nhf zets|+LJvD=I0=h({b4zS8YZwx-kiK5V^G%``UYdV#q1 zLWer?q1+r9E8)_|$G#FmNZcL`+P&VvSqY`&ff~z)6^q!&#R9uX?6!C-ipyAm`)RW ze8?UcSFCW0Dccqgp@@E5CG2`JowOIG&?cy7*m!wu?oUe7ifPxe4K<1tx$QLJNN@_Y z>vfkGHSvr!9yFqiWNk9ZNh%o21B2igCx!B>197?jCdFyAJ2W8D(o6LgUvR| zOTPmN5G)y%M1k4{@izXeNuQt~^!yanN=#S*IcPU+q~hL&$ugsMac!BU7b{JE0_d2Z{rs>-arc$x)QNrI8EYZ2xA1i2FU# z0aohq9GD!Z%!~)UOe0~`n5gT1leaFC5IA4FbjfRZ8RzEjQPL3~j*)#|TxnRp!{P=F)>vzfBCwsyF`k++kg0 zZBytR%j?~HPOkyCQdmW$a_^8QJRORhU#r{OS3XX7>@{)?jQZzE@8cLbJP9J!l%cfr zV`4hMAK$zg?73q*Q0Zq0h3c=_8M05X^7n@^Ru`K2rwBW?MMw6VSjus1oaxVUh%nT} zN{P2hDYkD#rR07BNQL|U9!T%<^79^4M>Os{fUfydfe`EBv!2nwr9eIRa{4+7|Bdss zTV+hx=?&KZd(x%{52j-#1bc(Xw4-T905pZ`<=s`We*p-8D?oX21IgAZ^zjJ__cAke zfZM-Aoyo?<_4S7Z3~vl=Y;J*Vy$}A?(;smc1>P-JT4bHxec`Pk~=kRXvtJ`?aS-}OtXA2w!} z$uG0@8+4URYUE_I;ZAKN?;fW2`_6Ho?Zs#i?4z%BMeS=ZyB)Z8Ge3er@8Np1RP%43 zQGQ<+6{4A(<5h*i4Qb$s%i8_NmN1Wlk(zhYlF3sv|u%4-SUI ziy{Zw;V*EUH^BXR>Bb>x-D12?IRj&8`f*@goR-?+K}=zq{u>O#Wg0lx*p7haB-<$w z5L3{tl=Jw4PQJGDY-Q6U+@m9KBRPYuOfSau@q5X7AMDvBZq{tsZIISx!pZEm-$XcA zi<6j7_*T?zW9;o+N){WBbe9>&6}tDS@3|pg&^Yu1v^aS)`rezcDh|Zk4lHHm^&77d zou;YYKB~qsJ$B0SWnI?|6oL1#1fy9gz~9tIrjrW^(Kol>fzBp!-#hMZeZ9Ns>5Cy# z^)cpK4AD#a(D=c#1*_4yWv1V0_mAzNRQ|O<_it!$V=I$p#sFN&F%Xx6b0ms|Kaf>V z%iqH%CwA>NSm_Carrn@F+lg~Muy6f1*mvc?rm%zOZ-0aomM38(`U`f!k(~u(A0iSp zs;v(m4eLM8Kt1(QXle^K<;WfH>CUwP(06R9Ell-aG)zNRS58MBI9WBS`v%ueNVlZ> zLF^sSiY!7Z%mjbJ5g=GcsD$FDM8St1e&`D<-Xf=MgE49jD$Ffpbsa0;gQoEF96(yr((1V{Y0+q}+{h9SI7L#@z&;m zU$UMrq|VOjzr3Z~RpAejzyiDzk_2B~k$W9%C^J{_V&8w9|Y`XRLL=Z@U8V@seHU*qMSo7NxoSi;rF{yK(t) z8iK(WR1Rklw=yPJ8WDzG%53l(KUY=(j9zvsbz)x-**pvB-IjKL2wy&*zz2OXh~qe1 zQnirhQ;vB~-VJvPDhmr+2fQ@Y)Xu%H&q`0%gjXc0<+q68FU$vJnE>c;gC49LNS zDX9Ru<%^M#Q}S4M+Ru6nqO~Z5o5MYoezOl6ev`{H@T;Oi=`j{io`Kf64Gfm-l!FDl zE}KRG{JLU(jyIZSs~mat)TcHdxhsTkcWPYwuqd|5gx%}MQ-%t8^R@{= z?6~N@jcrsYUPJy23rwNM4qWPB&3yWJ)mNTC!&zU;p8K@tYG;0%#x+#gM^)`yUhzMj zKA$xT{x_hDPa?f(gh(Gi;$mdT}&!mA1z2 zHY1;q1gtrNJG-|(ZzQ`mc6}1BcNn*v`t)oyS<@*wAX?sXtiS>bJIGSjq@M`Y#<){p zrU=yc4YW~QdKm8+9ZUqo0@6dq0Wge%A?NV)0(V$=pxqGfNsqra*IguE)g(Py`KZ)W zo(H(yp@bxqkTXszP5rmLT4SprI(qw7)WwV0?rJGJev_?H!|E7sL%%FqaW=u2uYP7P z%hF8S`j5Gyt4d)y>%Gv`hD!wy^7cNesQ&#aJZtTGTVTC*qof4$PIv&rgh0GrDQBC)xd78 zoKI$2kn&1gQ}Db4OXV*=uOM9iTXD2z)9w}^d2(3EcWR{56tfG4*jfr^?Jmf67|H8` zrr9#~8$(v#u)?)%!=LeGx^JNE#y+IGWWNqsy>=4g^0F3=up>$n{2C!uDcuh539@ZG z?rq%+!lZ5-=;Cz5x3BlgN8eya&)}rz@~xZxxa>a&Xe-Uha1WGOWYZaxgaKI-MmL8g zLx-JcV5zr5Uv&(4^SiIsAIdiDj2REuIj#_< zKcBJVtm_V-)mgt5qW=D!_g`Lpdl7J=i@g?Xr4;2sHf`xeA2AX8p>_0VF6N+9$(ABC zF)@O$!#5)PmolKE&?lkzXOHigh>D60+;B-|NBN9p5ceS2BS{(?MhpNKl;R>N)dGLiY^{FS5@v+Ox*Yx><8BIw7sT-Y=1n|%0B{{g6tLlAibJ|3&zx*si4ZK=V_Sz#g*B&qBNyp8U z7PUGdiE0&EEU9Ty@2N`^{e;o3EzHflEVpC$W5xO%CdjwO82w}eCRM!RLIZm9#zRV*SW7^^SD_7^Spfk=Ox=RFZ^sB)nSM+In&9QZ~6L7W1Gx zg8=Bv#PiLkkU{hZ&t8d!VK9_>tyg6aiz*f4K!*`yV8OD&U5xOo#RsqpJvmx2xi@OP zq8VhFZAc?0zvY#HdNdryW|GR8ex{_rJy6utaM0!5F?yLHIs2wjSWr+CpM&k4`Sx*v zRVhh8${26+<~|P~P3j!F9;jFaCm-hkIr(U8{_a?v@nFK-${MPs{%v!Vq1A6CEU6-`lAvj1Xa`38nn z6qcDp$OMOmx*%y>!(P$`x8sk0CX$u2kTElMA@tsZSJl;#1pEZD?D_*trib5TL^O4v z=@&!!j~H`V5YNH1<0Ev6Q!iwjz5OHuRo}+vl(o{^W|woGA_NgVcD@rF|Z`@fU-_D<~5&$(9Emp$q+dwrFvqbe!Ik`uGnxct~w zZyRZ#5AfQ$GSUsu1)$X<=y}@xy|Bt9t`)F}OY>oH$Yhfe{BaHVr}`rxME;6F(fI$v z+naz>y}xgxOQ~qs%_&OLYNALXnn;^kq|ibcD=BkkiO?YJkXj{0q9RjBGEWUV72A-A z3{f&iDpM5aepXTMxz0J)d(QQ~XI=mQb?x8Ywbpm|e4fwq-1q(557-)PLyRRJiiAw< zoUd;gtZr!Vkl%?}TTM(N(Zw2bT(4UZImdYEC2hd`w%AwF%yd}(*h1F!~@YI-;K);r#H3`Wx7#5aAxG&ZMnEk%S- z_3>e9-Y&We6;?3>1LdOAitk67WuMXiFzcv|wsx%7cXe4XUGy#j$N4ku-R^|-we7mz4skFkwhvVMJf$?L6) zN=J2Ohb_0qYXb8_KNB-um$gI}^DDwW{YWHb@4e5Yo4qqQ@@cmJUo!4RC727p~uI%kDs4dFi5}Ip8 z3!r`6%|CYY!qQQU6G#@>k&TNY>Of&lNIPpLmZWh>OQ~?-6`-+xnha!sKR<(8!5}-Y zS2yF`;xpK3yZ+jwQr;o=lR-6BPW+j(L0aK-I+U$7<)mqP^(hgov<0i#ualpbBdgNX z_35=ct@r)*oihE2Blq40vVpmRu?xl$K&HaLDEbNPy?$i6o2jeFgrx1!Q!MBr zCm~#3H7o=8qM5&Fs{Lp0$}{?Z*Bw52I09HEcSgYQ`ar1%#C^(`jux2 z%{h&p_;89Fzi<+Nl8j%}s>SyXoZfwXD_!LW8FG{_E1>{&p28oF!IBLQ(gH->4lC}qaojz zI}v5Ao@l?DTSLb%%p#VS>HU1~lOBhZ>1Ve44X>!;POK=I z%DFt9UI?Z%i@UM?PG6-$B#4ZEa-!2x-IsmP82UcX@pJO7k>9La05ad_QU`-k%X@$} zRb_bWl$)~{d=t572HTEbY|zS>UFJ5ju1sd(Hjo62xUj|B&unD|@XSLWU>kx##g zUf8;-!-#J2Nu+7jEhvltc}}Cv6(TI|Zr{WFIUJd{-i9 z256OIM>UO!Um-1>Y|v;6KHxa&&ODT8a)X~IWBP1HNdmH1Pi4dCb_2)uhI$V;MW;z_c9`cF)jE4*=hs1I!T6?;n-R4Er5tQ8 z?-UoS1n`{HOVF<9HQ8-#M?ph!fxoj2jtyS~Ki zab)ppx&^KTQzzJb6py#WY({Q{?7H!@%wPo$W%_uW z*@o!(roCsW(;_57Ic0c?GzpSscq-IA4nlqBH!wj9+1eq0|M}nR#!Xt|g~|oc(?g3C znubZ)-K1%cPYmg$T2pT=mBm2vdOp>Da>z`o|-O#XQt3sz5Y-SUu-78=~@SA~LUCcLt9zBh<-!YEgJ_t^7L_u1m&;$t@~+p*LN zBAnN;^XY}tOw&W1#(12@4b9s*O4G_Jj;7i+zuF~7|BM<20(&Hz zb!%Q9&E(j_=gMq;8&u)xfN4-)wA*CF7x~$(Zo-w9-SEOtSr`vU0^hN#0o0_arF92y zN6W=Ma!%8Pod7f`?LjL&Jzul%``p!6*_x5=P3aH!qdE)a$7Q^)RfgGmpR#&y(1do> zf>8j7{LjZne|e5VJQ8!3wINC`C4{!zz(p0sxKv6JxSE{)vUri|PoQ%_G-+alfZpR} zn%~NE2E##XM1zzHT)qEfelq@ii&M@(uz_=f|M*@}5fKe6fH|(P$T~;!i_v-!XcYbG z3rzyoNjTsM0r3)6dV6w}B-$!~U%y=Pug0aOi2ID4U>nGK0U333e_Q;z@(>vt1pqw$ zOu*DJfRxebiX?S_$-=Bu6g0cBIl{i|qlxWZD1^=7V@Gu|4VUE^J@)FmiKPbkQ-Bt! zR9@G`h8Q9`G*lieu|d@=^@4C16W;sdSs_p4y^bxQpHl1Q5?&Rrmv%tR%hP#C+=9JK z7I-=o#s=?B_kpG;Xh61aj<-kPy`I8Sy!A4)Z|dx?jnDjYZm{o}9L=2Vf7_cKfj&`l zn1(j?fOKsw-0(^Ah+KE+?nku;8ZxOG_~FZJwE6l62gic^qw(N(Uw$=uo}a%P?e7Gl5x7Ew zf6-p3U%C4SuIV*KF^l?-J1`OL6eWIcU5f+KP%XEh-I8izXv1$|wFL?kRulM)PSoi8 z8fatxwksHPyjD!vL@@+`7l#sCBIJHVVf}yX9z>Eol&Wnfar*S>=T<3gkYqXToj-m0 z;+QgJseq+n3z0@RSd1L$uYi+pX#&i-*-uL6JGzfs;M&6pgYls*%>*W>JIlo>DpTYI zy2Rq4cpg81X;m?3cRDy$b|TuRi{U?W88?h3)_`JfCJo*_)CsLp>S+TEJC-O2k;^GD zTZ6R$FuMfzr2qO;WfE0@wsU$h2)1RJ+_!&V?G%R|70?cdY&0o|pjUJu(Dy>%7EtGn z9heAQO}pP!$PSgC)R7dkvOGOEj9q7A%sma+4sq2$%1^7}iSBscUNLh1-2oJEGEhAsYz>a_%Xz0( zanKXAkzhXK9Y9$-vU&|>&YGp%aPu;roXDCr8pOu~#)PI-gt*w+A018w19L2|K+7{H z`a&2eKg>&}JwlZ#z|9#5!7wwwdea|iPZWUk{ujI4Znec_6xLU}cgGlV*8)@nx8R|$ zeB(wvzEl`AVHwu*xWWMdsOkrZfwq?-9yID4a9 z<|wSqYO}Lw9b*=R8hEI3q&!K$l=8`X{eiBa$MsR;LjmqQ&I-J@1tI>BC1vAQCse^@ZzJQRHwbdK?)C;&jvPque@A%{Kw*so|U- z9AuTw!rOR-=M;rmTwKkJH@lQILsF4 z$Z6^vbZCo=y>j^nbw{}PtqIxD@TkoitX9$H`C_M#Vuw;PH0ZSV}< zW_bq^BJtih56}zZ7kdUN(0>hpF$1C{XwEdEHvk?(0=$5o_hbB#15T7cBSL|}(Oez6 zA`(A#E%Ky**UB8oiffst#GwN&po;6Qf|!W={1}6@C}M<+IFJ< z&}mhs^Q6pDMbX8*vQvhibsawfaxe~fyEJHt+bZDAc{P9XrmhR{cWb%-18Jj9hGQ(V z1xbS)f0paFhJa&O2L)AFDz^OD*Wrn4Y)GgKMvR1g@!sl~p^rzC-f}01$)a)djYT2x zI91zlY;$L`f_Ge{^I$to?H9c3rvW0s=-hgX6n6QTqH$NjW{d6WvaP>Y9@Q&>^K3^jWYC?u6 z8~4{Xu-TgeP~PqvT>uVz3gw6kY;%NF-k_fh_r%;!+V#hMT=EymYT7~A7HVVO+$#3A zQGU2G^Z=T|gPF&H%bYBwg_haZAOKYB4dV37I&TS}IjtHe_4ukG$W*T7lL{g2Iwo2p zq0I2v1aBB(3fzA5vv#(hV49-+^4Q0OXa7~99=U?t<8a9FJ3ye)KR!E<&5;M>5MyexV==w6VeQv+atoiff zKe;w-08J@fzDhrxO~)-=9NMktVctZg9}mMrUaQ7T49vhxf|B@7OmX}yJ$d-#VQgI3 zcQUko?)ARbnE1@|4p!b>pr6pUb@FZ526^{p}9&Bykp<(r7D* zz~qY8cOOm@7LG%Dx^v;eg^k%h);?cf^yBPkMQTS79|i^sp{Q&_a+D;Dkd@Wn8biyG zj4f3$3?AeF4*JVXwA`t1(Dk`lKg~A0r0%S`gfV0sh#xmP(%ZypkZ>j)bK5A3$`I_V ztDyO6g_RweI@giZngTYZ5`{2pw7*>SKLFiHSDt9R2_8NtY}t*YkHgpdCE~HE(;9Ym z0r}Oqtio4W%6({{Hb%-FAr7SeKgdSvcS{NQkJAS}MDj^9u|>@%ZBG>EJwGlse6%pw zIa2>)^}g%6DvbQ1 za9ChOARX6T-iF^5;G}Gq7V`2f=^2JVZzIH7NXO9VP3Mu$*VA=)k zB+Ed5^8=8C-5=lV#)zEAFW)3&ypG{dh|be4`vG$T@QSSo;U$DQ}~xI6&Fn4`~J!Vs;h?dP?AyUVW|K=)`J8ViaC4Vu!-o9M8J7GAV}e zW}6*&`$>>gLk3ODRIF$l;0NNX5MYBsG}ggxOJva^1(JCoNfcupYmJIPSrSUT3Rj2( zS40g;q`Hx=W_(0*;XYfivR{u+DAQA$cVY&1^Zbz~8hr{`kH)cM>4?MHHx;}y=>B0* zQH+yF%Bot%k0ycLhC>l?A&0K!^2N+XQ{GZ&0#W!!0qx?1fyih@8fzN<%pleJ=8dE8 z`PbgH#cqv3Xu;`n?Tr~0;&Y2@2QkFsvRl{f`PWilCeV#w(T4n0Q)~HNOc=)oeSi@t zEDac`c}ieppTv{R$Y(gEX?BM#-`rOuO5WGEd;Pdw9T}fC!^c1i*n-$hooY}|t>FO% zB}d%83K3dC$rkc$92z27wTJ)_C~sS^84d|W;+D*T3JE`x!$|aWxVVT;s)NA3Io;_K z=@Qin#%$&f(^BfNTQm$eJe&{kDilDWh@9t}(r%2bD%w17cb5@*TjN5$e^{n@9{GyC z=M}{cpJH!uB;6ux6DT-oUlS9EmDY^rWJ+!^VkZpemkI1vNLp}I&+vQ=Y~?mV%n~SJ zbcUpnIIo&<4z~gTA?gk^`J$5*kxDGA!U^2(VT8ds z>~OHcYAt=BlFcE8MG#cZDok7$3>x`ngvU~*T1>|5jbjYh!kLKNQRQjB%6gM(E=t>_6xj5<}wwV+Yc-G3Y}*#GL)NGJfKsK$iY1Sc89-+1hm3+ybHLtJr% zc^rBHf-$h(qrjb%T;X$@-n?I6SyCQm_!fgNeCuc&|I=$KOS!3yiE*@33B}_=*)aa|UoGYT^##du4CgMD7&54XHbl zfsy?jI0HFMo>@}fp+xAJRUxvPv}qn=ix@;EdOLUQuqaMr@a-&&pNB0{g8E3Ur2>Ek z(yj6qSIij>MSZw@<$ozDi3G8sMa)(BlPbtN?78gmJOaH{97$N{#LqOOVXVm7V}L;? z-4GBA*caKcNc<~v_%(%Q1I|=Ka|(4@y|IA6p23(ThOk6Ibj1pFXm3RTx>5Qkxmjxx>*h8F&eG6Kp~#)$ADU zyY1eCHETwyjVUHr?vdc%si|X`KYW*EFHQ_q0_}l+v94KqlX<;qeVZE=(zQ!xh`xcm8HKZ>PX{IV5BSJKaN`rdmVYBt7j7D5bA zB*o(mL$10VZ7ELGHeRxWh*VDeSw8dS3?SSgH8XR?rcE^yvuDhhan0z4U z?Q+79s4H_w4odhK3S&&_xwe<*S%C5?4BnR7`hTZ+3_QCpx?|DE{u?#>Q2^r#+VIfg z4&~+7-J#dnW7YK0J6SiGfNo1#RVdIMsw`8G`{e1lx0EdL_xDfpp>zc2nl!;k)Q^W^ z)B$U<^|0K)HQC01obTbl|195bwr{@Rh8z?k+5fKI{FOt~Ss=TV$^2JO437@t115_k znpodsC(d5LBEbMU#^05cAZskvgG*F=zN^#6iv4E}T#tEm+RG~_9|;bLxZq+RaJX{_ z=5YT`%tBwhI_Btb!k~XLK72R^I4559BhiY-VqexY$pFF;HRu)n zd9&jGyM>Cq>a^9dBmZ-#b^VIkEMnJuyKh)U{q0BG&ELXX(ev3e)4SrUR&}S=;9S_3 zY(tR;nGU5IQ1v8gmZGaW6F0Q1LTApL5tx^677nlLcKM6_y$nIjp(A3rOc$8w&j{>?2a7+RxF2o(wf(U<&Nf zB9TO;`|Jf~3*_2)10orR(tRK)={}PtOxO*v`7>uku>k9QoCs9aeC>h8W7FGs$hd@4 zpipcSzdy_lhAnDedRh~8_^Ic=nUKPirO{&fLgQBYw>C%2|Ujyx0h3UTuC zrAu=gHWOsPHrT%e>MICl4CV*D#PpEJ?SPrI@fZko0;5)GT#Z_2)7x4gDX1wBpv2mm zz=%D5tU!{OveF94~p~OzCye~CJWdN36bpav`Gf|%BKNze7uj;<{?< zQ`}%etyqI?IfE)lg0C<=y}a78df)DbJ`_Gzk~nnmBw)y-4@GdLe6Yyh!&(5GB_wPI zU5soa2B>IG-&1ia^i{8}-a;_IXL{|(Y{>DRRFk9>C6#UWYh6wl3Jp^n_QFkONjhcd zIv~ImqGT=bK+sApVbNm1&Nx!Iw}IygNuEE}pAoXUz(lo7f9^GuXaCjhK-#eP=^?1f z(2QG(vs)6$7P3d`D{FM4gBDNF1hN~d%slHC+~c)#_#=foi=0NIP~g7r6rZ&s;SApp zbyY~oHVDKr`l@I|pXJ-kH^wy{JfkI{?4b20X>X*T*WeB7D~RKTXyB{~|04e! z2tXI8OFcjtNGSb#%``;qQi;qGHPsN=BR_l1bb}zZ_H{WO! zrft$dk!f)B-I%pucHm*m;E-4ez5q@1;krk%G-2Va0j8r1Kx!(l1v<2-F4{NwkAz3* zY@NztHN&#GA01tSKc-|Wte^C<|VTeMu@E~C_wGAC?@ z^kd!8z{|0&OJN5S@~M`hxHI1Fq2{N>DE%;{$|ds%-Wx40!0|I@%%I+x^?=**ufok~ zyg<9xB%wQSzGiVqP=^ei=s2;m0~2AALxQ@-!r(TWD%?XjU}{uwDUW*)jm(jEA94vt zqC-kibVlSrmim5;BWNhnv7^0)$-=9d*|QF^uT5Y7TPqwgp;RuTMhxoAgy7Ibc}wGi zBSlGQ0=hV0Q2WAq=l#)xkBX*wq`yX=0gL2mF~@6RgxmrqOcUjyC#poEIS5lnmO^|+ zk^A6n)ZU^%@d@yUfOFGW9lCh1gt0v~!Jm$>J!}MEEdb>YNEt&q?5I4vx4P&^Vvv;i zoo(}vvtd|PjLM3{*RTv{Attb~jHTeQl!Sq|xnEBYNuGhix3si$e60GZ{cmw_KYDDI z^o2(T{}jr@ZQYX(HpiKHXJ@cZ%yDo~CUE~0TyyYjZDYeO=x#fm@8Z;ZVEU@nesg4Y z?hMDN!_ozYDp!i{vGhLzr-7@V`{y5U06g8%2@lrTDh-3H^1Hd69ijhN%gojI=IO>- zkA7n8fZ_ZKBJ2 zwDj_y>6FJ1w{yi>L%U25|25Uj?9X3m<*uFLFxk0(eT})ZP(Zz4OebsiM6R+z>z&QI z+-Ll_Y5H_?y%|i_h{QC$pX>U046e9V>gi8}0GUbS{qw_bn9(=+5u{?pCf^bRy|0Vq zX1FhF9>p%b9P`J^DHX!%>Kv-b=uKVTmN`^^gm>n=f+rvN`9~jlYIOFROyJ|dlt$C( z1@CQn$2Zj{Opb4JIUe8EUnn!Bt-J9nPw|3MEh&MQ$$XIsxx#;JqDUut zp&q)?F=k>9R*kaSX>`Q+;MU>I!?+HZj=`{YX4~=T6@f>P1dFYtU!ypaoo3n`Kj-Ho zV(5Y70gbF7GCu9{yqLeD(-=ubPo8W=<^&SU&eKkCYv-wvr<6LDHrT@`vl!!xb9wdi z23f^pQk}zf=dg%%eB$i8q>F16!u@W&3G~fsN6Zq9FXAnhuGq#id7Ge0^B-Tgl)f&s zu+&&epmG*ZQhfS;0r>C{Tn{wZF)OxU??{U6VZNB0B+L}`*>>uzVox(M`5M4xBxs@r zXX+oBS(vzIrBdH*wD3Q2pEPZl#$xnxMaiYxEw$)xhFbu8=hYYNAMN-M{ymrQe^U)a zW9%z#18eHe&h8%xKaA?1cMzU_xAB(776Ck)xSJAVH~qdQ7j7%w#|j0pBz^4Ia&5Ti z<4x#Yj*pLrfJR9F`5!k684{$sw#G4O6@z!%&BT)HCM*Gs}No#+>j|Vt9{rts>(yG0AcHnl&Y+ZNIc^jM9nRKe}4C>`JBC z-Y`z6${RB=5&rZkwmfywBNr?Ggo2C5*ju;E#1M4AjhixxfZyD@y_CbMaS z*PVn!*jstb&qd;~Vev4|!|mwWxLSTuzpk1Eja*O^$KI|~iYsr>QBxL4D<_c+_` zrsY(@bD%;<2muO_(9Zu3B_;;2#m~=|ivvMPnG;54T!8I&V!#L6k$YxvZ#i92N}#Th z{xS-ON;H*Ib3ld>+^@MJrDV&t2i;{}C=pmCppCm=eJ!$jb@3Y&+ZE^_M0<0x&>vUD zy?8U0;=+LYMk4%i7&=?hm$-&)w`Hp%pp96aBxPJ7h@lenOheG%Grnm)+JBMvQjc$& zLvW!zTCNX^KQbNxJ{XtDsl-E2q~`wi@W-oWCat_bW>2(+bhAd!E=14mfHUbtwyk$_ zbAt$qfUpluP0JGBP?>0k9x1buuzz;HZiP9FEGG;S$!27ZW^XgoAZS{3>BWbS;blT2 z@6h8My~9w!XtTY{ab)jC2?2FLebsoJY&;4oo=F z0z}s8?B5-Masj`z9_X&btT}U5uppsvw39>YM~!n+aCdfY|A=gsp@zba!H`i)4^)9r zogJ;9qB&FFVj;z{)yNlSR}ljRnnLrP9`-#ZkY?;GzZ4JeI3eP=?z(*M`wN^l;dMI%(NcGp~VOWXLd0yrH zfI*4j5|xlp=aj}9%8}#+>GZuICzQwZdw8o2aS6~A0MFAPi5Ny1l6ljHiD~wzp$Pjy zeE|3=4A@=bW5-<(ZXjL4T=h043rw~)l5oK4=HZHLWBpzu zwCnc()xB}NXD?BQ97!~mEbh|)SV8?|fFD;kHZ?YyAq}s*Z|sd388JW{Dr#JSChFYV zccP{OTT2pNkCqkp9`WVic9u&@vbAC~=evKmNi&lIW<)(OB#MPGWet=&I$6h(5Syu0 z2pRY;t|$VPqxQGW)PsnJoIIfjK1)zlv#=bGz5i!fbmp1F-@B@G2EvT|DXsD{J+?^m z0T&q+DS^;_WiLrL^ulS$6j?~;*VY>1ZG*LVg~dL%Fdr8HV}%FDy3L%A9cu-0NVG8W z&86Hz`o^)=6-I*)iI|=?ptgDHlmjY9P0gq$L7Uu#zj5u=9P~_O6z5Z4AEchNKe=Go z;y%vBi~BRPiA;5T6aeKp;s2a4SeLU((87NkRL=9NDqZ*_Dvi0`$~Gekdg?KWYddrx zSAp^@idGnI7EelSjw^MCqpeMU=A7SKJ7^27`Owm^KyREs=;L2vXlR&Gf4)(7K9caY{%%i4w!F@xequ>RY(Z}5gn4$43;J5|0US^IEl*8{Y=5>-wbB8eu5C0+tw zwE9Sj-hL3B%UFb;(!$P1vVixqt`W}0v#Wl!;4xnuT!Rgxibin`)1jl9S_U0g`Jy26 zX$LY=84EpUmeTS&_6~xVUL3RtDmVn$lL(9lIZmB&koj4iHo!O;S_v!-d3g`?6ntoD z+1nu1dg=BHk^`2b9vPhlp-ArY@ygB5yfTzj(3Hg4)z>I(r%RXctFqAYpfn+-Y> z-(ZAPfKVIoO_Y!XPJ;_UBrWXd!mKBGNsmwHiAeDsv}{A3s+(1<3j8 zN*VmxQ?RkCSF52Zf1QpZu#B4}=B2+0YmZ7LyvMp(7B?@qvh5N)weqy=RtOzUD3HU7 zkZ?kcg)Q8AG1mCv8;jR~xf>c9mWam({y1BS{wNAB6jUW%Lp=SXWtY1KG@2h94d8@< z!!OqjfHqLw{p-+@sdOmuO~tNVy8@U9yt-I^4}#k8Rj`)zYFiUj;P~zeATyxETXWrj z_dodxy05hpV+qnpU)k!r?yVXGYTz(cf#cM;p(%^X=1$>m&yjR7G;WHk4fQ=V2+s}e zfIs1S7k+CA05^pO3bH_tMP`;-JN?Xub|OMA6sVF-zTh3%I4YG_w-a!bm>C+hU?<=J zFAv=13U~%!t5f}tg#|wg70`L=5Q}Df|M4R~>60wP8E$Ybsq!V`4}{5vlj1N~l}d)O zFA@19fG3)gEC>KA&aM@;0C~R9pS_2?X{@cS!{ZBHKVA-i5%Tqmetv$GT_C!>urhcv z%Ul|v9UoE(*Yv^97XW-XdLT`@nqLxG%WQeEETj}lT?z!~esOkjfiQXb%9VF>_utZ0 z9LdVn%K5TWubmSXW<(ms^-0Z!BrE09&dD=H&Gxb#cNi;(CEMkX)mI*8GPqy{WZXkrwXUSiP+2K3R_E(9SD zGQB;p8Tqt?HF;yF2OUnpDNTVnP($L>y9uCQPcd5%7A11&XaueqRoeRmriR=GT0-|g zKdVC{a<|82uYgGZwK6;wF|oqm`K#ncUc>6`fW6YjRWZ~q{_GCPILNqzOx1X+m`GV% zI1(mtKUClD8E| zJG!uvAeH~M^#GgTRJxRtlY{RnL#Hc-+cyKHVq-m1Ja9%N>!pSUFpZ%=Voeb3NoWn} zIJrKsN)R}S4e&BgLOUxp1{YqBLJBGh@)X0?e>MhVf2@9em(yws6@p_q+7E)6rodMy z<0KT8_wdP6r+h`E0g{z~d2@iW7!DM==(Z%R+$NYhL!djMHhLIf=hs9?YtB0Q&)Ksk zt2JNz%*GjvxKnlBLKx>q5X;A03;(~sBlsjl3o|Q(muqXQis+O+SaLyBt4RKd@j!pt z%#@PW$UD99t>zmcU9naB_Vf+U)j+o0we=3sFH0gVwm)^;w5^Gok$)qRDS~>HFP^F? z_|I0TZ%FY#Cx+#zJRP_j=r6AK6kxeaNACacD~p!86^{kwh3j6s(+s<-&9VfudE~ei*PM z;otxuNs&a$nUG1WfNpRj6=N*$BHEaJ3L`tTZY7qZe2Z5_iiYsuq4_eY^`p-PP3kRW z8%=C2RoWA_wEDAM^U7p3@Ajhmnzt;f9Ok(tjM1{t+=CK2a)(sF{q}RphD9%BAxOCy zIH8yUu1plU&M&GA8>kFWp;-vQmPRgUI9Fqp>SrE;5O~+b0;B5snqmNfcx}62)!|&0@iO##sVdH8bYIn^N^I1 zjjWQ(66^&yqckTx6W)#e(%u+{It5d(b)bP`u8@#OsO~0S0k1*ERov{{NC1EMW+R|Y z@8B%H!%>kOWz|zl9By`V)Uv>Gj<308;V3XYOL=&uzP*z`{i}-+uC&ZkC|O{ zYB%E6a#D4nrq)DcO)FM$pw=C@2LR;nhmHpiK?M=b1g+yR9?EzkuX3DnWu&}ID77{) z@Nar;XJ?lL4HPtndPq}^Py-Y%vFo31fv>9g)Tx?D=Kg>d#|vtupq>Ecvd>*ZPBWjXH#~=TslY!$jW-% zd?aWM@7~=+YM1e;c7#A;6e@H+RV_W_IhNtO8|u{0y8YPYnu9&+s?li}w4w>R%yzbY zLVJLf*Zv95;K^Q+%*W8X8XNu+pmTffNPivUx^JEL1USjq_Dq92CYBdSMS?3)!NCOh zKyT=Mv;bN>x{OVYikXqRS+_3S-b8(grY#ALaZXm5nv-h)edMvmPdzLdpP7_BkW0H#E3F?8O9Sh44iP~qsx^x&~CvY7qs;d4>G>XW$tY8S9 zg^Kz4Pt=I3xx{%Lbq-d0YA?er}bq`06E5CvQ6Q>li+x#~wJkg{RCXWt| zPqB(7p5GR9e=>@#alIGA`udK#4Wjd%`$?U2QvBhn=Wxk`pcxW?aFQC}c(Cu`cqseF zE$s&1t_av=&&pZf`ujBs#xMj=KurlzYJia6*|Tb3DR;jf{xW&hsjfDoks5t}9qX+O z!)!P#Fk6s56dL@c7G9F`W(b1IJRnM>O29GYJH*2fT>3lLKZCY&>j_AVecDld$~vri zSP+QujW^db9P(c8JPb}kNoqyuNDC?2%zWx5sF4Smq|Vdr8VKFN>B0<#-icKoHPRoK zQv01P<_8>?0(T*zTDI`_FXejBU!=mcW)S+7#s_G2skzdT#Um;>55D!25L#5 z9nQY-$H6~m;rD> z@Z9^Na1rX-AeK!GD$ zbG)|(#uVC+apo1cz{7&8RfMpaN=VX(LZLtV8S=^~teS#~9OOAT?l_2(N7-jYKKFG!;jFmSPB5T|iEwBMJZAP2+hD=3vGa|NPx^cbRk*~uZ# zNmR(9Xxf0RDXOb`G()ebfbF!9t|RW-KPWf(eCLx0*j`3=*`FT#<8 zl*^nhtUF@zlsccjdX-rHJwCf%8GbwJfI%c?O`m=n+JjcqHk3i-2Y&cs5sd~wxR#^Fwnx5WWP#c^w@2tm=1qi{ ziVBD;Kl!%fB$S<)jlmy6@v)GA&Xxn^gI?d2F=b{x5F!0h?&s-G=sx9jnPD|H*5}tt zWO&5f{&-U8-kz0(2BVa9`Z2Ilg#)lG0+&{)DYl|YYdM-nhdvGckXt7sZ>u}X^_^#MZ|)Cvh$?$y}iYH-M%dh8pjsc3ZQ9LLN&((^G};0N~# zT%6tFE_|0HOwyo~s!k-XhGd|eFl5<+HwADq zliMC>zuYX;qtTzOMl(olu1Hc9;8T)lvl+it9MuvM8{!$^*uj@Ie7}qc>=ZUlvLx3# zp@mnl7Dx#fm&bZ@PMoj?-_REjO48DW0mi?5v3*e3wm@T%yx}lf2Q*l#8;-aS1QCyp zWXv4sfCj5O0PSE8uhtSDxu#<+auI?x$tngyci+1I&_H$g`dTQ^V6ff{sHP0KM?C$O z4z#>%4W2{Tjhrw7%q*l;I4BDCbZq*^+k5R>KfH!$P_4PV*zcm&HK|_6=dVkwEkf&z|T9j24f&E1LNaUH^~o-%U4Z<=x3~~0d1@hLX~3fsnq4shOp)wq!qlG&u3Evo(YPUv~K7wrIIa8(&@D44t?AH3q{l#E zl`{AsIVRdR*vHTc3VDcb)9(kn%T@+--g;8*{ zF{r5`=}4^stj+@PjEPoiy*EbH0{y{VfOFfRzSM#o0*+G2w!ImIA`GHEM-uY?AMXWn zE(8Pw5HK@0F=_Xgt}e-32*26y%=sbmf|7xhLm3_EDp1IWkhY$RQv4*i2~x8#SD>7Z z)TnQ7kA=Lb8P=ET_&ca~e9Q|G0BMwVhF`nGk*Z`>YRAHPBW3gcU$e|AhDW-5#V?Bs zP*e7x6UX6Hq8iwUW(-oN!@R=oo}Mef$^raHXh9QaQH1VP;Js>C&d`GxIdzbSP-4iB zyVbIC)ImUJ0$dbIATl`Ug!8}-U@zNhUM+e%JmZ^yl1M6uhF7ii@5cT!nB^T_{R4HK z39k`zg^bJ|oY-PcgV-|E0}nGCEn*%3bV6l#aBdOEKG^V4uMpI=`Y8Qo#*Ja9tu6aQ zMGI>eSl6dUmQ0R0xDY%friz+R*U-7nsmh&gs=dKfyO|ewa0(hNi3K1MmI!|lSR0SZtqvoBp?EfQ40B~boxz}j5E&9A%`60V ze~q%1AK0ZF02~r;F`d(>DnDNZuQDF#qJ86kbI3v$P_L-dsw&yHZ{KRL!u_8KyX>HT zdBg+^t!U8%~5m~wN@{5BSP$xyZ%E9L%29(J0 zp&z{j2v0fdSz%_CvX@P6}R)!kbk^%AL@0d?vUI)Enk(r{)S72Nap$5E|9~toZrw9 z*){0&);U5Lf>@FAz5RjIL7vo91(c?6|GtQoKsi_GrKW2B@7c`9)~U_JlxkE_s_2`VeYOk5<2 z*XUA6h+%A7g-90LDLZCuP(k44d#W5h!x)kb%3F2- zFm*tE`Rilt42RbB?>~Kt2VMhJyk^_}g8&e?X_|k`qS2*ey`LU)ifI%oTw1VuLdCQC7{(1EuqS642pjKdJ2r3wsS~82ZI-KRW++gC%z{! zV0a;TOL}-j57>!Se#t@Vb=UTDQMsjVSzA;dEl_s z6cO?g6Ieby>$|VIZ`wqEJh9%RKLAGvPW~9&HX!rBC-Lg2kx)qn!%P9>&7?(Li&((G zb9?f|bIAN|%(!s@6S5+i%vY5DJD2GnBB3v;mH3|Th*8z0T<+5xTr5<7lwwK1tUlk< z0Il6@)29L0kfP$^@mjBk1G&eB(D&ZnX3Hlh2__<27bH>!AgGgn6RFw}xi6rc0ajrw z9fZ|kVqwv~TiL6PQ5v6Hk{2nmdGqEq*LEO90kEl?Ru6kf5?zrgH0k6ZxW&3G0}}P2 zz1{M^e5mgcSfwm0CBOCc$z+xzI>Xa04y=Tzj7-IBaWOH(jEo1a-)!Lz322a}h#W)y zENUU!hs?1B1K+ffTyrxuBGSOR?qBx_=sJPRz@_u_jbP0{Fcn&`H;oxPwiPs#n1J;~ zZetX2S!nHrQ-MA7hguaK#1J6s8=-R3#FP34KeA zUC|~2NSUVaRKxR#|8jie&yvbQ;08-s8PYEf#x8aJJAD`18S`v@eyV3uU1&b7*LXm+ zt(61@2CkoL8^UJ5GT?B+b9|kjmi?s@s^L^emSwen>>6TOvpy}O&eUGt}wB@lsUu| zlg%FvHOiqx>evw)`RHx)E%rtRfK#iC7&5effjvbj#T68B@7JUltKuGTjQTBmp}s}2 z9Gt~uSpD}}NAbb>QLQuZzMDvmrXgCXk;xz3Gq&yu5_cIF ze)&^dD#9BrR(T^wgB=o1J#mEBkK10MIoS-W?HG;~-vlJu&AZ?*1&yuox?a@Ea2iK(rR(3=bT-oHOHaSq{Vx8LW3%z^92 zmIeVv8CsN$%NzL~#zt9*-bO?k72|(zj3JrfqLdXu217o;5M_`L4UD=WS|{re9E>#Q z#Q{`36b?Ch12@R;fcoNV$N&^J2l`@twooA%ZGh$;-ebj0A?|TVt+=;`1>TWb|5t|H z|0Ff~7W-@7jU&=Q#D}82ugbS5M9vUL4l!mJ_7scbeLLrd>lYUBTQqwLlW$T|Qo!WF z7R+q!(qSm-p?;_MJFADYY!fyeyxl(4BS>Ak>v8X2p@$+nG%_q=&r|&K@bEAT>4jgZ z$>8^I8mzWZ+-ox$xFyc}2}&tLM~r|-t+7;B1C%f%BZWM+`Wx^{)cFMdiG8dHdNE3E zIaKBlmWY6gJS_xLA~B3Ez~w#%b%b+DP{umcri11S;8bgaT0e`~a$=mY+P;0E4f?Ybbyv&}gW=mPo&s)s`uWG= zAOn>0rwJb%y*$QVbG#62`qp{fQ>jVN6pcEM5`xqdNY;0&sa;^U5T1ys9n=BI!jaWa z6FShtO5!3|GvQn(PyvV}>d?(VD)WIK!y-Wol^VjgB9dHXqT{^0yliri1Gj-DU2oUu zLyrbbHg#YirulOlAP~!JQ?+nTfWK_Vp92iI=TQba% zY479^zecGmq0A@OLLH^VH9j^)QBSU<WilKxFSr#aJ0WMrt9<>lZR7T(&`d_aV9D=A$iSwbMAsi?YI5d{Vi{9K? zSjJFF;nw$V98J)`fh5)O3YA?AKrbB__tR_vgk*poFRjkMu^>^LB>dSC47PKwi0M;n zjv4a8FP}fZ9Qs}~)C~0dit=W;|0OIXKV+3ZKZ0RO^IUBp8C`8#T*%A#TWWl0CALWp zwO0d)fs+bZxFZpuF4d%>Pp=~U60&USl>k(}LW4GP*7Y0Lq1widA;)aY03aU+NRcvR zmtKmhuI>K+iE13aA8RO?tM{}peDc^Xkx_ZVJv{z!iiS$$c4M=7z_>2?GQJEMZJd)! zSlDZ+Eq2S`-woxMI@VZ&f_NF^dy}abk}w?vYQne32MSOfZDKIj9jl8E;M|%nWm@v# z&L`b|SKTpJ@1s;eQ6Em23H8vUUp_N)?odTXOG^}izZi)zYzl3{9#|NvbIjk#CW*aVK7MB&Um;=t!6k; zW-yGoKOp9PZ{*8`(O>Em!>PqSapSt9dWPsniKb`wNO=*)RU(*s>WpZ)yETXJRK zR(KU^Q%8t1Mrbzo0hTF?weDg%fmL_qO8C|JG13 ztT7oCD*wOnZ+~k$8G5^nhEkmAni6H4k1Q(dMEbhAL#R5KQF*Omctf*({#c|7k)cC2xZY4< zdTswg!eIn||AR|ARG;V}Fa+8G_h``0d#`bKYr~|qgXNbPfLmM)U~~JT>mEVBTM`(dW_0(dEWC965zi3_9*)z$j$Dc-FE;h) zi4A=G{861Q3x?l*A+~Z z&4=Mv2A#y+UWbuwm`bC%Jd|SB?+-v?iWcNi;;Bo1KQ4wDg#h{6Sj(l$M&U+(eH^^7 zHbY;A`cG}0{>Me6qgC;FFSNgj4xxG;$*Ry z#c-yG>U|cAGh(JNCgY@qe|4_Y@8z2xn*I6O$oq|S$Dwk4RmIeK^YmlKeRhbFRuDFx z+V8Pev*%k(;o-IL3D50~^DS0wk&?dRD8f6rZlWvfj(>fwd)0Xd!DLGV9@I5kr4<%g z&-C|{R<2*Gn~*-fM)F_A#G9jKCWLGn{_~6`%n~~TH{p)Xg+Z$<CF+}ro@_cQ$Kq`1``i{|h+;kY+C%VmXl#+Q1wYK7UHsr;_9lf{zA zKBKJdaSa#}LR|Iz{s|{W%S;cE8~MfZt({MO|5jA=pOE$M)2C%Gvh*5m2FKhTZM}`W zaI()3=ZgwL`eD z3caUb6;=*p8jN0a3eZ%@`kQXxTz1c|o4&>)rY@1le(tBv4Mp4uoGat!Kjx8FMc|lS ztBtrFtf6>LO9>%xB#tqv1prML;jGbG!cg1&Kd4~ZVp}Khj82`l*>CuJ869-l0M>1Q zY1ZADBIY4V@07+XK3lwK5ntfQPEF;(f-c?;yt33(C@ETJ4phe5my{j$=>M$@V}$Ns z*!TVrcYAt_Z3gm1UPUCOMhn7MjX3B;~{!BnJGm-d?m;moMX? z{~rNvk~&ssVnE#*L{{JJAV0|+%pmL7i~P2s?C(L6rUxvVK75${NFeCr$B)PKm$g2N zO_sgoKUHte9~&?ik{+R(1yil)>f@-Tnat=wH~D@B3T{+omLyn(V&@W*T+?o7kJnao z5J*jr#wn;YvYZ8RuthqMhXWZG!HA?49jyK+Hb}e!>R7$BbtqxG#W%sdb^OGMY^be? zIUt+l>P+|^wSb6E+_-5|@co_JL)-_`5^5j{%`gH#kn0GL!q-x_o9pPDFQ}elQL8Hw zy;Kt?;c31)i{EQY-iZA&@nSBdHC8Wx+(aND2Ck&F{u7YeQY31)TyU>^5^(J$Xjd)+`+itFw79+5F#Pl}OSF`UZYzG(L z)^!7jbpRT$p42`6e-`R^makm7k_{1Z+ra_|VqVh7DEII6^ZRRuei)J+I+d*8cl;l5 zboW-lor6r9GA2~oJsj2oBw#gFwCl!dMKQY$xa_ht;*^5f2+BTUNs1iEbYWe3h}ZV| zJM7ReU!vcpMI{x7lURQlGI zbQoRGlq*2&`2dREUB|byP?H5UW_RpCy$(o6bYgaOUL{-Og%N}roG{Wglh+}Qo7K~^ zSXTt3WQ-?!Y2W+EGE(PE{g4LC9Ciz#sD?q0*1U7E0oivPY8d)h`FMyfMxqKpH}!3iul~P~=8Q5(uxaad1H=jTpIb;Sg=5zY_QP8!i>`E<^b?gG5*zM z0KUhPT0e*vI@S^%@G2rvwt^a{3Rf!UA z7(hj~6?nk+f`(u!NzXP#2wgcRY286zNlF_{z|Dl#h-ddHaA@oz{oU#T8xZ0J!5g%J zy5&~Dhk|4ocuXpQ@GjPT*Zq+(s?+^<_KEa6)p5?KF6H|Qg&07;L8g}`w(#SBWV#xK|bEyyXIA%_9!q5(4 z0>O(0tIr%0i2x~Zr~wLx%M+`Qc#y*tFCowCy2O65?dg~I(kH3(uI5#mb#eI)!GruU%gttli|&}6+&A{Q%7S-{ zlaemeM=x|9x*B&sCS&@2C+#oauGfEl{pqc4w|!ar_z!N*H+oh-MoV??mwo{KYxX}r z&3v(QL;GcjUY3JpGk{b{ZSP%_6tIWLujmbA}X&-qZgdsl(`_h;@0LAre_jo7T| z_QP8&J#wyADs1L$|DC$+U_`KE9`KJ#Vfm>yfVg~sYN`m|&tc+wO+eh-*!b0eyRQD>xoscOU$g_WqnG zrzdpRvzLnb{d*s^?yUP+-FO)9FP)lSfH?qHnQyEz+Gjae!^%F8nTAM|XO3jhhQ>nJ zmR~?`{WRLA5zX z?Zc-)|Ei&4Zogq-mKXFmR=otyHsW$m`DNwk`-IDC`3g< zk&&PRVjxL|R%yFM5sOfQB$XgZf&|IfK13)41OWvFQA#pu5fnt2eG7{2-g0b?=CJ_y=xmLlkU}& zV+RSABZzXqM7R@mhhz^m&7u}#{4-&)Rk7UH2jFc>e_vMR4F@_HA8jxju31-`8n%c%t&j={@Fy`8+5}Js-ApB@2*FJ za-Gqa@>1@^#cjcc^d!$FGb@V?w{!?98kWEjBrt_Bb#tRt#@ZH#q9Hpff<}y7+I*=D zbXRImd$NeeP(-I;_MQqIJ!75o0&h?+&i16*LtE~=#)HaODEnq723&3uTVIQIDoJFE77Gy(hB{z86|W+gtHVSdBY zFZv{6UnrAjjtK>CTc}Qpy!a(_3PKE-%lmho=VW# zkeHPv4T*3yq`W4|@%RUlHB)jOF@^cn7%p*-Gmb+jVqMHH@4r0{V`uXn2SYK)JGZ53 zV-nb&pnX!Y9oDwCEcoK6%o~awrpb?{-Bhz)TtLLrol`cdH15NERxidA z9Yjrz+`03Qe_CM~;nYx$IgA02%1V(#jesS}!e4F+Ik<9vz9{ydAP=8!hM(5TJ0A|c zAbX$~O~53f=IVt7k?X#Hj{`}yJX#o4z#wp-y^Tpp5ycX)FiqknLadN#PjoZPOUYgS z?hyn~4zOk)qc1HoI5j7bf%Z*SsLPY<2zTJXEu2WnYN$XBpV4^k*+*@EguD0WhDund z5#xJposzt?v~(^!Q7r}}dZ7GU6Eiw8u`KH2Vb*S}Ziie4E|X+pZxyO=V~KN7$Qq z{}>{sh`b3M#cnk;G=w`;$-Oqaw2*tlkg1j<%yIx>*nvyeY&x(sIJ-{y=Y*J-jGx{X2yaqCaX_E6Jw!2KSA zd52Cu9Luadrr0`Cbzz69RIJ!82plUn-%w=0ek=N_-YM`#e3OeF{24g;CvV$jQ=ucR zYiJ08Wl$hbju@%f(PX#4mbGyf^>?03rQyPick^j|3GtB?aF=>79t%-P*QYO!u<_7K z?})$L$6M$WWr?eIMd-^xiMZ_gk!J^X_={eb4O4P=M&E$fr?cvH<uDQaHE{4^W{H?$n@fedbIRarUsABIoTCdeinTQW^UUpCv`* zpo&qUb?l>T{*T;7BZucPg>{wSWLa$?Sl)uMBIe)f0%gDaV2gW~<8m{euC|SVp=$l! z^0l_9DeRuVd}4FsDn*xb=s^DTY90WC<^`)H1(A(m&JF2uO*YdA(|d%;IgePp3Rh?R z#p8SL!^0zQK(n6&Db4nTj?@_4@uSFPL$ZIExOH@=y@pX*Yj2Sc2kHJcwuIBrvqaS9R|=V5Avv2G$ z_Lb8wg+aXq168k2+_sbS`1ZLsvrdylc)@~b$!E_g1}EJDmDV#ENf z%)Qo{@I+0Fr6%MZ4emyul+T z@ySC38SMF{-&AE@nO#x@>cg(u9vfwakEuF-MIc1B#bxsf6PM$zt%xcekmQ~${xM8r zcwi{X^Hi^)BtwyzP4)ux)V8)+E&Dv9KUY-B0}-yd{o1Nk=c)YhIWnZd51 z9bCV>-Ksf=sc$a+WeDqdkxNG7?w#C zvEO;uKByy~BUX$;X*U~NN3=M{`qR>ZzYcqBf~$7Vy;RLGIgplU7+ylVbL60>r)PI} zx2}!dWZ;tQW`je1oz#d+OP)V}Uf8W>luoZihYQw?lh4EI?+rN;h|&tcU?|3J zWMlKf{aX>ci!?V1D2UNlYU9ootuyj^1=Fj1F-?B$gO?w;ddz5e|)o5{Hx=2{G0*dx9vgalS z4^L!1t9ChVg7APW0Qxb!^~y#x#)2(kl7VIEk-#uq=NGEgdMSBfCnE?uj1aueYNFQU zK;dJE+bh~Gw+y~jbz183d;LBO3yZL@Fvf6e7aAN6J5oWn2|JFte{31PP)VUA8|2xJ zr{%TwEc006q2HI4osGHcBZtVEjsdHxR$F5iB;fpNW7J6H$&l?Ob=+ka;g^D!CF^LL zoUVq|X$pyP zs6eom@v1E2n{I>C?83izw4qW;&znVV5vq4;>Vzms8(Kw0Ql372dOE$7fBwS4<@0Yl0Q05we*V4dGRH-0`4MGYzBS*+?VN(cz@{> z&~WNhFIz#0Hk6;5!B*4!OObYHNC>~|%HP@Mn4qC#JhM=Ha%Zo|Gv#GrEtuyy&#^$R zPfa?l0ArV}uc%Se=^Dq5)v1=5@oI1f#rlWvX}+VQqnty}LPA28`|Xz%_}xlNgrC)% zm6fGrFkk5~?-On6l_T^Ra{OgaaL>wf0W*y~`TR<+t(M*a!DFw?pw_nKwQt^p z!JWJNw+WmvklnRw&`f8K^lE7vZP(^o_v%?!uJ2O+9wj?| zdJ?aXHkeza{a0RI9$9ph-m|md8+IW|qP~7|wevt_? z3?KW+Md|hYgZi&VSgVWlwcqW{Vd_Nj_C=CBKH?b6Ce|S?Jzb*9QL1>k&-Uf>-nP`3 zga!O*cF>6)c4kWwqvc$L7k%OSY;Wo%6kL9cZT(*RDKG6wx9$0v;=ZaIK}H!ROi`32 zoGst9V&z-Y`d#V@P!O*-dj{P#kv(8?bVh`bYm1F*s?8Xo^2f-Z9%W(P%s6*yx1T)>~ErGcq@&?07sYB)r%MR+h3E%a*ZZ^}8#@i6}5%1V<+%nh^oi3it5lNM!( z)61#76onopJZylHw-uy)VGwVnM8a?s2PJs`cA5)V+UOP5r%!YD>DT#FTfRgET+klz zX>y#ViSKX=nEn(c9P7>*>-k+UF7)FG9t}h%eHH0{@o)XCWojA)PZX@XY|=Ss3zNV6 z!n+4fq zHcfu4nGTU8uzu%VSF*=NaZ1{B6R+qF+(n7jB=Mj=&-d?56aIK3{XA~k>=z!Mx#ts+ zZTL;M9dskaGkrGiraBAB5>59%tND)W*)xZCc}JA+*XdbKiHLD2Nz%Nx-Zx3|{2Y5^ zn+WH`R!Y*A>0f){*FX8xv)<1(VUX~SD*jS(~3-6oK=7DE7 z3vPV%>J|>#{(s~s^`O3ebV8=rpb1w*XNw@kJ+h5_IxN8Sr<;vncbElFlnPy=}Q$-fRm0^vZP}#Fd!v%onAT zJjuf83ri!tRR`sHA6WAKR}cMCnBe^_+xn>hM!LF|nuXRkGz>fbLQ6ifO^vw2Fvbm+bNwc!W>#RXy(8x>JnbPk3-7 z|KX-tDl7+)K(nQ^q=7&0GO9j=!!YurB1j{A_jx(p@izXP zV>*ZDI81I&pO!yTz? zEh3Ux`=TQ6kDl)CyaL^_PXTZZ#IGThFxkFQj<LjfK^2Ho+U6JzyK_Oi%b*hPDGPY9Ukur$`)}MkXX_@#m){NlA^AknP#>RxyRN2+D>07X6VZ2#mioh#goBN6KuX4k`Nm_+3^POVyeXQa> z(1Mq_&2Tfo9WgbvBf5AGKY8v&ah=LPH=DU8q@)>HW?YyM><YALn)h*-!XE5ZH z#EByaprQm_`?4DCpG!Bk6O?k_Vx=HJszZ*U$+K~g@Gy+pC3v9(ML5u3T;w5Y1;r5W z^>j(n)lg`02IA&&u^!LSu}_V^mHCUuW(m4NI;yATI~asulPs9z;9XuKU9$`;OHZfw zb}i+6ni&7|8pAU(NUAeO<=b9l{V(c-(wAc>SFpzyKhw$;NLV${Ak4g#i^w}~f42(( zGRMHsuvtAhh%eScHi6;)JF|cI0N2Sx`ytOAbVUE#Gy{q5KdmG!p9Kg~5kV73svYAu zsm_>iwiZ&!5!9UCLa>?>PqUOjfMtn_SSkY%d4joV**i#W4>7a+-}zEY?r;m$3%m+*)-rHN&yg}iC_AzC{C}2kQ`pm>2$YPr`*BKUEe^^- zIQ`?QXRN;%Nm&6o1P-Sk6aqTiqMj7Uml_xMao>T}yeNxO=&QR>!u07*W~tm#1vl)nG^M*Y{|ziuOfl|saiMj)%CwxA!s5t_|J3Fe|W z9ATP0kcXjjv5wBzDB6nS&kiVSefb82^{~9tMOWmc{BDZ%sRQdna2ls~YpUS4zwPT& zTPHND4Uos#qy1P%G3J;%fYtzQVpasesN<^egU+@c?!~@NZ|N-rB_XgQpKXM~qo9l8 z0t$~SZ_B0@7|)YU?_Mck{+nyei)8(W#9G$z3IQEypMBYhhodG6V+bBOeB?i#+~ z>}%9)1`1-__YG(c9+kQkp$1eOOtbOb)$)Hx%3}dLNc2f&zZMK*O*?>}CDRSpIf*o1Q0+)*XZy(`H) z&;9)im4VtGWkAC8&H>D!_AUqZ#02nnD1M}xLRs%e{cW$d6~VAjRDqyX^+uG6x7UN* zk73|xlwSizen`HH5PCjpmgpKovdWMIfBzu@ z&$7Q-94D2e1Szb76575&|D+Xo5^FoVLyR$ulQwG41)EY1y!wdpII5Vv_V)=C;;X3f zIQ?JAOvT>e+$gN?8;^nKay`ipIhWRtZNTcEB~?_u4IIqqi_Og)+1HxNz=3TCrdjdJ z*6;ujP}!_;JT+NVjXd4-MB^>K@;T~nCBaSD$KUQ(1QsOMc6nJwy{@4ZPEXa0Icw9N zRom*TBn3Yf*)zGjqgN00bj_q^k@WDe{A@G%#Ds+MuSH)A3&1bu0tp@{{NyQ4@WqczzN4Ch5@uXYpmGV`E{&$D~wVIdG5eOx1}PaVdI2VBZZYh;rL)*vuxMS?2fbE z-wicU>?GE939243Cjsll9%IeLKMc{DtN-c{5YMeBjPxjN0&x)vQs|Mn9S+g+wBt|6 zM(G6~U>xbKZ`0EW?5G^$tKSN8Ss)xL6|kTaVS?m(($c;(IwR04ej z?Gq;$`nE97Y804Z^0vFyKO&_j{8qX|v3%iU?Q_{dD zjH{Ht_l`wP40z|w-WD>f)ZL2`Oz{gXt0XNC0)Q{Lx=6`3B}=#TOKbqGY)Gq&2^cTF zfB=D9EN*|N6(Mp#3>l3VfTIorSSO1NfNde~Kfc|GxqbUj3G#V3L#(zS0>I!Ny$G6u z$e+6gcbF&*Jqg@?m6DqyvtNafWN=Sp3u5Hd)~ykaS|hH3Tqq43=Jl%%s73O>TEoH@ zhNEn(;BK~m$k4+n(Vp20xY9~=Z^?VxZ>N6zuYMr9@^YY&1BaK$q7u@P(GH+o_`*iQ z&4O9Y_ULzrBHY5!{_Yp9muo?1+#(za)&Awt16BZ6NBS=m-zGdNaZ-%afJWILWZyd0 z2@<#-mXthmf&dd>f006O04NGE9RXBXv#^Cjv$L~LgL=sAyz56GW^z_Xni`8j1mysY zNC6V!$eE5*=v6e^+1Zh+T87mPsku-C7;M z;5bB6@EQc56gtUpMhV>mu6eih;(8JX=%<?*9&8y8AwI}WP-inm?X(|ps6$qF^w36XQ#Rc+_!{1ihLiNDV$68D|0`N9C)N1XHja{_SRWPzgAuu z05GRB0tHzeFct)$4!thZv<+~~2-pc`<{S~!VBX}o!c3ne`_I0{9IY4SK&}p;3_-~o z#y`)qH6$~;O00N{W3NQk;~^;OSV$8JLIhDW=S2`(Xc+_r^76@Jk{@+6YQ}Z3nz^h! zz+uh@AbZ?hhsc-pR?`bHonYVbm@11uiIL=tPki^DIP2<3TvQ*hu)&^2abjwWFT4fz z+>lcgjAYTH`&d*35YS^w-gU0^*zW61SdlmIZdAr*|J|F4;Tc&Ua^(LwLsS%3zn;ed z-Jx>k)Tx6s8m$Wa7^mqU3+3_1OUam$6k?bCdJAC>v9AeIxIjQYlO>T_IBc+b_3DZn zjc^5m<>ZoWakIH#u!XCVQd6s8Qcb+Zz^nvw8S3Qpr>ptO;7mu2P4X>D?!I)2dnlCh z0X(4ig@D}d#H0#it6JrXxJ+>>CZV@nt*M5E2{$~GD@3?>u1~}el4md>OhRU%EA}(k z*oRLRDTp}P2^<1q%rvs6j(mYIE)+y#8f$Je$mtE3ccbbr-+dp8m0D12krP(ya@Rk? z9N2UrXBZo&)ovkNqX~2b4+}8)h+T55sf+^L^aP?1vfZ&8@~*lORv()_VQmee5HsK! zw^HRY?I9ZqQOF4DE(C;JaRXw4$74A0ETF8~UK8?7xYhy4xptCWRLd+10*RtC+mr+g zg5@}3dP};g49vUK@#xooT0PYn!lx8{vaM`vZQX}fGO8hHV&9Yk_3&VBks^i`jFgId z-GrGeD#%8F&;fhxSbJQtmK<`?oHvpLsU`c=1A%rmZZQH~3Uc3PslPR@ZF&B|A?mwP zX=g-#kg5zd1D^eYdnKdc=<2LYh*m-rd{gs+UwQ_$0$~vLKrR9I0OUO0Y!r|T=CH_qmWXaB&;?^LcnxFWnw^u)s~5g>uP9xfUhAl zClnlnmI07Jw&Qt}6AcpN#{;izl2Qo8%puk7C-%Faz;xz0_X3S|PmKm{27A{ZTt=KDP_g@G>m@Hhq&w#&V+ znS4ES1RReLr6HSm3Xm5Ja%SFGZSH$aNTXfoTcuqD=J*5&xrsG`NKFQokvv#FJ);+W zw#wkNN7@#9)0f|53XN^>S8Bm zsGf3Na4cc-;R}FzwTzMAaeqY6tRSQuO2LYIC-_ewh+{#~2lPDv(FBn^yu5s`$$1bw7ndWm2*b_ioByWSl>hr_ zSS>l2jMaHtfsQ-(JEr5VRAF*;p+f@=8u)n6i+#Ba` zB^;@<_<1`Lm)EWn4BdHLb-!MSKXFc(+1XpD%rAT9tUb4fC^g_a*ytPgyi9pG-2*sB zHA>8X2$mBe9m#>Xp}r+d&2vodV~O1hT7-xOT9&-#B`WB)?MhS+=p(2?WkAeu0>l60 z`ZDV{2#`p4Er+-{Z(-e9kkzh`(Ac;6t_W#F+uATZRRuH#fIKS6^oI?2a#J>9>q?AO zy@|s^1Utlt5fJfAYaof>i4FnDUlf<_C&r-{i$=7G_RxhfTOVfL$U_ftI>O;J@;IO+ zm^y!Hmj5uyF!yMhL*v2aO2)ODfU6Qrw@YY98R0RJX^(uxczoe{WExm^a^mP;Zlj}!yy=jQA0UELcMJcB~NDL<}c_okWV z=#g*+x}SL3GpI&$Yi_F1EYNb9h*3F^;C29NIR+WJFS(Tu>nB{CflZOreEsU^Z)raW z`H<}2ueR0cLCObLh`cl)8-Ttff{1}hY%o6BSp0GG`jLY&uPp-+Mec&0lGZ@CxE`B` zY{MG3f0s2$N-4s6 zpB{af7eS!M^{dV4!QCr&pEDz9A?H+NY5MLgQEE;EB61=`^7B;mOU*IjnVF=p(qduF z)Q7txXp?q_LebT^C{EG-HF1g%OeA!JFk$y*rd{26Y4zmG?yKQNl#->(!nny!wCt}Q z3Fg>`+*jSgIPt?MjO* zfa8oT@kYZ`rkf^+_i8{nT59pZ-^Z%{i~DcjxVb;kVE{2V%EtZ9jW)2AC9cPSYi9C4vRL%I_)SnX@QVBm@UtbR_N)AZ3hWz#IFnFDhE9gtG zwGK1WDr%m$ug8CuUO3?CS&05|5&X)jpi3HFZnM2aDL(L;sIot)0kuZG7tTqz(rc2#*WWIgI{g#&$@^Fr2a@i z4y|`%@6;owYh4si3V>YP+;ciRbZ_FhA*H@}@ z_sBL74u#yJ>B%?h{6D$2>06)v_>e%bY}{~9SNLB`_g`=6zkeGH#{cb#r7hs{2Dr^6 z(f_h=yl>gVmzb2))3wwseEL!C2}UhLAAW_7TD*nj63tWpn7*CK>#E(0Q$B4opa}Wj zd!R>R!Egkil1`2gQyGA4r4jjcWhleJ6rhwwI6-yl`{?PjO{3=#v|6q!CXnQ4B(kK! zf-(q9Poz_v&}xq@#E_HVnIp%|0S9Bntq=&7BWZI_bK`xMGWjf0y_E|dj6sBqRZ$aT z9fG8Kl1UTG6{MmxAOw1};Og8l4vRnyf+UvX0K*wN*f;etX$5nO_V9HpwwwZ*OJyME zp2OF3`%Ip7P6q+h^hpvh-EJdo6G69qgmMsmb>tNPup{1!przc>2upyg1R&=SY?Q>b z_C&v1EeFZy02J>h5O-ISm;tUoXO1`T*wCFXiXZVMax)`**V}%SFd1Q#aHEwc3SO$< z@-vpg3+U>=9m1}2uUdO&H?Mg4|8zSg{&wd`CpJVd&iMO_Q)@s;+>ZbWoK#Zs@V_=n zAkHKP?8Vb~FZ*_6%bPLr=~wvdkN|xRR83F6?~?ext`D!L9nV@^ zxyUC`2}9i6G?Vvvg`}x=MKie|1KL>>O`G#>AaRd1NRVobX2sn+@2cTzYwcttp`Vwne!6@EhXbcQ*YR#U-pZPn!pe4pv%dZ@+C|jKlyi)WkW9e=~?Qe0zr>RtLd&~1(y`*TlCz1ksJ39yUdtp#C=+#9dejjQj5p;ezsa-U|>KL z7Lz|dF`kTtF!%CZP-wl4iJ$s4MK=>Z*}|Xy(mR^0{0#+ie+E;2mXhYywUSGn!zsUT za}$2dJmc6uis1ZU8_$-Q#da!2#KCKo*>v^IHsv=5v&MHrVN1gF=U?tuTiZ39f!p(| zIp2O1yNvl8-_&1AI8d(T@A~+woBpoH%>Ad3?W}Y~C@46_yUpZZ5f~)9yh%Sk=j}3& zkzXUkH~sV7u4^DKE4A3{&wt|`>&pG4BpRv%N)3)3JI0*Pdq!r|Da9LM38e2ZOSgW@ zSPA86o}(8eD&?rUxbvN7KGU=jYoNoD{t|N6s^YXgpRFXMckOaiP+)a#p1Ni;DpH3N zkgW09PHMh-)58*PzGE$=Yk%ASb#h&%%=8{{)a~MSw9`#YO~nT@mh&=_`!bLw7>kwo zS2oS0nCWDd@*4)_a7C^dZm{R9*62yAiSPxKlD{X}Z=Gw>>h3OilWH6#T|;R^4?p`Y zBN8<+O$3Uoi2JE2#Dnx+zksqQhaaPQo~~y3zGF#_rhTSSA-A=&OY#1KMjMGvV;!cG z$Jgfp?iPE52vE*E5qrV5%3bQAuZc6T!u5r-?!3PpJ;ML9e<5X0sxI`L$jFFNY}{Mn zLcqNZzwSR8G&sI2+c&@a_d|ELY)dh#|L#;(x$5c$EhctPNlA!RuKSN2j-d-GcVGX^ zHnYvmIytXW*ml9O7j}bBbl5*Ue^!}Isd>7(Xk{_-2FkgjGG8bE^b5CUd=+ETdJdiH z4*YbzORQsQQTVCI4(m~c8M|F)QZLgzmoCh(zb3iKd+rRM5Ru)FWxf`QOEtc}n4wJp>n{?6C2Rr7YPybd|iHa_!=!pj{E~x26BQhWbxLCD_K>os^sZ|Hc24)foLL-b-wskk#)QWR0o& MHGg}cYIgCz0e_gl+5i9m literal 152790 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�!W!iD2uZ<7g;poA4*mGvoj@6SE2B5AEOXr!n4ybeB9ePm*kEiDxQ}BI zX+buKT~g7zvo|7XCqcz~-&)OYD>6MJG{3&-Ue(4%+4$?%y*vPD3AT2$t>0wHcw#Kv z@h$9Uy!l+jVQa8hPqA(@Is=qEM6Mf4*HZ<9 z^?xze=Y4DTQ-P@ovfrLL)&=oO8XPw}9J!Izi%fD4+!HU@p>v{*P0YMhxeAKg(h{~K zq5ZA_w*8jOq_}gdc>YKc-edQh;=br^r>~HDd;2bsW?T{VeKeTL^Gj(=%brim1o}_UVR-Lxxt4v2cNMKNR6j`STt3lOKqKP z#~4hiW(%ZS6@4w~xfUlgNQzb3r@rMdouJ*D0N6h1RLO>Xm03A!!HvyEWXQ`-IUtz* zS#)jTX_frh`=bCKYzh98ok{Vau}qxV?%_Dcn(d6ve#eFeXHrG$Z#fMaC2`p%FAtV~ zP|OtFNhB(MiDU_<=?Jm6^FVuaq{>%ihgii)_oGgokf)Z@V)A-1HoShL$Md{wUNZSl zaMLtoltawQvy>aY%5uN~^8Y*l;{mk?9~c7%^i3mX)PV*9^^KdCObCY;7Ocxfz!1Oc zJO9Eoq3Y4kI?GmK1c9cx5FBNp_ZH&n&&l^^t4I?zRmo%asmYo6AIKN4o_D;Rg zta~(Mlyc5jvBdnn= zPoCPgg|nDzjQG@zWRzVXzL^GmaGt5nc8u3(`N2?u!v~N#L2R9vhqoLJ>sLp)^D9Ou zgnky_0kD|iqeeEPXkOTg)Ygp4k(v!=dQZ~>8?iY9rLcX~bQV@L^FRahW;k%(Jr8qX z3#G?|iQ%aaq~Hkkx7r)R6w`C8k3inVI#9t)qpXxxyey2>l~JBrGS0GIAUL-{7!P0U zpR#AAI_`Y=6P>8~X^XO}705~f(i#6hI1ol(P`kKK?a63^O5l#m*k%)9TY*zY=?&@k z9;l%8e@VJiJ*I84`RV2>4s`5-Lq-JHqgGxM}A zhgxlfuP?#`k{*h@o08;o!n)N13y-J-Z640g&aJz=+5TDI!3AqTIkt3w-d7V~;GPnV ze<(<}kj3CsriL5?;yH-VPMINNXI>5|sHj2}v1L@P!=kM)Aqu z{Kg3Gl#ED5!cM3R33y((0NglQOHP%5jQI!=QAN=kWX>8356pGHC7gQ1cd0_9vHNGi zWdV|>UKY_kA60pW3M2un6URQkQ?Qi9sP;g?GGi}-38XWh`%THmgtn$B8{|Ww?YFy4ZyTOMDbPj!jqx0) zGLs|r3y!9!FZJ>>fs4Y#^~MR1M&Z!cFwnWmDdDD%O#5JXW;&&x#%oV~Jw5P@xWTcX zDPNH^5eN0JrR7Sd0x;^6t($Kk8D819=-(9|$JAW&?KWO@5TYyEM5#{D4K-`~TA zyi#9D;svO^l}9FW_dZ0?r%4u>WT``@TsEE;UFA7}|EmPMC`v1wcwc?Mi>c>5GB+-B z><{B(bL!cCx;Tn0T(kk@ImC6s6HRUJ>0L*<)Rxh8ew=()muK}40V>mUXtmq8b@fV- zFOlncz-%lgp52&fQvKzS#K=Hl8GeiD?oFiTW3>NIc8@xM0IpT`l67A9d~Ww1j0Tp8 zYpP4vRa=1qmR9&+qm_RXCrdC8JTxs8OGyknHmSvXymVse(N{TpUlD^ri;GY>^37Xz@c5% z^On#)N%HK^t~gYxB;cHzC3C13gib?RHLmS1tWL)AgwUihBmE+xHSnj}Zbg`H1O5cv zu3HpMnPQv6wPcAm++(SdBV;@@Vy&b~{+7V^bM~*~GU5C6Lob*+nRKCr=3{{Vu_%Pe zch{9NL08Ah@sh87J_SKmDr|3#R%t3uSBVigw5snmJ2;Z{^tKg0V*wOB@>{#n#+1=y zuJ`+&tF-?tUJ-%|@r>5RSnCHGF8C|*J}uaH34bPp08r$7AjmJ$GOKK3UlZ`b>|?@u zUY^=5sM?=uw;VC6CTOcZE|X`EJ(3^Uo|!Sm3|t`Qc8HsEqtbbA@~=EO7QB7Fvn>2G zGSq}ENJ90_A>!7s)C^k=Z*gfl<&_(od!z(c8}PS@p69WwRCdZbgC?9eM_P!fk@6-D(%x*AUd# z@~3ZEMh#eW-0rAyoUj-TyT=0!m+EW9pO%fkYv?md@+_QQza1^*OC#KG2aB7d)90b6 zoDglb{*1=U@?^n;8TSn7y5aGZ;^_j;0l;z@725>MX|iIkqh|~w{g|tAv&nxJU=PCR zEIZlhzEIUM9x}FB439W^Y~($$Fl)s_#+OeQIiqC%CBb z@nKtI#a2^T1Hl}Y5l<+d{`K4sc{{_jgC^Cw%C4cT3|yM=2bV&uLIpUc^w1L~0o2eB zJM`I;h&*3p_2$NS#5Z~o%}$Vn>Km$#G`|N`c!P`wz!rxBCliaKF5{zItk3_jmM|zX z9`T9;3tL)=WU~~&FnGs>DF##?a-N^lqF}{9(rH83?+=|&g}4t>pfiOx@p5wMyNdwn zz%=r(Zv_^9oYNwPS>N|PePED&h&z4>5uc~7@?~t9)q)l|*c|@TA<6>umL!6TrO@rr zAk@llVAa0nCN}AQvLgDdGuF@godN=x;fIEYroNJNQ|n2 zpjpWy(<@XwDa17&VkgtkE2{0Dq$Z+y^#`;zRHZyU9b`>C`5m1_)$@Uqy03miE)Zho zA|Pi@zT1v@B;4*WvFw_#`0GLhD2vg{R2howWP*(>d3LvNgD{l-d>7@9(ijdMkVKCN zdF+S9TL!EKgw8E^FCE-(m?4O_-?NJLICCPM0r1WStHs4Yv`4QFxqT*5cE|{QjuB!5 zPc+jbk39Zxv+devTI~2EQk#Uyg9zC97vKURtTr(iN8rNG^A;9>2LC2abtsu3eM6n| zBnFfKkRLIZAUJSu0gic=#BJA#BYFz^entCyz``LYL3i=X}Sn zNvf@uX(?dla!p5!6tZyn|_26)nbJL%~dRM5kpx+*IT|a0&0A5(v9E?hNGomU`frFWpsbr?4`hBr;p>cn33*YtT>L8z470xoZs@ zdB;yXFHc` zDd!vxR{GhzyJI0OkLHY8p2t|-E@!!t|DM;9N0-+HH5ky_&w--{*Ao0mh{$K_>VuXJi z{#nct$r8wiz*Cxc#cv|WMgiz4LIMR?8FA6Qg}VYDBfPo~lQ-Tb{Mdi;$>Z#QhuGN! z^B*Pt;|WB_{@;`iIr}5=V)B@7y#xmsnKhZ1BcKeJ6C&`DjLQG zNkQ{qJzHav@QNM$M|0tzykTsjR<4YOA}A&N^c_zgv=?Td;ID;qQl8!rUtGZvnT#N3 zcf}mCbw&lU)h#^sijcHmD@6PSBLMGX_BBERV`pC+E$dkopvk)xm z=~+|+{hIUz$&};QcEUJtPfdtR1%v}j?hLczlR85k%-#wqSGlGFH) zAUl!L{~bY~xzOh`FQ@cBGrJJ`220#vwuH%6<8v~X@vChxv|?B98vF$;=Xu>ZWW^A& z_Q&}`m`i0QPMy6N%+8xh*}b109?yh(Gyp!41}>8G?quIlLKagrzUV0@y?~4OLF=xx zRkRVeFpTg@IX+&l>N7unJ#;2j2}904?##Y_39HH4kYBHUh3P=xy#Dd)Z7xiZFW&j}+*n17 zC8y3s@ayItB!voJa+~^B=v$Cgn-RNLnBKe*Q`&VBm6h~z!W9s4l(6W`@Xpe&=5=_= zAM0L|%|iaxLJ4D4okXm2lnJ%4!~+jri|OUXq1)H>k?q$Aek8NFvv*R;^AWvxhcWHk zeW^%-5VZ%F&0!UqM6H_grIBC$5OVEI=th|#WxQ=VGpjQV02X_OB^hr?5gAOk@qVBa ztqXgsmlHFrJt@w*+K=QBV5{UH>rV*Hj(-Ky0#@^suhPTvN7<}503ntD1!PyP_zcO4 zq6k;Er~B|Sk1Lkdet$>rWkf_hnzfJhndBZFxwlMSbt==gg5vq~PAi3RLP=WI7wh-O z-N467(TYW3UAuGZhASHmm z)qZVpqA6^mXLD{_&}R=eiq=UaaE}L}3~i|o{xcMj&N05$eaA&JoyFZ_Wj|irgM~vV z^6MYPM427xuieDmO}K6q$YM7P_z*@UwF+f(z(;nz^y71$@HtlLAUY!Y@8>l49s(F( zBqdC@VIZO>^3&S=SL2+@(4W{&h@N<>kcx&65)jiF42(?EBFFmm#au#KqBz`xIs5UR zp*Y>+mnbRk!@tNoa^?5I;7`sbIMaC{lV5dBdBamxnX$?#Ehc5qxVw)J{~u-9)~yh6 z_p0)Ito_7v#4RkYzkX-u7js!PGs<$=JP3`kua)Lw+wmIop2~A|X?a!IHG{53q>or28*2>Qj3VdQjcjdkAVNC@4VOLGBc!2c?ugdcu;0wAWL03fiXiS=D;!=-b1LW#)%YwN+`D)0=KD87 z4F7OHZL<~j3DL#dAy&EX;5V}UQU0h)oESp6c2%SUznGQReDvyePLpMH-z5-NX~s&a zW3MI;Q9Sw0-6E&qL&I-XN~ABlNKIb@=8wf>ei0hf_?ifVP-lg-?~LWj)U1D9b-NBV zyl!(7_ScmQFW%g*RU)Q$4b(n{Ar5UvL8iJlJ5t&MQT{A4^y2g+)fjS_lvQ~jkML_k zq)E9xg|LHNw#y`yKEn~-KEfU%#FW{`n(Av!{bkBWzzrRh`am$X^xI4Ed z;i0$w*!d$$A5$74a~X4!Bck!03_JyW-S4`a+`UDHLFswWTMGT(M;9{Uc{&g_| zTop!m;)^p8Fy6p7h~jqcrsF1aa|%cc7cPQOI~ zjlK7f9PM!uTM?zQ8IN^fQ9J$m2{GpXl@#q%b`)hxMoc^TD2IDmTR}LYtf))%hFoS} zHr}^BsX2eb3_Qd8$MJ|a#DA$?_$g}m^yhe*h5iF@!>7iTprOUNJn4ROio6+?Eft~V zQ%Zx2^wH4`qmRahuBNpe`BLKFf3HDFo{hd*)P0FwT+6Z3 zYyAHA<6Cc?i0FukSTPi%NHxy%)4Xu%bX>N4%I5|!S^e6(%PvVbmRmZHn` zZ@wPT;Yb1&cX^4aw@Hb<#1)77W_PF?V0jQ$FYZ-kkKQxjgI<5x<*h*1&3l&sL#FCj zL_Q{Xmt8C80debOMh}MlLF+rtoZ2-j?dA;S1(AASGITae`Q zhy^zuzjXkEQO|+}Q%LA%F;ztvb;pj;6ZvRiD3%*HD%Iux{!M*Z7Zhh?qk%R%#z6^L zo;dmR-1pURrDnZHiF}oe@;*v~#g?-{gXDzhHB5zskLo;N(70sVa|hjhMU{ytu3*b3 ztrScg-xOsppZTuu)}7KE;`v%`9M*HC$CHSbh`yyy{k$6o36S^^i5Lb`YGHrPA~)di zAS{~^fHz|gM75|o<}0Z?kIqTB%LElvkLZU9CYWDkm8)nb#yB`1DZK9WqAe9au%cV} zSZ;(ynHpyw$9p{6^?7V;bi%Q*wX&Hr$j8lFvwxg<$Maw@^{Q_@yY6=C`1QJ0j$9lJ zLd)V#3#z31@F}Kl+W_aGvk1<+a0G1z5FMBK7gr#@MWHOh6}Y_YUQ-A1)lUCBddl+= zBLWY?k!doOrx;2!5gSd--XRgm*6t_>a=6~P@AzA?I)@KH`+t8L#oNGiHS|k@Y@~|w z(T+q9AiFKdnf+R@;Dl_}ow3|AtZ!qZtay{AW-n%l zp_s?Toy<36Kd+fmA(!ZdOI*s?3_y&_WlZD3Mhni4S>)Y}vd{R$be{jFk568Gk4#TE zr?#sbIXOA(%1sl+;Eh4Jf^q-Y3Tfix)F_yT&dn?@-M`)dw9p{m2X)(I(i5U29b`sD zYKSlR*nVPDdnViRdY`mi=mm3K1}ysAQ&YxIZB{)n9;D(xr)};FtL62?*rhFCzi!>; zfX*M6;dJ-n#S|_T+7qIB%;!7ijFr0$IgCN5``2>v=JB~4c~R(B%g^)b-^wh>L9yDD3$nqA6iu`TR$Ez^9>_aNn;&ED6*Kf$QsaBB<^$l`$_(Fp+1w8A*NphFbs) z*HcLit^$z{hrv5AU%TM2u`*g+D*5|Rdz`&-c6j})Xxbfa;C0K_WqOA+SpG_8&5xm+ zK1vVL2V%xQ8~}kLu(WB-X7|YhPn3(EZHFyY!S%P!-1xzzVpq;4 z-m2`*v%T6<%o;D8q#i&MK4R^M@d!dcq+*r4BUT9*%C<$F%k6&?xJxA~W4l7($J5=|#m^$`kNNDbttCS46uwj)C&prCn$hM8>{Q zIM``w(wg~9djj)E>XdMI8FHjup%*WCTpc0|OVfH`K*R{;gRRxEk|&3S3R{wH<>(fL zox8VY4Uk8Zk7L#Ee@Gg+wT$%5lAH7{!HEKB(OL!>?~TfP_!!61`k|9NXS~juMuO7o z&mwC8Q&n*n9&NXx7RQS4j-gbxnYGCXpr6ja&>=US>Fo*UQoPkB?#?@4*IKrT?lH-# zKDr=0U^B&Dp!o)SxuasMt!%m9)}$rw((Jp#!Vjm?3Zi-dZD?QQjXIDfv7Yz6hO)$J zz`i3bzuQ1|^Fxr2$buC^6;pO{S%2Qm5(xc-A{cx&Dw7T`Z5d@+{g#_HlFVhjBA(Z} zH0ZcCI4oO_*XXyW*?($lT7}9e(;mgQ8pESuBp2yjNatn@5w)#MM>Ghnpk_@13*NTq zu6uofazYc-_KOP3-`*W&en(~gkyAFF#u57O}gnWmZf`A;qkCr=)naH#m3_2->?nXi?$TT<}?`Ih=;qw4l^rY&rI?_jcLJPM6*r;pa@pqwpL}*4C(75ZC?262s4f z*t-}nh+VgJ8pI|?%4?a2oa`|HS}R=K{pkIVmC%P9@{hP=YF`eW|KcRE z+UeydwDz7^DK+<#bXN7#ruCH}zsLXz-KMA+>PKI&qTic+d$Yf!Q^TXzW-4vg<%sMz zV`LZ6a4^g>Q0vZ6xWF}{=y=*^Hv7}4wuZaR!&}B_%BDh5pKb1SUHIjv#GJtP&QuKW zO|m{mP87FrsL?BY|~j^fVbg|Km`(uZI{cZBlHf4>zhOl$Bw_$DIEF>!LgNpK9pH!}xv>dRv zDp6s|7;soOUWP?I4QVj!p=AyJUrsAnzgY~sNbbEykyA_z2CJIrr!K>mm6c_Vvc-TB zfYoknxY0Ot`nj~Q1brJ!FPWWRD&5{%H-X^~-?zCuT_b}u%~rm;@iY346ETLH6i+Z! zM4|QH5%4~g{wz;9#nnabf<9TrG@0vnYwk+Ut@fqsG#E}gYM6uYN;;&29G5NgV}ygo zM-K;dcPa7ffRp|?`%NLZeq^8j(1OQtri-joCVPrvW$DFFR&R{;fXPmabf~Ye*sj3s zo7OPSYugxN*Xpr@g>}8a=EG!9r)qCrXt+-QR)W%am~4AKq~c*l#a1zlKPcyYSy(oz zmaFH#4jT%;P}_aGn23YJ2qH)!9g4E(!k;af6IzD;_Uai>qUEUp2O9+zt~xT@9ywjU zqE#>!W!tUTo8ho@QbV`->cS}WHRtm$eZEd<-YB@NW`)f8?4PQ>%p5tK-=#|#9hwPd z?4U~f#%NxLx;b;yqqqoeL!|}!W!MGNJ(KzFkk4vCpJhbEd9ygj?e`3Rh0q^XD-*$! zmZiqQC0#obq9LTG-ZsERGbXWSq-gJ$W8j#hnyQYgq|NZ6s_ra@23FLa=nRfLGUjJ( z8tO+2_8T4hWoXFND{I(YIl4+-J!KSqspgLMja>>B4Q_did!V8XDSJ-V7 zZ@K+8b?Io1#*|<3;sWefeiQLp9vU8q7$D z=|0)!trmVVkg?y-O|ZNk+gAMXhmRGLij5X{oof8@cH0r!Hz_vuO5mwS5E{<4xUT2x z4Ak-!_z}^C+Z3!~m+NzyVkpJ&ust7w1>HUk)M|s zmn-}+F=`ex;l&U5>$4>paxdf`I8jrYb?YZ~8EhH~dNQ0iq=)12?ht>f!f4EsLk|L( zWI&-7sA;P&9Pl}7Hsr%w%z8cHe4hEs4<>W4(blyDKC{VIjFooRhcWo(TVbssn4S?E zol*NRHS;b0)>6Em&?FiLBVCM;r)+|`H2E~uoJj!z75cvM&rtsTchH4#+Md3fe2qO- z@uS^Ro_a^W3Sx-<2xN>U)hM4QYSgs{yp?bvbP;+P?ppF~5f{^C1LkFs0++e}Z4YH| z_XE-+bfX``hJx&3SQ%+^zz!Uirk1CFOJSJ$wd3$MyINth{)wj`Rd1X4HWyp_IBSm& z!5-YEm1T-!bl&s#L9wn$UURXq>M`c6h$248b=HN6k$c?is5DIYxaK|F7Vn&}_f=LEJ26Eogz>^qFz1z1_LB1%omMVHT2f zbk+AkFOD?@Dnum@w4V`;&(|r4U6!70mLkvcXUi=;9Z0aKAALs)x0?&CS-mTg+pEbg9a_V7+b$IBS6Eo_Nam_IYa_0iMy zJV6s(TZlKFvp>$X#!=rJ`S|rcRIiip*KZUEy?%Vb_(zH;W*V|Xi}`NT1XqlURugng zRa?8-7enzFvGhLqY=X_x>Gb5Xagp$EetGwasr{6ySY3~#+zac`u-Q&+KjWa5A@0Q$ zZ^S)pYJGng=JUyFuZ~8T&MvOt@o$duR+xc3igX;Vmf`Iirg>@x0}XoUXZ$`f#h^ld(;*kAqjZTqhw7;f?ja<)=bc(j8 z9k25kmsU>T_RY(zEeV&gpl8A+?HvO>Ky$N0fNkZF^p$ z^U>g6lnA0b-(|dvcun!)PNDu_mB(y;kIBL%E`ztoAOpJU!xx4LnImpn^|c`cmyK>Y zqkq>8+V@YCE`7i`EWD8^cYXyvb9;e-2b7WBwmU&u434AEzE~m}ut;wtsL<75eWsw7 zorXYK7R4Yw?oZOd!094s&k`%b5f@30K1gLpUJw9cj^i zYqo~cba9S5T$G%Y-dp_p+Ehjfdwyq}!T=ugi!Wf!b8Bn`4aEE!n@Ma>NU|hV#UP&e zZJ5XOgqS|4^4mi6b}zGrOZFWce8$TgF#QHE$8Ez7VxHcF2$RV%Ll;lug1&Y^u+a_= zy%pjmiqZ=DyVHs%UyHT3dS?6zDapr5Zywo2F$;8|%@V)Avl~%9ha?8AYQMi5Ab#XTc04-a0oIln-0%NO-PqJ3*_0B-KbD z6Aw&1K^oOhf25voWzx4BIjQm8k4T^Tw$^*;?H5GEbh&bC9~a-<1#%4#MvS}J&soyU zn7ul}o0c&^$?Det$)EB3qEw8Gz#eP{ROeK@Y~y#yq^N4{oooq%wgwBoA0~q#c?=d2 z5#Fq8#I&NVQZ6XsvTc3Sn+8*gaxTs8co1jJWIls6d&`?L#-#9gDZOB|&%fMAy_NGq z;-cJc}Zc;RIbbAdHpM~UcGZ#5Re81sPVaIYgr$=BR?ZPB!>_4YLx7pSbc-Z3(FfMDY zqe*Ce`kCat72NHOxlnCiv(`kp<+-3zv&IW!E42?@&YD(i<~!c4W$+Uiq}d-QsiPMi zlt~gGqT&-rG?`Q{NBN{#h-muC+$~$RiFTRIGoM(96a`FP8D7IsVa|iN(@P2kV=L8j z1nlpxfI$@R>Ljac{3GSJD5Y6g@g*-_xGG$XUi|7S-UUSMXL<6HXxJ|)7PKj;TAyJg z8vjoIPKM&uS8y;FFM*FtUC^##c*zT>Sz)zixbSV|04d+Z%fO8!f|IG4k2NGc_DhG# zKNfu?;7Z-bX^S?BK9Pk4CdvHX6tTr4X%n!*_W{LHtaY~EKxX}DV`LBf&F&a~R;61y zq{1riu3cf*@j7I)`St)up*^~*wt)AP{GcmZ(!$^&0Y599)~n}A55SL3F99EJWBeEe zD?`49Wf@;-J|}AC@SE~Q^}O2Wr}{oKhpYII_>bg&S`H5QZ7EToH7eC<%=&L{Z_PeD z3~@t{mwoKC0Hm7ecGW2wv5UX9HI5(78ijnu^@#=n+jrMgQ?=+_y6quaDO{hc7>IxByyx5)cvKwuolUI_XYLlk zpP?1BV!K=pr}J*0Os{T)ar=WZKK4wwG#OmFKhM&-NS`v?=$g2CkMw}KG)7!6FXycO zVyNSKdIj1ONs{~i^~Q&=Sw9@^PIYaS3xjNjLS5q3+r)J9Efe->UPsyI{kofnn4_#m zj|o#em9UZ5db^L(=*!~xVZi_fuL*(kVJmw1SAdMj?=z8%rtbooz54)KS)vTUyPYs}%=9$ia zw_0(#acTp{=!}@^g^{4^y_Jo*fh2GzZeS13-L5112(YNV%x@xJ^y}6TE2?5gF1&Oy$kUfsFH+t=qB;fYd$%q0;Iw5xMj}@_rpf= z;hdTOH}}*1!z|kh@Fyjf0Rf1}snnvcx1H8^c7Zr(2jxxtoDw7G5 zAk3<5DmIU0LPf;umj7{AQx6)8X0+#3{QT78P`}GHS~F zVqcGM_M3yht16vC0V*G|Sj#d}sXPe(MwL8;-&D!+8vRp{8INX;tsP;ydjEQ&EW4TE zR2vsCWRyQjA!AF&l#eX4ma$DVlcVobHxTwO90_sfKO9L|qUZYu@5^gp*`{acJ{U^1 ziqv^>tQ%lIWjXh*j2zVyI*k}>j`czY-?9Jg=saHt{|Bn5%cq2?-B?b~37^>|MUYCJ zRSJo>pd)%r9SvHjJP)ajy8n6h2S@>$OXYn-&b~{t z9Khm~;3rr;;E^Z7qI@DBC}tE#-@uU@_VrQY_m|BknnM^uf0qg5^@Ql%8kG`HL>XO! z+Tt76ztEoy<#_RU_=l$!&)zR566oq(=`H-&5z(E(fH07SyUdMyhduR^EruRlyGoO( zh+!47k7j1=9pt_>)t)E>Qn~&Ks>hmQM(SD?n6k9TIp9F2mjU;41v;D7I}NkFh0{L# zs;m`=s>uT)Z3UC{h)%iQ%Cdjcj-jUCO9S&uxxAOob6A2TL}y~wfw4aiPfDmqP5L-u ze$^@*PHq@FX4-i4H63zrPTnQSSzbelvpw(CgD}AyY#^&p?^Lu&Tb_Z+QA@A7z+X>| zRMMxK)lO$V5f>7UXt?b1zBWuHg&Fy_JrKoI&Zc7!c^saatd|$x9KfIp8wXInN}p{Y zvSf0XwQ&%yjP?%? z7?jTQ>K?#&RT9RXS0!mXFfwo&(ZY8*V#G54VvL{Sgwy!PCYV1FiawP4=HQD3&V+UY z{7wiRX{(rC7xAv<7k7CMS(NvG_QfdiWgvVh?yf$ie9soqIM2)65B-g4NQpDaIvW~B z_o?PcS2oq*9b&p& zBsv}Qr`EY4Ps?*wypy0WvxDo*8A9Ff=M+S+yw5a5@^{FDbFr3M?5BPd!#^JLgksLx zS%e=Oh8deCK1#0dCU>Er&^q$U0DH;yG(vWrGoy!d36+4kM@ggb4u90sFIG6Ex(t)0s#gS@#y`#%0Z z>?t>C^O7?Y!J9^am7!?mPh&AEvEb2r-SvMkb1ZEaZWB-^Z^mdZ!Q+v7 zKBEkGi=MKg0TW8ev!!2MDSLDETPfPqt@w_{e40ii z!qu!GIP$x66c$b~Vdk5Iit%@5_wUfT0$cDGCLCy{o|_Ca)2_Suv|LDHMBBYF~pj-x#Ndg(r_ek z?XxDPa~)ZI7z=Yx7vB3nC?cTGZjVfx5F3iI9ZFiZ^7LHvUyPhWIxswkS)HJ0%R^e?N_8C>u z;ZSP*;eS90RlE}1n^19g6miblwaOY=973%l_8xC!F>sVlA{qz4CH5e+-&7#C9J}m7 z9z53i^yjss)8Cxj_0xNtEpfr7P6eP^(rHJg*zS+Vx)mQgr^{u@QN=`Y?ve9v%?N*5 z^!Ra5=E(jxCXh~ZKYGRHPm>L4U$D&|o3)7P=%qeRUID&a%kJsY$NXV;)Xo`+XmzdO zKNAb1vR=CVY1{tIIpExKlte~i)LQpAyYC!{2umxN3~H3$pAi0cr2nY&A20nUaesso z|LLXwzo^Ox6z83{IJ_2op3X*H^t)(3H4 zkUUe0KdNOP^(8}ga6;2cLLxB`zdL^e2?Th)tfjJmw?sw#SHmKbj7xHZMJt@&Dm{Wr z|C)9yhCA+`R=M(hC@1Y%_k$x~n|M{&c3Cb@1SXwz=wwn6SpB!P0n~q*{2MoDPoRFr z5byNe*HW3=>JdLU=r*n2kOuR*0C?mz2C*_HR=K1wZMDb@j+9H%?U2!IG5B_N&0oKL zRb*`Y+`Y!d4~Iz&`5KURinVJZe(fy~W;BPaH(@#z^2$KY$?lx4StRcj^;cs}O4M9! zLB2`%>ciIz|Lb+vbdxF(GzNlS}_o`35j)m{UrJ($EJxu4=_yD*_JhwE`;jy#|{!T8D%BY3faLNGc zw*)+{T7Il~yiMRRB^a$5&Y};p-j;I~J1m&XN$=w;2&tB|F<;9pWj+U&m+ndoD=tIa zwa-t-+#c|k>jd-3wJTm?RB&}5p7VcWL?)j@P^i_)z1Tt z*j-{5M43&qY5U#jXM2cF%x^-d+)d1Ta$zX}J&6Lc+}5b}ojR^jd``z0gU>yQcS20h z$*1$CNH3UB_Mcr`BDlEI)erTAc?*`?Y*4eAKC@~&X9lz7urg6lURU^$9$x><{ zesL_16vZf`k|ZXz30Y#Ds0bcYeye`?j6gRDcTtRUvr?&^88Wr-j03{$*Yoalm$7pH zgK>aJw#RnhyBsh&t{%-!k>1x5&+hJBPwF9+9DJ_OuBf<%>GSqJtN^D zvB7g6nV^*CZ3aFv4%h4PVw6(0_1OQ3C`7h*GTq-d*DsLkH-TG!c|5vatP-$!MlnIq z$g;aYbQyP=fU|MVYwEN2 zDO*_p?}%=zQDYxM$3e&;E`V9;fW|OetOlQDE&h7+Qx#E1k{%kPG68J5)3HapI>oJ3 zZk7de(U{&(Q>Xc)_0QuvZ;@n<%>#a8>>jNS6e^??)+ECS?`M)#gOVD=%nTt3Gjm&$ zQnH>~5J3eu(^RAPt8(~>xL--S#KWTybyO*bv0c$tgfK6BQ!3?mgtm4CQfBAf<}%7n z@0r36e8wlM;Q=t|tAmjdyKC3dEQF2AZCs5rUNf{nB7o4c4QAp_v$))~B0Ahr3kj($e z*7$-fIso1@@4kZ36M{dePkf+r!RB<7*BlFw#t=yJw~ud7Cs}HIvcY&=LQpr2U)STC z_`9xvT4;NFDGQLTPOMEtvb%dm7>|4@Emxz`dUDJF(CQ#1tnWJOd zOXscjSwvDt`6a#o3xhc8iS+l<@&(xks}FrXG&gBT_r))vXK^Kc~rHr z@_0K5&ffocY@g?)-{Oi260eMU2XMszS=Kw}kaSfLNYfj{gnY*=6^eM^YK^TinwZQ) z=z`(6Wg^}F*W>5E6UjpT!z_@sMs=D$g8t7>tc*tcfB_?kK^Hv!Ll-;)Q7TbXvz$tQ0^!O^3S?0_$lW7wsaiE*cWgi1V3uKG~&Hg1zHf`2s=m#$IUxKxrJ zgwJ;r$zX}ni`NFF-aLn8Yd5TGpC4)H$A78oHNmZIhk7NC?%x~*8+n`r-I$5u1U9eb z2O}AFhO94$tG8QU6JXg!^%>-yGWCUDQ8f-(T|LmL>6#y`qcJvMlkX(r0ET_|o}uI1 zA|H`xZRv+V<`PJttWceBkI)dle(tvdx8D)I@wG+6c3U`OoZhMP1{^_S4G|$Xk6ZOG*QyRdGQz$rW;xt4o2K_N`FC9UXSdyjRv~ z*?DwV_ht5ux34e~^|4?EBz&#raXeZSsmV!UD)Qz8C&4*t6UDwW9iL6EiBGFJ7S3dz z(m?Vz!BBhXU;keldhS+SH25eEp7K@l_~)Gi=d76+4uoAk;Ro$SuP0n-%C%FH6PTdL!agl z|1DAp^C_OU5o=7uCY;asHtJ=T5^)r7FemtV?yD5~DaANOp zDQ+qh&{WB^&6Mg!-*UmP54r(9TY_zsJr ziV^5Cv+&0#!JcF)1{vwc-2e)bU{fj?0YT_^#Z%r2{n1iRw5xO#<#CwwJ+VXHZ(({! z(*I;w!s<^3h{N+Pz|d-o@|95$ez~{$Zg%*jpCPe6-_c?7qQmcH$o2!^%Jytomq!Z? zynWD=GILbbh;w@ZFmDeI96fa(HhpRI0X@f#va1XWZG00e=(m}=;3E|Cz#=qP0~%Yh zXl~!hYg1ad7!MeAXb&(W)3D33ozALN;n7A={)TCJ!PjlKM>MvoVd(aiSpWoEgs9sj z_t-D@sirG;;35~yL0d_cco4p06i%x4-g>4{p@1RdJ5HJh;SVRxHXIeZM_VxwviWOY zIz3OOk0Xt6H9nMMdnMQ6^sn9b#dD^|A-Qo!lvd99ejrPeu{c7<@}NjBa854%mU!r3Y|-KG}(7nH2NA0W|Yd zCk-$HTaleKK2EfU61L!Fmu5EwGPfBVMpf?6Rg5==Ty_+;H@<)3?0btIO;_oHKvdTK zucB79R91!jbEU1@p9z*t5{&b^YWzf+WvFy+Eu(u(t)!irUn-F1nqHETmRE=q3oT!3 z%P0mQYnO5HM8ch;!VI8_#pTb2>qzdyuRTuX6`uGtfaZqM)O;;|gF&fe3@`Quk)-L1 zE__5Oi{xWxnKv30$PaWc?w_A-?L7srxBLye!Gkc_vC9k?w4_y*zd?BI&IO=&fo%HK8iA9)t}S zQ|vI`E%fr9^RGXf5pAW|S}=GAUb9vU-chywc?eu)|(x675kt5x7k8 zT&z`UNdp>#W?`GbZ$Fh({4#%iWw8EPU3H|s%GxeW)%I+Ed zX3J#kV(Mci=gs?u9pGwq7RkJQ*9&Bd(71duE+_`-RFIA>*9sFOXqFj#Lh%jJh0tYK z*VO8>0x(?5<_GJeaKrncQQT}{$@*qIHG%@-z1Mi$s!dV3h)n&_n>1K$E$jEN6Ew<< zL0BntgBJWB_TD_4%J%CUFCkKFLs6N9CL}`US;&+rnL>riRE9Dp3K^S_Ih1+In6WZd z$UJ1sP}rsn+pyWZ>(YH^=f2= z%D5c2`v#yw`=#F7jUkk$_*<&E3VT~Dd>Cb3{$L1#|^nq%reB#xuOt3F=Vvl20&nV=nMOVM=8U(8{;Iz5uU zH+eT+6q!mA@N6w^-Z>DP5G$Z~A1Kf+MXj;hIe&Td z4R+R}lt!&Q9xKXA2wWOw%DJqU;Tny|xG&{>#K9O)TMF^zI8B24R749F``FKW7f%*1 z^*P0^))}u4E%v+E80#n!o5$R}#@4(J3}^xH$6uib zb}3kN&bO6`=KLR&rlXWY$n3nRvQHbpED&aQ8GDg6KicTzoaNp=FE2AEC(_g6_`K`Z z*Q;S~C$cK~#WvRFBih6HulshFfoVSTBY#!;lNLamL)Ahoo%-75IzHBLT@^TL#TN4 zEt&GA!E(wKFGRUj6O_6X6%Q(XS)O*Pm{1j8xe{yf@-W5``iA)Q!hF`V63Pk87Ck1H zpne@q#gxYcoMT619^l2c<+B%tyt{#J7P&H01E*#5rl~h0`>l^GKFb=sS}zNdCQXtdvdERZ)xV99886>|`j(2@2qME8 z=fwvqdo9iNfnb@e7T+|+SgE4KtntK`k(Y{tJ#UQim~-AE4oo9Z5vSHM#vAR1Fvit7 za-d)aO19ojUeks*(+U(+|>QhK9VZ6dc~_lMh7R`sK;Pc}AOWChKihgafV z2zL-vL*Y{@)XvLv@nOafBo2zdS#%VMfdfpp>=4ObBYNW%oR&Iq7HQI*jx8j+fRSQ5OkDni)Up5W zsC@iA>**7o-vH-J|13RwrhFA!MasT=EQb=#TSP`jMMr|rGod&|wsZ83T_)@K>j;*l zH&O9vFEFY)!#mfc6VCSnUflZgvtu&y(iYrlOO7rB%Qb?%2xQ-X{B_ooGtZ91DcoH9 z=_9c)?=bK2V871Ktmn4SL(65Qb5J6GHh}L7-P|(iszrdhz@p~ry3NL-jkumn@W^t# zx%jaED{JLX^ho>>ml`ZIM3R(9p@J>N4bfKE9#2y2(flBHs@<2qTVbCQGHaV6b)rR? z$H92DyVEtci;~Z}0_Ru=Nw8(?o3%!F#>xil$%&cKV(EGX;)a4nC)r$$+h2ct|Fe~V zE1VAIx*{p@j8`4;kSIU*jAAndb^nhPR1~4~oL4H-v|dzBGn1*x8^O0lcY;VUjxmsK ztkYZk6m|A?)Dwye6YXr&lV&u}d{OemKcBA+R{)(F8;MpEo%N1&04Gpl7IgNtU8NBl zo3{odbdpeQ_MWKe`#eQv=MRy z75X*y&{dYbdT#-pzpP+A_L%zgTi~r8?x6@S$;SPBp5wM_7Im#IIO>zq{b!20>Vj*a!14RWPBE1%Td zhp5lpGz2C^3{%+}TSUY z%WNwByb+|UNzL+}pyr!D=zQ9THGKIgh=S-Fizdu`utJMW0{V7ZSN3eS2U`Fd0wei{z?ctdu zmB=5^gdnZPW%UDx^w{j-Ll`MHGo}WUI>8FnzEHO+KgJU+HxHr>fv?+R7A)p!`Y7r( zw56bh=0ReMvTP<@ilnS2ReSSA7GBA}SN|Z_0Zv-a-~E!Y?}~+LnyjyyvWU5dP1lNv z8*ZfeV8dyAHD?xqJK@LE)**&uDJgp)Fg~&<{V$g03Ui1qfX5@sURGD2&e6INA!Mw?Q6Je7x!3~H1M<}lg7djOCOq671w+{!LK|elcx(orOte| z*kpkv&Klvfz;NeKfe$wB*g=Yq)u-pO+m4bR=@K5?$|(jFR@PPowPI^R%!4zS+bHUkqmoQE(n zq#T94xBQtJq!T=@h&{k*mmL$F$nAHJo*?68nlclqjT)5qQ#V9&svMEKL%fbx7G&lF zsalNEi{}!nYp^4>WAe4F29hG6!%yLiNncJRB#922Al9TqSNN;!!`2yb$CNy-zh($( z9H_VGXFZ18R+si!F_y7(IE#f!<59^3949YI{BOBr&v#JDKOkY#C|$=+tT$7<{6MWL z^gi0L+j202>4oHPCfVU-r(Qdsl5h9Ph}mV2dP)U5Hx*RU$j8xHR^5ktaUF7Haz7KO zo-m7nYLlL<$N zxJt(2{nwHYWIWM*c(XL{AYivV+pjf)&A1-TcpEsi)X_tDKF}UOth=LQDxGrf>SXvL zW`bcq_ajK^6aEpsKnkPzV1#bt>6P~#R)wGbP~zK-Vxu4!&I&W6-&*IW)4%C=ew9IODt>+TK1vpiUNp2IO^^_R6&?)Y+~h-Y`ZL0BQlH8#|t6M!gelJK)if5FdG%Q84^Ob zhmxydh8+wLT)1D^{Twi(uRRjIpX}woPzBCv^4Y0o(FYET10Eg{xBNn5?+p2^&yqQ3 zL}C%f8dD&%=o2%@c8Kp}?d|e_%Vi&AQIdzIk$VyhrB}mEn8&&~c8xp)CtITuE8Z8T zJy!#>&xaL+fARtU8OaenC1JcfLK({+r*L(Q_n?4XT>H^Osb&dqdspM^J8nnq7S?Ya6zssO|#-Du!$E2BiPklz`&>m9(JgZ!a(^Wt%=r^2>+swluch8xCCnO7Z z0tPt(TWm)jD_~jSCKap?iL7|Y8>|kLKG5Do`#g#|eI(pT?9ocOcl)uJ% z8CCrJKxQ55wrCmfEbf6)Z_|3RD*JQrSCl6*@}8(2X(AyzBqqalwQ5m$0@%c6fg=>` zbm=A2#RbKQol2L^eGNU{O0rK$sM$<*@<<_g(_S1*&U04 zk+dsI*vYZgUy$LyS?HAjiFlSH+#h>W(U5Ai7Ld7w6pwJ6a5kBl;Vn167mQeiI<)T|mZVQiF zE%rLgK6tW&Us(EPOY%-7x^vN5S!G`{fm_#iZeQ>_3+=G~9ktHc-rKsqA51__wR;Ss zCrjO__)56O%&gvgsv=+q*HgVZOrE407nxXU!qb#!s|VQcE0Cpp8!WNj#RWM_@nebF zZ{#nU4}N&yt`+>#Ju&ur82XDduzZl)33#`LPuTGJaUJ4{>(6PL)21k__s!r{M3O_n zD%g@6W|U7{y@AwE$^RuVegudEjZB0DlOJ$TzSINBwo=n9Ec?NoyCzuv@mIGc?!{=_ga(p9U>ZpeYS_I-D2>)rUZ$}hLw{Aats+n>1Wt>=Q*OUC_+@z z#~K7l@p?OK(l~VSS(I48>v*-3@Dj3xl%qd0^lP3VO$Hx#9sZZd5tt!VET7vokjgP- z(_d9UsAV+94D4F@dSNSDyMy2^0zGjn0m|W!2*76A4p}Q5_*Jw<(%uw{MU}jq66W}+Ugi@!zYOL+Nq5@h zX4#MgsfM3=uM#cXo>gre#J;_RiY)#ZSsXZ8|6dk|Vj#(%kQi3f7fibWaLQ(YF{OT^ z=$M{sY}5T)pr4P8B{u7^Yf&k`d&U6jE1gitr%~xm|0bWNf<;Jad*GJrD>-RU!K#vV zmCx#wjL1ioPnR6|MA|(;s0?xJnWl(Pw^1cM5uy4Tzf?hlss|Os;F@g-7WM-qquA@L zY|=CXh*EagYQ9+(e@XNmnliFhxM$Zg1f5+ui&rV!L7+!!OCJ0DO4$Th{TvS&TLj?o z{*RKb9N}bx+&|yE%dGuaQq&MJG4bc->_d4U7@dTEw8hDMCHkGP_UtCJB{yE>{&HnE z9Plf^|M`<9p>_UUzrhj8_~kFTaKIl%KB-X ziPWMhM_CMlg<;Lf+Q(EZ%TL(+~<$3JV&D(hl7HAHCpTyuOSs#n2V1ndPz#(xuoi zwyT+WnIRB3geA)#xl zdwk#u6bHYcnvz|^-t0O^+BHnWMtjBUx&l@!aQ;U_-D}h9_+%kZ1BB*PB$e6rJQHbf zJ`MT1ZRbEeZsi)C;6eWhS+Ff9NG$$p*aEKJRd*y{GM1Ar*+c_4B85M+*gVJ^VKijyYjaWAUO2vpn?JH!*~U8@m;I8g>K*0 zTKs^(jr}PAojPkojqqS__as+-iFRc*E%^Z0?4xS`cD>Hi*h` zZvaS2KvI&8_S*4`aLM_l`_0$orzKxl?(w5gx}Qz`P{*qi&){e&zcXT^6in6`z`V(a zvvD0X`Oj|Q*IAp6vwWD2dBQpu1qIhIa|}ag^r(B|FV}WYZC(V_&8Gu7@)HYP=p(BbvVXA{y<&2{tSUlt>>wCdo z@z`N01d$3N-}Vd~agfi5QhxhhC)d#2={R$U`2{5+$BJhvBNsJ3Th9ivN?z(Oe|Z(} z#q!wTaEV;P>4(C`ltb&lKXtP0q9kqiAcuLO$J^d|8njhRqYLO@Tr5$y;-aN^(8Fe? zky;X7+}bhIfh|2kbHJK?&it`Ba3;-wM*Z^)-IHV|q~RZHZ*#qUD{)FSM)a-5$h%z> z_RzBZ+OQkiKb>0pLZSYvTT_e5&lfX#3JPw|mp!%0U+s!qnIA2&Y<+!3;8i3xy1%Q@ zWuWb&YEMU()F0}wgP;=pG4Eb-|3h%gE5Zo&C#o6>D|Zp?7UN($ejE<->grD;v0q4JQXERJ1K29mTFsb?2v9E8x#BAwgZ# zy9`-)^nTmS_5@pVPolYXpUXnnv4k{-i4Lx8-&DMDW7!{(aog@*a_*ez21|!YrPKF5 zGujW+q^{7lT z4(#_n>U|;L?~jq6Gus0ri%BgoUr0xyT{X^1`F=T*vj=ZJ;3;oO_n;#ryo9~?_rq`B zw3YIeK3a`GNaPd@ov#YNr!x~J+5d_5Ikoqg0d*P*@6}~UMn=!Uu#-_F9zazre94#NN{VCwWPO zHwgCLyKtBzV@7bP>^8w&PGc=q1>@0(ix2R`O()GPp>WHc|G&K-{}IJ+)%=er{v!%F zO4|(9f3)I1TJb+bD?B?$Wp{rN4FkNhbHatKeiP~s8FK3EtHh`SA_^!_Vg%hi!- zLj0+i#`)t!XVoe+hSZ$N-n+bbv{&!4XX#TOI#=!*7rsPw*?R2L(B;g5Y!eyhu~58F zgqRFMD(F4jtA1OYABm~XF~qO<H%ftt_p9gmM(^Eg4m>vG%WW`X2} z)3c!RPkFk8taGQlU$AftUq7)W@z-1-v2150A_^Q`3Sk6bmm`Q!9fqa+9m80>kaVAm zA{V2OOd9R|q6(ua9Xl4=$UWC*jxo4BwJK~IrPjYHqNlIF71W&ChXg$~%a$ZgW|6Sm zRJiJ+d2$V=H`1bbaU}mmW+r(pe5}W=J<|0R`{<=|H$&yq@US+qYXe?u!IwEI zIQ5VG{eGaR2ESsoqKH02V~EkLw#8^ote&p##K`qY;tvLf75bA0Ud!`K2+u-dUxlID zywQv2+$3@w_;#t(cIj*#m-ByxZKTcC)-tfFVe2Q`b={rfS03EKmu{Tox{EkN472Q$ z@Rz)3)}DgXLS{>JgffihZC30tfz#tR
Rf7EVQbpvp8Y* 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

oLj^>l81ru47Iu%6ZT}D?h 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%0AX4YboE@DcMj&jj%&PZ%-)A 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

LFY&ZBrBzz-L?f!!E@LfC2}^CnlC2;-R&D5 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

  • Y!i(cG*66dOzMm-DPeBMM{PAL8CL&xN#6FB03X_ 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

    K^c(^slMBgioNzDDX)bV*~*$Vg1ZE_#P$%uhd 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 z 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

    1{t}HMRA$dWNPiF zTmY;hH|@T#ojDQyV3=n+`g6EWk5_gOr;1F+Nt+yj^{?dA=^XcWQnQE$Zj}aUZJIi4 zjW=&TZ@HYXwd~!)S(_iyUEpFX<@|~Dwv@p!&*epzQ0yJGZvkTq%0$U+3x=B8BOa87 zBj4`d6D4bJI(|)-HNYdc8jI(7`l;J2L-L}xsPl|#QRIEDG53yY*c%UbtE$#rGB8Tg z?>#;n%k1e(;m3OC$ePRd%F5laU@7NJ{TT!YIF*v_;fP0(;vXd2Bt#Uo;Ndt@Uv;R| z?n@Y+DPv-k`d8*7T;yx=!|cz5OZs1BTw$R=DYG0;pJtyd*5Z2O>_bLsO`N=yqnn~> zDqVTlDDIoZn#5|UK}+liSB5MvE6fTKT|M)?uW8=4>F6Wp_SL8IiuvLP?;kZWhS=MH z#JP;@S=P>mvk&pa@mbqv`bNGT^OP6vh&$2>Pi(xNAML)~6xnTvdM*-(wnV2Xx~){r zkFG}=P2ICHoXiutr~T<9SKMpHIB#QfwmSTpV~9g?F@lFGhzr1YqkfU(YwfQkAD^&2 z|D(%`W$Ep6#nWQ6zdd3tIe7I)bkZ{dBbL7Ft8aDQGHy=vA}(AQy4s0xE?(&{Yu&p4 zI2C<8>9SYS0lwMg5P%r2k%lsnaHBJybLSVmIdSeZQ`BbW3|_i)$tdDhg{1v$?~4Q-~ng4HuQ=a-stX6o-* zDh4QCuN1dp!|v(<=*A{(D)ubhPJI9J7oRWGHf8R8&pA3mLl;74QFZy6BONatB-=}E z&EA;NaZN-sIXJyE)CAD*MN#)!i{bJ%4)MEInr!R%fo+pWJdNmep|QfKV5*77f06rt zCbPCrUKG5}7WE<__GR8iLw0>$X<~Y7@w?2AlX%3(Ra)6}65gFA^>Ulc|CApcZTj#+ zPI+Okn)3S7KKk2qVX5h^4iRX3yGvAA$mNh2x4DU}Ao^3n_C$bMqNXV{l)|XKvwo=B z%-`I|Oj3BlQ#O?98IkuH?gcj;aUNu)kbmD?<*|W#DkZunbM~=^BHEIJmYX7HW&W^N z?VZ$Ar?o|yvR7*XDxEk6DyUY8SkxCgJBrz4QbJqih7%Skir1&V^;WbUzol_VfjEYa zQMz2+VSKYRb*sYH#UvsmCeDgJB3{wzW6}(vZn3qA+I8u{9G-#%FXej{t-^7IC+UuG;nIIx3eTy%(O^qmoqL z@(7O&r~dOYwkQJpO&^INr$M=H)E@3!-(q8QxI}GiDRF!w{ZRGR%3$n`IaHg~Hi~!z zmr^F!UE)@0~Y*uK7U%B^6EJU(uufH+QO@oBklO8@&Q09;wN=8mXy-f|Z2mp7-~SUI0u{G}`;e#~ zp?Lc12=1}Mzoy^T-VY#^?>;INF0=1c4qy~K1Dt}bSS|3-Pe4iP8k{D!!~E$}7&qY+ zdb$OFR>|Y9XHNXfQ#eQ9JSeD?NU!!6ZCtOnjsPDE5Hy{rkHs3;XNRIeu!- zy&@fNPp{O`FX_yh!JUg5OD@Wzz05kSoenT2f;iE zaiPDpVET#oTelAChEm4bPO`8+

    B~jQ@Xj=~o6{*)#%rvYeOZr5- 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 G?*9izA8$DT From 30fb126b63991e8c00108c39210ef0cb17bf4408 Mon Sep 17 00:00:00 2001 From: Trinity Date: Sat, 11 Jan 2025 17:23:16 +0700 Subject: [PATCH 12/53] Update spec --- x/asset/spec/02_state.md | 34 ++++++++++++++---------------- x/asset/spec/03_params.md | 4 ---- x/asset/spec/05_query.md | 21 ------------------- x/asset/spec/06_logic.md | 44 ++++++++++++++++++++------------------- x/asset/spec/README.md | 28 ++++++++++++++----------- 5 files changed, 55 insertions(+), 76 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index ac45452d..c054996a 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -14,7 +14,8 @@ The `x/asset` module keeps the following objects in state: | `Token` | Token information | `[]byte{2} + []byte(id)` | `[]byte{token}` | KV | | `TokenManager` | TokenManager info of a denom | `[]byte{3} + []byte(id)` | `[]byte{token_manager}` | KV | | `TokenDistributor` | TokenDistributor info of a denom | `[]byte{4} + []byte(id)` | `[]byte{token_distributor}`| KV | -| `FrozenAddresses` | Frozen Addresses bytecode | `[]byte{5} + []byte(id)` | `[]byte{[]address}` | KV | +| `WhitelistAddresses` | Whitelist Addresses bytecode | `[]byte{5} + []byte(id) + []byte(address)` | `[]byte{bool}` | KV | +| `DynamicPrecompiles` | Dynamic Contract Precompiles bytecode | `[]byte{6} + []byte(id) + []byte(address)` | `[]byte{bool}` | KV | ### Token @@ -28,6 +29,7 @@ type Token struct { Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + EVMAddress common.Address `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` } ``` @@ -35,10 +37,12 @@ The token id for the token will be derived from the Issuer and the Symbol with t The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). -### TokenManager +When create the token, `asset` module auto generate for it a evm address. This address is used as a dynamic precompiles. + +### TokenManagement ```go -type TokenManager struct{ +type TokenManagement struct{ Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` AllowNewExtensions bool `protobuf:"varint,10,opt,name=allow_new_Extensions,json=allowNewExtensions,proto3" json:"allow_new_Extensions,omitempty"` ExtensionsList []string `protobuf:"bytes,11,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` @@ -48,27 +52,21 @@ type TokenManager struct{ By setting `allow_new_extensions`, `issuer` can specify whether they accept new extensions or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `extensions_list`and the `manager` can then modify the `extensions_list` as he sees fit. Otherwise, the `manager` can not chaing the `extensions_list`. -### TokenDistributor +### TokenDistribution ```go -type TokenDistributor struct{ - Distributors []string `protobuf:"bytes,8,rep,name=distributors,proto3" json:"distributors,omitempty"` - DistributionSettings DistributionSettings `protobuf:"bytes,12,opt,name=distribution_settings,json=distributionSettings,proto3" json:"distribution_settings"` +type TokenDistribution struct{ + Distributors []string + MaxSupply math.Int } ``` -### DistributionSettings +`MaxSupply` defines the maximum number of tokens can be minted. -```go -type DistributionSettings struct{ - MaxSupply math.Int - MaxRatelimit math.Int -} -``` +### WhitelistAddresses -`MaxSupply` defines the maximum number of tokens can be minted. -`MaxRatelimit` defines the ratelimit of tokens can be minted per epoch (each epoch last 1 day). +`WhitelistAddresses` is a list of the address that's allow to create new token. -### FrozenAddress +### DynamicPrecompiles -List of addresses that is frozen by the manager. This only exists when the Token enable the `freeze` functionality. The addresses in list will not be able to execute any msg about the token. +`DynamicPrecompiles` is a list of the EVM precompile addresses. diff --git a/x/asset/spec/03_params.md b/x/asset/spec/03_params.md index 9cad431a..c7a05497 100644 --- a/x/asset/spec/03_params.md +++ b/x/asset/spec/03_params.md @@ -9,11 +9,7 @@ The asset module contains the following parameters: | Key | Type | Example | |----------------------|---------------|------------------------| | AllowExtensions | []string | ["burn","freeze"] | -| RatelimitDuration | time.Duration | "86400s" | -| WhitelistAddresses | []address | ["realio1..."] | ## Details - AllowExtensions: list of extensions that the module provides. They can be update after the chain upgrade to enable new extension add-on to the module. -- RatelimitDuration: duration of ratelimit for `mint` extension. -- WhitelistAddresses: list of the address that's allow to create new token. diff --git a/x/asset/spec/05_query.md b/x/asset/spec/05_query.md index 8faec520..5f7c6522 100644 --- a/x/asset/spec/05_query.md +++ b/x/asset/spec/05_query.md @@ -79,24 +79,3 @@ CLI: ```bash realio-networkd q all-tokens ``` - -## 4. QueryFrozenAddresses - -The `QueryFrozenAddresses` allows users to query all frozen addresses - -```go - type QueryFrozenAddressesRequest struct { - } -``` - -```go - type QueryFrozenAddressesResponse struct { - FrozenAddresses []address - } -``` - -CLI: - -```bash - realio-networkd q frozen-addresses -``` diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 59a636cf..ba280ec3 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -6,61 +6,63 @@ order: 6 This file describes the core logics in this module. -## Functionality +## Extension -### Register new functionality +### Register new extension -To intergrate with the `asset module` Each type of functionality has to implement this interface +To intergrate with the `asset module` Each type of extension has to implement this interface ```go -type Functionality interface { +type Extension interface { RegisterInterfaces() MsgHandler() MsgHandler QueryHandler() QueryHandler CLI() *cobra.Command } -type MsgHandler func(context Context, funcMsg FunctionalityMsg) error +type MsgHandler func(context Context, funcMsg ExtensionMsg) error -type QueryHandler func(context Context, funcQuery FunctionalityMsg) error +type QueryHandler func(context Context, funcQuery ExtensionMsg) error ``` -This interface provides all the functionality necessary for a functionality, including a message handler, query handler and cli +This interface provides all the extension necessary for a extension, including a message handler, query handler and cli. -All the `FunctionalityMsg` of a functionality should return the name of that functionality when called `FunctionalityName()`. A message handler should handle all the `FunctionalityMsg` of that functionality. +All the `ExtensionMsg` of a extension should return the name of that extension when called `ExtensionName()`. A message handler should handle all the `ExtensionMsg` of that extension. -### Upgrade Functionalities +### Upgrade Extensions -All functionalities are located in a seperate packages, for example: asset/functionalities, therefore the exentsion or upgrade of functionalities is unrelated to core logic of `Asset` module, all the modification and addition happen in only asset/functionalities package. The core Asset module does not need to be aware of the specifics of functionality handling. It interacts with functionalitys through defined interfaces or protocols. +All extensions are located in a seperate packages, for example: asset/extensions, therefore the exentsion or upgrade of extensions is unrelated to core logic of `Asset` module, all the modification and addition happen in only asset/extensions package. The core Asset module does not need to be aware of the specifics of extension handling. It interacts with extensions through defined interfaces or protocols. -Each Priviliges has their own proto to define their state and execute/query messages. By assigning a distinct proto to each functionality, you ensure that the logic, messages, and data associated with one functionality do not interfere with or complicate the others. This also makes the design easier to understand, maintain, and scale. +Each Extensions has their own proto to define their state and execute/query messages. By assigning a distinct proto to each extension, you ensure that the logic, messages, and data associated with one extension do not interfere with or complicate the others. This also makes the design easier to understand, maintain, and scale. -When adding a `Functionality`, we calls `FunctionalityManager.AddFunctionality()` in `app.go` which inturn maps all the `FunctionalityMsg` of that functionality to its `MsgHandler`. This mapping logic will later be used when running a `MsgExecuteFunctionality`. +When adding a `Extension`, we calls `ExtensionRouting.AddExtension()` in `app.go` which inturn maps all the `ExtensionMsg` of that extension to its `MsgHandler`. This mapping logic will later be used when running a `MsgExecuteExtension`. ### Message/Query routing -The message we pass in `ExecuteFunctionality` is `msg.Any` type. This type refered that it could be any type of message. +The message we pass in `ExecuteExtension` is `msg.Any` type. This type refered that it could be any type of message. After receive this message, we will unpack the `msg.Any` type to an interface which implements what we want: ```go -type FunctionalityMsg interface { - FunctionalityName() string +type ExtensionMsg interface { + ExtensionName() string } ``` -As we defined the `AllowFunctionalities` in Params. If the message name is in the list, they will also exist there own interface in `FunctionalityRouting`. +As we defined the `AllowExtensions` in Params. If the message name is in the list, they will also exist there own interface in `ExtensionRouting`. -`FunctionalityRouting` acts as a centralized hub for routing messages, making it easy to manage and audit the flow of messages in the system. -It will route the `FunctionalityMsg` to its `MsgHandler` - where the msg is executed. In the `MsgHandler`, the message is further routed based on its type to the correct execution logic. This additional layer of routing within the MsgHandler ensures precise handling through message types, enabling fine-grained control and execution workflows. +`ExtensionRouting` acts as a centralized hub for routing messages, making it easy to manage and audit the flow of messages in the system. +It will route the `ExtensionMsg` to its `MsgHandler` - where the msg is executed. In the `MsgHandler`, the message is further routed based on its type to the correct execution logic. This additional layer of routing within the MsgHandler ensures precise handling through message types, enabling fine-grained control and execution workflows. -This flow will also work with `QueryHandler`, as long as we can unpack the `msg.Any` and get the name of the functionality. +This flow will also work with `QueryHandler`, as long as we can unpack the `msg.Any` and get the name of the extension. + +### Extension Store ## EVM interaction ### Enable EVM interface -The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module's predefined precompiles, where the token’s core state and functionalities are managed. +The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module's predefined precompiles, where the token’s core state and extensions are managed. -The token itself exists as a coin within the bank state, maintaining its own logic and functionalities independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. +The token itself exists as a coin within the bank state, maintaining its own logic and extensions independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. ### ERC20 Precompiles diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 8871d2d7..1a34816e 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -11,9 +11,9 @@ parent: 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 two different roles, manager and distributor. These roles can be assigned to arbitrary accounts (could be either user accounts or module/contract account) by the token issuer. -Each token can choose to enable functionalities supported by the module. Currently, there are four functionalities supported: "mint", "freeze", "clawback", "transfer_auth", each handle a completely different logic. We wanna decouple the logic of these functionalities from the `Asset module`, meaning that they will be defined in separate packages/modules, thus, developers can customize new functionalities without modifying the `Asset Module`. Doing this allows our token model to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we integrating new features. +Each token can choose to enable extensions supported by the module. Currently, there are four extensions supported: "mint", "freeze", "clawback", "transfer_auth", each handle a completely different logic. We wanna decouple the logic of these extensions from the `Asset module`, meaning that they will be defined in separate packages/modules, thus, developers can customize new extensions without modifying the `Asset Module`. Doing this allows our token model to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we integrating new features. -The token manager's task is to choose what functionalities it wants to disable/enable for its token; and only the token manager can trigger those functionalities, except for the `mint` functionality which is handled by the `distributor`. +The token manager's task is to choose what extensions it wants to disable/enable for its token; and only the token manager can trigger those extensions, except for the `mint` extension which is handled by the `distributor`. ![asset_module](imgs/asset_module.png) @@ -27,9 +27,9 @@ To link an asset to ERC20 Precompile, user have to create a gov proposal so that ![asset_precompiles](imgs/asset_precompiles.png) -### Mapping functions +### Mapping extensions -ERC20 precompiles come with a limited number of functions which are: +ERC20 precompiles come with a limited number of extensions which are: - Transfer - TransferFrom @@ -37,9 +37,9 @@ ERC20 precompiles come with a limited number of functions which are: - IncreaseAllowance - DecreaseAllowance -These functions can be called from both AssetModule and EVM side (by metamask for example). +These extensions can be called from both AssetModule and EVM side (by metamask for example). -Other functions like: +Other extensions like: - Mint - Burn @@ -52,11 +52,15 @@ can only be called from Asset Module side. 1. **[Concept](01_concepts.md)** 2. **[State](02_state.md)** - - [Minter](02_state.md#minter) - - [Params](02_state.md#params) + - [Token](02_state.md#token) + - [TokenManagement](02_state.md#tokenmanagement) + - [TokenDistribution](02_state.md#tokendistribution) + - [WhitelistAddresses](02_state.md#whitelistaddresses) + - [DynamicPrecompiles](02_state.md#dynamicprecompiles) 3. **[Parameters](03_params.md)** 4. **[Messages](04_msgs.md)** -5. **[Client](05_client.md)** - - [CLI](05_client.md#cli) - - [gRPC](05_client.md#grpc) - - [REST](05_client.md#rest) +5. **[Query](05_query.md)** +6. **[Logic](06_logic.md)** + - [Extension](06_logic.md#extension) + - [EVM interaction](06_logic.md#evm-interaction) + \ No newline at end of file From 98c8e915811cd949d14e7ec2aef8c7d467cb504b Mon Sep 17 00:00:00 2001 From: lacsomot Date: Mon, 13 Jan 2025 15:14:18 +0700 Subject: [PATCH 13/53] update spec --- x/asset/spec/01_concepts.md | 4 ++-- x/asset/spec/02_state.md | 24 ++++++++++++---------- x/asset/spec/04_msgs.md | 15 +++++++------- x/asset/spec/06_logic.md | 16 ++++++++++----- x/asset/spec/README.md | 12 +++++------ x/asset/spec/imgs/linking_precompiles.png | Bin 0 -> 44445 bytes 6 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 x/asset/spec/imgs/linking_precompiles.png diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index ed473ff0..6bfa9bff 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -10,7 +10,7 @@ The Realio Asset module is centered around a token model where certain whitelist ### System of privileged accounts -Privileged accounts of a token are accounts that can execute certain actions for that token. There're are several types of extensions, each has its own logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these extensions from the `Asset module` logic, meaning that extensions will be defined in separate packages/modules, thus, developers can customize their type of extension without modifying the `Asset Module`. Doing this allows our extensions system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our extensions system. +Privileged accounts of a token are accounts that can execute certain actions for that token. There're are several types of extensions, each has its own state and logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these extensions from the `Asset module` logic, meaning that extensions will be defined in separate packages/modules, thus, developers can customize their type of extension without modifying the `Asset Module`. Doing this allows our extensions system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our extensions system. In order for a extension to integrate into the `Asset Module`. It has to implement the `Extension` interface and has its implementation registered via the method `AddExtension`. Once that is done, we can make said extension available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process. @@ -20,4 +20,4 @@ Currently, there are 2 type of privileged accounts: `manager` and `distributor`. While it is useful to represent the token in bank module, enabling the token to be in action in evm environment is very convenient and pave the possibility of integrating new features into the ecosystem. -Each token can be enabled to work in the evm environment by the token manager, which means user can interact with the token through evm side like metamask or anyother evm wallet and more other protocol integrated in the future. Note that, token manager can disable or enable the token to be used in the evm environment. +Each token is automatically enabled to work in the evm environment when created, which means user can interact with the token through evm side like metamask or anyother evm wallet and more other protocol integrated in the future. diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index c054996a..1e5d4ce2 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -8,14 +8,14 @@ order: 2 The `x/asset` module keeps the following objects in state: -| State Object | Description | Key | Value | Store | -|----------------------|----------------------------------------|--------------------------| ---------------------------|-------| -| `Params` | Params of asset module | `[]byte{1}` | `[]byte(params)` | KV | -| `Token` | Token information | `[]byte{2} + []byte(id)` | `[]byte{token}` | KV | -| `TokenManager` | TokenManager info of a denom | `[]byte{3} + []byte(id)` | `[]byte{token_manager}` | KV | -| `TokenDistributor` | TokenDistributor info of a denom | `[]byte{4} + []byte(id)` | `[]byte{token_distributor}`| KV | -| `WhitelistAddresses` | Whitelist Addresses bytecode | `[]byte{5} + []byte(id) + []byte(address)` | `[]byte{bool}` | KV | -| `DynamicPrecompiles` | Dynamic Contract Precompiles bytecode | `[]byte{6} + []byte(id) + []byte(address)` | `[]byte{bool}` | KV | +| State Object | Description | Key | Value | Store | +|----------------------|----------------------------------------|-----------------------------------------------------------|---------------------------------------|-------| +| `Params` | Params of asset module | `[]byte{1}` | `[]byte(params)` | KV | +| `Token` | Token information | `[]byte{2} + []byte(token_id)` | `[]byte{token}` | KV | +| `TokenManagement` | TokenManagement info of a denom | `[]byte{3} + []byte(token_id)` | `[]byte{token_manager}` | KV | +| `TokenDistribution` | TokenDistribution info of a denom | `[]byte{4} + []byte(token_id)` | `[]byte{token_distributor}` | KV | +| `WhitelistAddresses` | Whitelist Addresses | `[]byte{5} + []byte(address)` | `[]byte{bool}` | KV | +| `ExtenstionStore` | State store for each extensions | `[]byte{6} + []byte(token_id) + []byte(extension_name)` | Depend on extension implementation | KV | ### Token @@ -65,8 +65,10 @@ type TokenDistribution struct{ ### WhitelistAddresses -`WhitelistAddresses` is a list of the address that's allow to create new token. +`WhitelistAddresses` is a list of the address that's allow to create new asset. -### DynamicPrecompiles +### ExtenstionStore -`DynamicPrecompiles` is a list of the EVM precompile addresses. +Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed. + +Each extension store has its own namespace, which is defined by token identifiers and extension name, which means that a combination of token and extension will create a new substore derived from the Asset module store. \ No newline at end of file diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 53da4436..78de9bdf 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -16,7 +16,6 @@ order: 4 Symbol string Decimal uint32 Description string - EvmEnable bool AllowNewExtensions bool ExtensionsList [ ]string } @@ -40,9 +39,8 @@ Example token.json: "Manager": ["realioabc..."], "Distributor": ["realioabc2..."], "Symbol": "riel", - "Decimal": "rielio", + "Decimal": 18, "Description": "", - "EvmEnable": true, "AllowNewExtensions": true, "ExtensionsList": [], } @@ -56,8 +54,9 @@ Validation: Flow: -1. The denom for the token will be derived from Creator and Symbol with the format of asset/{Issuer}/{Symbol-Lowercase} -2. If `EvmEnable` is true, create a dynamic precompiles for the token. +1. The token-id for the token will be derived from Creator and Symbol with the format of asset/{Issuer}/{Symbol-Lowercase} +2. Create a evm address for the asset. +3. Create a dynamic precompiles linking to the newly created evm address. 3. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store 4. Save the token management info and distribution info in the x/asset store. @@ -191,12 +190,12 @@ Validation: Flow: - Get `TokenDistributor` from store by token_id -- Mint the asset for corresponding reciever -- Increase the ratelimit +- Mint the asset for corresponding receiver +- Increase the Maxsupply in TokenDistribution store. ### 6. UpdateDistributionSetting -Distributor can change the max supply and mint ratelimit of the token. +Distributor can change the max supply of the token. ```go type MsgUpdateDistributionSetting struct { diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index ba280ec3..41ffc25d 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -20,9 +20,9 @@ type Extension interface { CLI() *cobra.Command } -type MsgHandler func(context Context, funcMsg ExtensionMsg) error +type MsgHandler func(context Context, extensionStore store.KVStore, funcMsg ExtensionMsg) error -type QueryHandler func(context Context, funcQuery ExtensionMsg) error +type QueryHandler func(context Context, extensionStore store.KVStore, funcQuery ExtensionMsg) error ``` This interface provides all the extension necessary for a extension, including a message handler, query handler and cli. @@ -57,12 +57,18 @@ This flow will also work with `QueryHandler`, as long as we can unpack the `msg. ### Extension Store +Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed and altered on execution. + +This structure help the extension achieve the isolation characteristic of the store, which helps maintain modularity and reduces the risk of unintended interactions or dependencies between extensions. + ## EVM interaction -### Enable EVM interface +### EVM interface -The token includes a field named `evm_enable`, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module's predefined precompiles, where the token’s core state and extensions are managed. +On token creation, all token will be linked to a erc20-precompiles, which allows it to integrate with the ERC20 standard and have an EVM-compatible contract address. This EVM address acts as an abstract interface layer that bypasses the typical logic within ERC20 or EVM contracts. Instead of executing logic directly in the contract, all actions are reflected to the `asset` module's predefined precompiles, where the token’s core state and extensions are managed. -The token itself exists as a coin within the bank state, maintaining its own logic and extensions independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile` when `evm_enable` is activated, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. +The token itself exists as a coin within the bank state, maintaining its own logic and extensions independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile`, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. ### ERC20 Precompiles + + diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 1a34816e..5bedd932 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -15,7 +15,7 @@ Each token can choose to enable extensions supported by the module. Currently, t The token manager's task is to choose what extensions it wants to disable/enable for its token; and only the token manager can trigger those extensions, except for the `mint` extension which is handled by the `distributor`. -![asset_module](imgs/asset_module.png) +![asset_module](imgs/asset_module.png)` ## Asset Module and ERC-20 Precompiles @@ -23,9 +23,9 @@ ERC-20 precompiles are offered by evmOS for better interacting with Cosmos SDK. ### Link Asset to Precompiles -To link an asset to ERC20 Precompile, user have to create a gov proposal so that Asset Module can interact with ERC-20 module to registerERC20 and change their params (`Dynamic Precompiles` field). After linking, all call to the token contract will now redirect to precompile instead of the evm. +To link an asset to ERC20 Precompile, when issuer send the MsgIssueToken to the Asset Module, a new asset will be created and a new evm address is created randomly, which will be auto assigned an erc20-precompiles to interact with evm environment. After linking, all call to the token contract will now redirect to precompile instead of the evm. -![asset_precompiles](imgs/asset_precompiles.png) +![asset_precompiles](imgs/linking_precompiles.png) ### Mapping extensions @@ -37,14 +37,12 @@ ERC20 precompiles come with a limited number of extensions which are: - IncreaseAllowance - DecreaseAllowance -These extensions can be called from both AssetModule and EVM side (by metamask for example). - -Other extensions like: +We introduce additional extensions on these standard extensions: - Mint - Burn -can only be called from Asset Module side. +All above extensions can be called from both AssetModule and EVM side (by metamask for example). ![asset_evm](imgs/asset_evm.png) diff --git a/x/asset/spec/imgs/linking_precompiles.png b/x/asset/spec/imgs/linking_precompiles.png new file mode 100644 index 0000000000000000000000000000000000000000..11480b35a7258bf2f32ba9100229791e04a2bef5 GIT binary patch literal 44445 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 Q?_dA|Pgg&ebxsLQ09I*btN;K2 literal 0 HcmV?d00001 From 0311dab72c32459d0785f24ccceebc9fbc30eb8a Mon Sep 17 00:00:00 2001 From: Trinity Date: Tue, 14 Jan 2025 11:36:01 +0700 Subject: [PATCH 14/53] Add precompile to logic --- x/asset/spec/02_state.md | 2 +- x/asset/spec/04_msgs.md | 9 +++++---- x/asset/spec/06_logic.md | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 1e5d4ce2..bf9d03d1 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -71,4 +71,4 @@ type TokenDistribution struct{ Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed. -Each extension store has its own namespace, which is defined by token identifiers and extension name, which means that a combination of token and extension will create a new substore derived from the Asset module store. \ No newline at end of file +Each extension store has its own namespace, which is defined by token identifiers and extension name, which means that a combination of token and extension will create a new substore derived from the Asset module store. diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 78de9bdf..34dcc3c2 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -13,10 +13,11 @@ order: 4 Issuer address Managers [ ]address Distributors [ ]address + Name string Symbol string Decimal uint32 Description string - AllowNewExtensions bool + AllowNewExtensions bool ExtensionsList [ ]string } ``` @@ -55,10 +56,10 @@ Validation: Flow: 1. The token-id for the token will be derived from Creator and Symbol with the format of asset/{Issuer}/{Symbol-Lowercase} -2. Create a evm address for the asset. +2. Create a evm address for the asset. 3. Create a dynamic precompiles linking to the newly created evm address. -3. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store -4. Save the token management info and distribution info in the x/asset store. +4. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store +5. Save the token management info and distribution info in the x/asset store. ## 2. AssignRoles diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 41ffc25d..37b2cf66 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -57,7 +57,7 @@ This flow will also work with `QueryHandler`, as long as we can unpack the `msg. ### Extension Store -Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed and altered on execution. +Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed and altered on execution. This structure help the extension achieve the isolation characteristic of the store, which helps maintain modularity and reduces the risk of unintended interactions or dependencies between extensions. @@ -69,6 +69,38 @@ On token creation, all token will be linked to a erc20-precompiles, which allows The token itself exists as a coin within the bank state, maintaining its own logic and extensions independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile`, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. -### ERC20 Precompiles +### EVM Precompiles +EVM precompiles are EVM interface contracts with state access. These smart contracts can directly interact with Cosmos SDK modules, enabling their own operations while also interacting with the EVM state and other SDK modules. +In `asset` module, there are 2 evm precompiles contracts: `ITokenIssuer.sol` corresponding to `token-issuer` precompile and `IERC20Extension.sol` corresponding to `erc20` precompile. + +The `token-issuer` precompile provides a single function in `ITokenIssuer.sol` that enables other contracts or users to create an ERC20 token. The function is defined as follows: + +```solidity + function issueToken( + address issuerAddress, + string memory name, + string memory symbol, + uint8 deciaml, + bool allowNewExtensions, + string[] memory extensionsList + ) external returns (bool success, address contractAddress); +``` + +When this function is called, the token-issuer precompile forwards the request to the asset module, invoking the IssueToken function within the module to handle the token creation process. + +On the other hand, the `erc20` precompile acts as the ERC20 interface for all tokens managed by the asset module. It implements all standard ERC20 functions as defined in `IERC20Extension.sol`, including `transfer`, `transferFrom`, `approve`, `increaseAllowance`, and `decreaseAllowance`. + +Additionally, the `IERC20Extension.sol` contract provides extra methods to support interactions with other extensions, enabling more advanced functionality: + +```solidity + function mint(address to, uint256 amount) public; + + function burn(uint256 value) public; + function burnFrom(address account, uint256 value) public; + + function freeze(address account) public; + + function updateExtensionList(string[] memory newExtensionsList) public; +``` From eb346d748b3794fa954e1d3bd7d1e9e78d99bdc0 Mon Sep 17 00:00:00 2001 From: Trinity Date: Tue, 14 Jan 2025 15:27:12 +0700 Subject: [PATCH 15/53] Update precompiles spec for isolate interacting with asset module --- x/asset/spec/04_msgs.md | 6 +++--- x/asset/spec/06_logic.md | 30 ++++++++++++++++++++++++------ x/asset/spec/README.md | 1 - 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 34dcc3c2..65e0db41 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -116,10 +116,10 @@ Flow: - Get `TokenManager` and `TokenDistributor` from store by token_id - Loop through addresses and append manager addresses to `TokenManager.Managers`, distributor addresses to `TokenDistributor.Distributors` -## 3. UnassignRole +## 3. UnassignRoles ```go - type MsgUnassignRole struct { + type MsgUnassignRoles struct { TokenId string Issuer address Assigners []address @@ -127,7 +127,7 @@ Flow: ``` ```go - type MsgUnassignRoleResponse struct { + type MsgUnassignRolesResponse struct { } ``` diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 37b2cf66..f8fe648a 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -73,9 +73,18 @@ The token itself exists as a coin within the bank state, maintaining its own log EVM precompiles are EVM interface contracts with state access. These smart contracts can directly interact with Cosmos SDK modules, enabling their own operations while also interacting with the EVM state and other SDK modules. -In `asset` module, there are 2 evm precompiles contracts: `ITokenIssuer.sol` corresponding to `token-issuer` precompile and `IERC20Extension.sol` corresponding to `erc20` precompile. +In `asset` module, there are 2 evm precompiles contracts: `IAsset.sol` corresponding to `asset` precompile and `IERC20Extensions.sol` corresponding to `erc20` precompile. -The `token-issuer` precompile provides a single function in `ITokenIssuer.sol` that enables other contracts or users to create an ERC20 token. The function is defined as follows: +The `IAsset.sol` is an interface through which Solidity contracts can interact with Realio asset module. This is convenient for developers as they don’t need to know the implementation details behind the `x/asset` module in the Realio Network. Instead, they can interact with `asset` functions using the Ethereum interface they are familiar with. + +`asset` precompile provides several functions: + +- `issueToken` enables other contracts or users to create an ERC20 token. +- `updateExtensionsList` allow token manager to interact to `asset` module and update the extensions list. +- `assignRoles` allow token issuer to assign role for token. +- `unassignRoles` allow token issuer to unassign role for token. + +The functions is defined as follows: ```solidity function issueToken( @@ -86,13 +95,24 @@ The `token-issuer` precompile provides a single function in `ITokenIssuer.sol` t bool allowNewExtensions, string[] memory extensionsList ) external returns (bool success, address contractAddress); + + function updateExtensionsList(string memory tokenId, string[] memory newExtensionsList) public; + + struct Role { + uint8 role; // 1 represent manager, 2 represent distributor + address account; + } + + function assignRoles(string memory tokenId, Role[] roles) public; + + function unassignRoles(string memory tokenId, address[] accounts) public; ``` When this function is called, the token-issuer precompile forwards the request to the asset module, invoking the IssueToken function within the module to handle the token creation process. -On the other hand, the `erc20` precompile acts as the ERC20 interface for all tokens managed by the asset module. It implements all standard ERC20 functions as defined in `IERC20Extension.sol`, including `transfer`, `transferFrom`, `approve`, `increaseAllowance`, and `decreaseAllowance`. +On the other hand, the `erc20` precompile acts as the ERC20 interface for all tokens managed by the asset module. It implements all standard ERC20 functions as defined in `IERC20Extensions.sol`, including `transfer`, `transferFrom`, `approve`, `increaseAllowance`, and `decreaseAllowance`. -Additionally, the `IERC20Extension.sol` contract provides extra methods to support interactions with other extensions, enabling more advanced functionality: +Additionally, the `IERC20Extensions.sol` contract provides extra methods to support interactions with other extensions, enabling more advanced functionality: ```solidity function mint(address to, uint256 amount) public; @@ -101,6 +121,4 @@ Additionally, the `IERC20Extension.sol` contract provides extra methods to suppo function burnFrom(address account, uint256 value) public; function freeze(address account) public; - - function updateExtensionList(string[] memory newExtensionsList) public; ``` diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 5bedd932..1999c6be 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -61,4 +61,3 @@ All above extensions can be called from both AssetModule and EVM side (by metama 6. **[Logic](06_logic.md)** - [Extension](06_logic.md#extension) - [EVM interaction](06_logic.md#evm-interaction) - \ No newline at end of file From fc22983ea75538b56c31e60a097c2776ed702edd Mon Sep 17 00:00:00 2001 From: Trinity Date: Wed, 15 Jan 2025 11:31:07 +0700 Subject: [PATCH 16/53] Rewrite msg for new asset module --- proto/realionetwork/asset/v1/params.proto | 5 +- proto/realionetwork/asset/v1/query.proto | 20 - proto/realionetwork/asset/v1/token.proto | 41 +- .../asset/v1/tokenauthorization.proto | 13 - proto/realionetwork/asset/v1/tx.proto | 72 +- x/asset/client/cli/query.go | 28 - x/asset/client/cli/query_params.go | 35 - x/asset/client/cli/query_tokens.go | 59 - x/asset/client/cli/tx.go | 36 - x/asset/client/cli/tx_authorize_address.go | 44 - x/asset/client/cli/tx_create_token.go | 53 - x/asset/client/cli/tx_msg_create_token.go | 53 - x/asset/client/cli/tx_msg_update_token.go | 48 - x/asset/client/cli/tx_transfer_token.go | 51 - x/asset/client/cli/tx_un_authorize_address.go | 44 - x/asset/client/cli/tx_update_token.go | 48 - x/asset/exported/exported.go | 18 - x/asset/genesis.go | 45 - x/asset/genesis_test.go | 75 - x/asset/keeper/grpc_query.go | 80 - x/asset/keeper/grpc_query_test.go | 112 - x/asset/keeper/keeper.go | 38 +- x/asset/keeper/keeper_test.go | 99 - x/asset/keeper/migrator.go | 29 - x/asset/keeper/msg_server.go | 120 +- .../keeper/msg_server_authorize_address.go | 46 - x/asset/keeper/msg_server_create_token.go | 83 - x/asset/keeper/msg_server_token_test.go | 408 ---- x/asset/keeper/msg_server_transfer_token.go | 63 - .../keeper/msg_server_transfer_token_test.go | 135 -- .../keeper/msg_server_un_authorize_address.go | 46 - x/asset/keeper/msg_server_update_token.go | 48 - x/asset/keeper/restrictions.go | 56 - x/asset/keeper/restrictions_test.go | 77 - x/asset/migrations/v2/migrate.go | 38 - x/asset/migrations/v2/migrator_test.go | 51 - x/asset/module.go | 190 -- x/asset/types/codec.go | 43 - x/asset/types/errors.go | 13 +- x/asset/types/events.go | 8 +- x/asset/types/expected_keepers.go | 2 + x/asset/types/genesis.go | 21 - x/asset/types/genesis_test.go | 41 - x/asset/types/keys.go | 14 +- x/asset/types/message_authorize_address.go | 27 - x/asset/types/message_create_token.go | 29 - x/asset/types/message_test.go | 164 -- x/asset/types/message_transfer_token.go | 31 - x/asset/types/message_un_authorize_address.go | 29 - x/asset/types/message_update_token.go | 27 - x/asset/types/msgs.go | 76 + x/asset/types/params.go | 11 +- x/asset/types/params.pb.go | 73 +- x/asset/types/params_legacy.go | 17 - x/asset/types/query.go | 6 - x/asset/types/query.pb.go | 485 +--- x/asset/types/query.pb.gw.go | 123 - x/asset/types/token.go | 80 +- x/asset/types/token.pb.go | 762 ++++++- x/asset/types/tokenauthorization.pb.go | 363 --- x/asset/types/tx.pb.go | 1982 +++++------------ x/asset/types/types.go | 1 - 62 files changed, 1622 insertions(+), 5313 deletions(-) delete mode 100644 proto/realionetwork/asset/v1/tokenauthorization.proto delete mode 100644 x/asset/client/cli/query.go delete mode 100644 x/asset/client/cli/query_params.go delete mode 100644 x/asset/client/cli/query_tokens.go delete mode 100644 x/asset/client/cli/tx.go delete mode 100644 x/asset/client/cli/tx_authorize_address.go delete mode 100644 x/asset/client/cli/tx_create_token.go delete mode 100644 x/asset/client/cli/tx_msg_create_token.go delete mode 100644 x/asset/client/cli/tx_msg_update_token.go delete mode 100644 x/asset/client/cli/tx_transfer_token.go delete mode 100644 x/asset/client/cli/tx_un_authorize_address.go delete mode 100644 x/asset/client/cli/tx_update_token.go delete mode 100644 x/asset/exported/exported.go delete mode 100644 x/asset/genesis.go delete mode 100644 x/asset/genesis_test.go delete mode 100644 x/asset/keeper/grpc_query.go delete mode 100644 x/asset/keeper/grpc_query_test.go delete mode 100644 x/asset/keeper/keeper_test.go delete mode 100644 x/asset/keeper/migrator.go delete mode 100644 x/asset/keeper/msg_server_authorize_address.go delete mode 100644 x/asset/keeper/msg_server_create_token.go delete mode 100644 x/asset/keeper/msg_server_token_test.go delete mode 100644 x/asset/keeper/msg_server_transfer_token.go delete mode 100644 x/asset/keeper/msg_server_transfer_token_test.go delete mode 100644 x/asset/keeper/msg_server_un_authorize_address.go delete mode 100644 x/asset/keeper/msg_server_update_token.go delete mode 100644 x/asset/keeper/restrictions.go delete mode 100644 x/asset/keeper/restrictions_test.go delete mode 100644 x/asset/migrations/v2/migrate.go delete mode 100644 x/asset/migrations/v2/migrator_test.go delete mode 100644 x/asset/module.go delete mode 100644 x/asset/types/codec.go delete mode 100644 x/asset/types/genesis.go delete mode 100644 x/asset/types/genesis_test.go delete mode 100644 x/asset/types/message_authorize_address.go delete mode 100644 x/asset/types/message_create_token.go delete mode 100644 x/asset/types/message_test.go delete mode 100644 x/asset/types/message_transfer_token.go delete mode 100644 x/asset/types/message_un_authorize_address.go delete mode 100644 x/asset/types/message_update_token.go create mode 100644 x/asset/types/msgs.go delete mode 100644 x/asset/types/params_legacy.go delete mode 100644 x/asset/types/query.go delete mode 100644 x/asset/types/tokenauthorization.pb.go delete mode 100644 x/asset/types/types.go diff --git a/proto/realionetwork/asset/v1/params.proto b/proto/realionetwork/asset/v1/params.proto index afdfdcfc..e3ef76ea 100644 --- a/proto/realionetwork/asset/v1/params.proto +++ b/proto/realionetwork/asset/v1/params.proto @@ -6,4 +6,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/realiotech/realio-network/x/asset/types"; // Params defines the parameters for the module. -message Params { option (gogoproto.goproto_stringer) = false; } \ No newline at end of file +message Params { + option (gogoproto.goproto_stringer) = false; + repeated string allow_extensions = 1; +} \ No newline at end of file diff --git a/proto/realionetwork/asset/v1/query.proto b/proto/realionetwork/asset/v1/query.proto index a07a2525..a3a3c427 100644 --- a/proto/realionetwork/asset/v1/query.proto +++ b/proto/realionetwork/asset/v1/query.proto @@ -24,13 +24,6 @@ service Query { rpc Token(QueryTokenRequest) returns (QueryTokenResponse) { option (google.api.http).get = "/realionetwork/asset/v1/tokens/{symbol}"; } - - // Parameters queries the tokens of the module. - rpc IsAuthorized(QueryIsAuthorizedRequest) - returns (QueryIsAuthorizedResponse) { - option (google.api.http).get = - "/realionetwork/asset/v1/isauthorized/{symbol}/{address}"; - } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -62,16 +55,3 @@ message QueryTokenResponse { // params holds all the parameters of this module. Token token = 1 [ (gogoproto.nullable) = false ]; } - -// QueryParamsRequest is request type for the Query/Params RPC method. -message QueryIsAuthorizedRequest { - // symbol is the token symbol to query for. - string symbol = 1; - string address = 2; -} - -// QueryParamsResponse is response type for the Query/Params RPC method. -message QueryIsAuthorizedResponse { - // params holds all the parameters of this module. - bool isAuthorized = 1; -} \ No newline at end of file diff --git a/proto/realionetwork/asset/v1/token.proto b/proto/realionetwork/asset/v1/token.proto index bf455d14..45b2f5ec 100644 --- a/proto/realionetwork/asset/v1/token.proto +++ b/proto/realionetwork/asset/v1/token.proto @@ -2,16 +2,43 @@ syntax = "proto3"; package realionetwork.asset.v1; import "gogoproto/gogo.proto"; -import "realionetwork/asset/v1/tokenauthorization.proto"; option go_package = "github.com/realiotech/realio-network/x/asset/types"; // Token represents an asset in the module message Token { - string name = 1; - string symbol = 2; - string total = 3; - bool authorizationRequired = 4; - string manager = 5; - repeated TokenAuthorization authorized = 6; + string token_id = 1; + string issuer = 2; + string name = 3; + string symbol = 4; + uint32 decimal = 5; + string description = 6; + string evm_address = 9; +} + +// TokenManagement represents the asset manager's execute functions. +message TokenManagement { + repeated string managers = 1; + bool allow_new_extensions = 2; + repeated string extensions_list = 3; +} + +// TokenDistribution represents the asset manager's execute functions. +message TokenDistribution { + repeated string distributors = 1; + string max_supply = 2 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; +} + +enum Role { + option (gogoproto.goproto_enum_prefix) = false; + + // ROLE_UNSPECIFIED defines a no-op role. + ROLE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "EmptyRole"]; + // ROLE_MANAGER defines a token manager role. + ROLE_MANAGER = 1 [(gogoproto.enumvalue_customname) = "ManagerRole"]; + // ROLE_DISTRIBUTOR defines a token distributor role. + ROLE_DISTRIBUTOR = 2 [(gogoproto.enumvalue_customname) = "DistributorRole"]; } \ No newline at end of file diff --git a/proto/realionetwork/asset/v1/tokenauthorization.proto b/proto/realionetwork/asset/v1/tokenauthorization.proto deleted file mode 100644 index 1fef9144..00000000 --- a/proto/realionetwork/asset/v1/tokenauthorization.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; -package realionetwork.asset.v1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/realiotech/realio-network/x/asset/types"; - -// TokenAuthorization represents the current authorization state for an -// address:token -message TokenAuthorization { - string address = 2; - bool authorized = 3; -} \ No newline at end of file diff --git a/proto/realionetwork/asset/v1/tx.proto b/proto/realionetwork/asset/v1/tx.proto index e6e25986..9122e935 100644 --- a/proto/realionetwork/asset/v1/tx.proto +++ b/proto/realionetwork/asset/v1/tx.proto @@ -5,6 +5,7 @@ option go_package = "github.com/realiotech/realio-network/x/asset/types"; import "gogoproto/gogo.proto"; import "realionetwork/asset/v1/params.proto"; +import "realionetwork/asset/v1/token.proto"; import "cosmos_proto/cosmos.proto"; import "cosmos/msg/v1/msg.proto"; @@ -12,62 +13,45 @@ import "cosmos/msg/v1/msg.proto"; service Msg { option (cosmos.msg.v1.service) = true; rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); - rpc CreateToken(MsgCreateToken) returns (MsgCreateTokenResponse); - rpc UpdateToken(MsgUpdateToken) returns (MsgUpdateTokenResponse); - rpc AuthorizeAddress(MsgAuthorizeAddress) - returns (MsgAuthorizeAddressResponse); - rpc UnAuthorizeAddress(MsgUnAuthorizeAddress) - returns (MsgUnAuthorizeAddressResponse); - rpc TransferToken(MsgTransferToken) returns (MsgTransferTokenResponse); // this line is used by starport scaffolding # proto/tx/rpc + rpc CreateToken(MsgCreateToken) returns (MsgCreateTokenResponse); + rpc AssignRoles(MsgAssignRoles) returns (MsgAssignRolesResponse); } message MsgCreateToken { - option (cosmos.msg.v1.signer) = "manager"; - string manager = 1; - string name = 2; - string symbol = 3; - string total = 4; - bool authorizationRequired = 6; -} - -message MsgCreateTokenResponse {} + option (cosmos.msg.v1.signer) = "issuer"; + // issuer is the address that defines the token + string issuer = 1; -message MsgUpdateToken { - option (cosmos.msg.v1.signer) = "manager"; - string manager = 1; - string symbol = 2; - bool authorizationRequired = 3; -} - -message MsgUpdateTokenResponse {} - -message MsgAuthorizeAddress { - option (cosmos.msg.v1.signer) = "manager"; - string manager = 1; - string symbol = 2; - string address = 3; + string name = 2; + uint32 decimal = 3; + string symbol = 4; + string description = 5; + repeated string managers = 6; + repeated string distributors = 7; + bool allow_new_extensions = 8; + repeated string extensions_list = 9; + string max_supply = 10 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; } -message MsgAuthorizeAddressResponse {} - -message MsgUnAuthorizeAddress { - option (cosmos.msg.v1.signer) = "manager"; - string manager = 1; - string symbol = 2; - string address = 3; +message MsgCreateTokenResponse { + string token_id = 1; } -message MsgUnAuthorizeAddressResponse {} +message MsgAssignRoles { + option (cosmos.msg.v1.signer) = "issuer"; + // issuer is the address that defines the token + string issuer = 1; -message MsgTransferToken { - string symbol = 1; - string from = 2; - string to = 3; - string amount = 4; + string token_id = 2; + repeated string managers = 3; + repeated string distributors = 4; } -message MsgTransferTokenResponse {} +message MsgAssignRolesResponse {} message MsgUpdateParams { option (cosmos.msg.v1.signer) = "authority"; diff --git a/x/asset/client/cli/query.go b/x/asset/client/cli/query.go deleted file mode 100644 index cac5ffbe..00000000 --- a/x/asset/client/cli/query.go +++ /dev/null @@ -1,28 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -// GetQueryCmd returns the cli query commands for this module -func GetQueryCmd() *cobra.Command { - // Group asset queries under a subcommand - cmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand(CmdQueryParams()) - cmd.AddCommand(CmdQueryTokens()) - cmd.AddCommand(CmdQueryToken()) - - return cmd -} diff --git a/x/asset/client/cli/query_params.go b/x/asset/client/cli/query_params.go deleted file mode 100644 index abf28d8e..00000000 --- a/x/asset/client/cli/query_params.go +++ /dev/null @@ -1,35 +0,0 @@ -package cli - -import ( - "context" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -func CmdQueryParams() *cobra.Command { - cmd := &cobra.Command{ - Use: "params", - Short: "shows the parameters of the module", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - - res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{}) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/query_tokens.go b/x/asset/client/cli/query_tokens.go deleted file mode 100644 index c2e36b2a..00000000 --- a/x/asset/client/cli/query_tokens.go +++ /dev/null @@ -1,59 +0,0 @@ -package cli - -import ( - "context" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -func CmdQueryTokens() *cobra.Command { - cmd := &cobra.Command{ - Use: "tokens", - Short: "shows the tokens of the module", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - - queryClient := types.NewQueryClient(clientCtx) - - res, err := queryClient.Tokens(context.Background(), &types.QueryTokensRequest{}) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - -func CmdQueryToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "token [symbol]", - Short: "query token by symbol", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - clientCtx := client.GetClientContextFromCmd(cmd) - queryClient := types.NewQueryClient(clientCtx) - params := types.NewQueryTokenRequest(argSymbol) - res, err := queryClient.Token(context.Background(), params) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx.go b/x/asset/client/cli/tx.go deleted file mode 100644 index eecd9b1c..00000000 --- a/x/asset/client/cli/tx.go +++ /dev/null @@ -1,36 +0,0 @@ -package cli - -import ( - "fmt" - "time" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/realiotech/realio-network/x/asset/types" -) - -var DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) - -// GetTxCmd returns the transaction commands for this module -func GetTxCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand(CmdMsgCreateToken()) - cmd.AddCommand(CmdMsgUpdateToken()) - cmd.AddCommand(CmdCreateToken()) - cmd.AddCommand(CmdUpdateToken()) - cmd.AddCommand(CmdAuthorizeAddress()) - cmd.AddCommand(CmdUnAuthorizeAddress()) - cmd.AddCommand(CmdTransferToken()) - // this line is used by starport scaffolding # 1 - - return cmd -} diff --git a/x/asset/client/cli/tx_authorize_address.go b/x/asset/client/cli/tx_authorize_address.go deleted file mode 100644 index 3843c613..00000000 --- a/x/asset/client/cli/tx_authorize_address.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/realiotech/realio-network/x/asset/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdAuthorizeAddress() *cobra.Command { - cmd := &cobra.Command{ - Use: "authorize-address [symbol] [address]", - Short: "Broadcast message AuthorizeAddress", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - argAddress := args[1] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgAuthorizeAddress( - clientCtx.GetFromAddress().String(), - argSymbol, - argAddress, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_create_token.go b/x/asset/client/cli/tx_create_token.go deleted file mode 100644 index 5837afdc..00000000 --- a/x/asset/client/cli/tx_create_token.go +++ /dev/null @@ -1,53 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/spf13/cast" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -var _ = strconv.Itoa(0) - -func CmdCreateToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "create-token [name] [symbol] [total] [authorization-required]", - Short: "Broadcast message CreateToken", - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argName := args[0] - argSymbol := args[1] - argTotal := args[2] - argAuthorizationRequired, err := cast.ToBoolE(args[3]) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgCreateToken( - clientCtx.GetFromAddress().String(), - argName, - argSymbol, - argTotal, - argAuthorizationRequired, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_msg_create_token.go b/x/asset/client/cli/tx_msg_create_token.go deleted file mode 100644 index 8ae443eb..00000000 --- a/x/asset/client/cli/tx_msg_create_token.go +++ /dev/null @@ -1,53 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/spf13/cast" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -var _ = strconv.Itoa(0) - -func CmdMsgCreateToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "msg-create-token [name] [symbol] [total] [authorization-required]", - Short: "Broadcast message MsgCreateToken", - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argName := args[0] - argSymbol := args[1] - argTotal := args[2] - argAuthorizationRequired, err := cast.ToBoolE(args[3]) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgCreateToken( - clientCtx.GetFromAddress().String(), - argName, - argSymbol, - argTotal, - argAuthorizationRequired, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_msg_update_token.go b/x/asset/client/cli/tx_msg_update_token.go deleted file mode 100644 index 5304ae06..00000000 --- a/x/asset/client/cli/tx_msg_update_token.go +++ /dev/null @@ -1,48 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/realiotech/realio-network/x/asset/types" - "github.com/spf13/cast" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdMsgUpdateToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "msg-update-token [symbol] [authorization-required]", - Short: "Broadcast message MsgUpdateToken", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - argAuthorizationRequired, err := cast.ToBoolE(args[1]) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgUpdateToken( - clientCtx.GetFromAddress().String(), - argSymbol, - argAuthorizationRequired, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_transfer_token.go b/x/asset/client/cli/tx_transfer_token.go deleted file mode 100644 index 77b26114..00000000 --- a/x/asset/client/cli/tx_transfer_token.go +++ /dev/null @@ -1,51 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/spf13/cobra" - - "github.com/realiotech/realio-network/x/asset/types" -) - -var _ = strconv.Itoa(0) - -func CmdTransferToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "transfer-token [symbol] [from] [to] [amount]", - Short: "Broadcast message TransferToken", - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - argFrom := args[1] - argTo := args[2] - argAmount := args[3] - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgTransferToken( - argSymbol, - argFrom, - argTo, - argAmount, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_un_authorize_address.go b/x/asset/client/cli/tx_un_authorize_address.go deleted file mode 100644 index 80e2ad01..00000000 --- a/x/asset/client/cli/tx_un_authorize_address.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/realiotech/realio-network/x/asset/types" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUnAuthorizeAddress() *cobra.Command { - cmd := &cobra.Command{ - Use: "un-authorize-address [symbol] [address]", - Short: "Broadcast message UnAuthorizeAddress", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - argAddress := args[1] - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgUnAuthorizeAddress( - clientCtx.GetFromAddress().String(), - argSymbol, - argAddress, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/client/cli/tx_update_token.go b/x/asset/client/cli/tx_update_token.go deleted file mode 100644 index 13182aaf..00000000 --- a/x/asset/client/cli/tx_update_token.go +++ /dev/null @@ -1,48 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/realiotech/realio-network/x/asset/types" - "github.com/spf13/cast" - "github.com/spf13/cobra" -) - -var _ = strconv.Itoa(0) - -func CmdUpdateToken() *cobra.Command { - cmd := &cobra.Command{ - Use: "update-token [symbol] [authorization-required]", - Short: "Broadcast message UpdateToken", - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) (err error) { - argSymbol := args[0] - argAuthorizationRequired, err := cast.ToBoolE(args[1]) - if err != nil { - return err - } - - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgUpdateToken( - clientCtx.GetFromAddress().String(), - argSymbol, - argAuthorizationRequired, - ) - if err := msg.ValidateBasic(); err != nil { - return err - } - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/asset/exported/exported.go b/x/asset/exported/exported.go deleted file mode 100644 index 000114e6..00000000 --- a/x/asset/exported/exported.go +++ /dev/null @@ -1,18 +0,0 @@ -package exported - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -) - -type ( - ParamSet = paramtypes.ParamSet - - // Subspace defines an interface that implements the legacy x/params Subspace - // type. - // - // NOTE: This is used solely for migration of x/params managed parameters. - Subspace interface { - GetParamSet(ctx sdk.Context, ps ParamSet) - } -) diff --git a/x/asset/genesis.go b/x/asset/genesis.go deleted file mode 100644 index 02d51567..00000000 --- a/x/asset/genesis.go +++ /dev/null @@ -1,45 +0,0 @@ -package asset - -import ( - "context" - - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -// InitGenesis initializes the assets module's state from a provided genesis -// state. -func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisState) { - err := k.Params.Set(ctx, genState.Params) - if err != nil { - panic(err) - } - for _, token := range genState.Tokens { - err := k.Token.Set(ctx, types.TokenKey(token.Symbol), token) - if err != nil { - panic(err) - } - } -} - -// ExportGenesis returns the capability module's exported genesis. -func ExportGenesis(ctx context.Context, k keeper.Keeper) *types.GenesisState { - genesis := types.DefaultGenesis() - params, err := k.Params.Get(ctx) - if err != nil { - panic(err) - } - genesis.Params = params - tokens := []types.Token{} - err = k.Token.Walk(ctx, nil, func(_ string, token types.Token) (stop bool, err error) { - tokens = append(tokens, token) - return false, nil - }) - if err != nil { - panic(err) - } - genesis.Tokens = tokens - // this line is used by starport scaffolding # genesis/module/export - - return genesis -} diff --git a/x/asset/genesis_test.go b/x/asset/genesis_test.go deleted file mode 100644 index 87fed1fd..00000000 --- a/x/asset/genesis_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package asset_test - -import ( - "testing" - "time" - - feemarkettypes "github.com/evmos/os/x/feemarket/types" - - "github.com/cometbft/cometbft/crypto/tmhash" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmversion "github.com/cometbft/cometbft/proto/tendermint/version" - "github.com/cometbft/cometbft/version" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - - "github.com/realiotech/realio-network/app" - "github.com/realiotech/realio-network/testutil" - realiotypes "github.com/realiotech/realio-network/types" - "github.com/realiotech/realio-network/x/asset" - "github.com/realiotech/realio-network/x/asset/types" -) - -type GenesisTestSuite struct { - suite.Suite - - ctx sdk.Context - - app *app.RealioNetwork - genesis types.GenesisState -} - -func (suite *GenesisTestSuite) SetupTest() { - // consensus key - consAddress := sdk.ConsAddress(testutil.GenAddress().Bytes()) - - suite.app = app.Setup(false, feemarkettypes.DefaultGenesisState(), 1) - suite.ctx = suite.app.BaseApp.NewContextLegacy(false, tmproto.Header{ - Height: 1, - ChainID: realiotypes.MainnetChainID + "-1", - Time: time.Now().UTC(), - ProposerAddress: consAddress.Bytes(), - - Version: tmversion.Consensus{ - Block: version.BlockProtocol, - }, - LastBlockId: tmproto.BlockID{ - Hash: tmhash.Sum([]byte("block_id")), - PartSetHeader: tmproto.PartSetHeader{ - Total: 11, - Hash: tmhash.Sum([]byte("partset_header")), - }, - }, - AppHash: tmhash.Sum([]byte("app")), - DataHash: tmhash.Sum([]byte("data")), - EvidenceHash: tmhash.Sum([]byte("evidence")), - ValidatorsHash: tmhash.Sum([]byte("validators")), - NextValidatorsHash: tmhash.Sum([]byte("next_validators")), - ConsensusHash: tmhash.Sum([]byte("consensus")), - LastResultsHash: tmhash.Sum([]byte("last_result")), - }) - - suite.genesis = *types.DefaultGenesis() -} - -func TestGenesisTestSuite(t *testing.T) { - suite.Run(t, new(GenesisTestSuite)) -} - -func (suite *GenesisTestSuite) TestGenesis() { - asset.InitGenesis(suite.ctx, suite.app.AssetKeeper, suite.genesis) - got := asset.ExportGenesis(suite.ctx, suite.app.AssetKeeper) - suite.Require().NotNil(got) - - suite.Require().Equal(len(suite.genesis.Tokens), len(got.Tokens)) -} diff --git a/x/asset/keeper/grpc_query.go b/x/asset/keeper/grpc_query.go deleted file mode 100644 index e34fbaea..00000000 --- a/x/asset/keeper/grpc_query.go +++ /dev/null @@ -1,80 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/realiotech/realio-network/x/asset/types" -) - -var _ types.QueryServer = queryServer{} - -func NewQueryServerImpl(k Keeper) types.QueryServer { - return queryServer{k} -} - -type queryServer struct { - k Keeper -} - -func (q queryServer) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - params, err := q.k.Params.Get(c) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - - return &types.QueryParamsResponse{Params: params}, nil -} - -func (q queryServer) Tokens(c context.Context, req *types.QueryTokensRequest) (*types.QueryTokensResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - tokens := []types.Token{} - err := q.k.Token.Walk(c, nil, func(_ string, token types.Token) (stop bool, err error) { - tokens = append(tokens, token) - return false, nil - }) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - return &types.QueryTokensResponse{Tokens: tokens}, nil -} - -func (q queryServer) Token(c context.Context, req *types.QueryTokenRequest) (*types.QueryTokenResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - if t, err := q.k.Token.Get(ctx, types.TokenKey(req.Symbol)); err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "not found") - } else { //nolint:revive // fixing this causes t to be inaccessible, so let's leave all as is. - return &types.QueryTokenResponse{Token: t}, nil - } -} - -func (q queryServer) IsAuthorized(c context.Context, req *types.QueryIsAuthorizedRequest) (*types.QueryIsAuthorizedResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - - if t, err := q.k.Token.Get(ctx, types.TokenKey(req.Symbol)); err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "not found") - } else { //nolint:revive // fixing this causes t to be inaccessible, so let's leave all as is. - accAddress, _ := sdk.AccAddressFromBech32(req.Address) - isAuthorized := t.AddressIsAuthorized(accAddress) - return &types.QueryIsAuthorizedResponse{IsAuthorized: isAuthorized}, nil - } -} diff --git a/x/asset/keeper/grpc_query_test.go b/x/asset/keeper/grpc_query_test.go deleted file mode 100644 index 329aed9c..00000000 --- a/x/asset/keeper/grpc_query_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package keeper_test - -import ( - "fmt" - - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (suite *KeeperTestSuite) TestParamsQuery() { - suite.SetupTest() - - k := suite.app.AssetKeeper - - params := types.DefaultParams() - err := k.Params.Set(suite.ctx, params) - suite.Require().NoError(err) - - queryServer := keeper.NewQueryServerImpl(k) - response, err := queryServer.Params(suite.ctx, &types.QueryParamsRequest{}) - suite.Require().NoError(err) - suite.Require().Equal(&types.QueryParamsResponse{Params: params}, response) -} - -func (suite *KeeperTestSuite) TestTokensQuery() { - var ( - req *types.QueryTokensRequest - expRes *types.QueryTokensResponse - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "no tokens", - func() { - req = &types.QueryTokensRequest{} - expRes = &types.QueryTokensResponse{Tokens: []types.Token(nil)} - }, - true, - }, - { - "1 token exists", - func() { - req = &types.QueryTokensRequest{} - token := types.Token{ - Manager: suite.testUser1Address, - Name: "rst", - Symbol: "rst", - Total: "1000", - AuthorizationRequired: false, - } - err := suite.app.AssetKeeper.Token.Set(suite.ctx, types.TokenKey("rst"), token) - suite.Require().NoError(err) - - expRes = &types.QueryTokensResponse{ - Tokens: []types.Token{token}, - } - }, - true, - }, - { - "2 tokens exists", - func() { - req = &types.QueryTokensRequest{} - token1 := types.Token{ - Manager: suite.testUser1Address, - Name: "rst", - Symbol: "rst", - Total: "1000", - AuthorizationRequired: false, - } - err := suite.app.AssetKeeper.Token.Set(suite.ctx, types.TokenKey("rst"), token1) - suite.Require().NoError(err) - - token2 := types.Token{ - Manager: suite.testUser1Address, - Name: "bitcoinEtf", - Symbol: "btf", - Total: "1000", - AuthorizationRequired: false, - } - err = suite.app.AssetKeeper.Token.Set(suite.ctx, types.TokenKey("btf"), token2) - suite.Require().NoError(err) - - expRes = &types.QueryTokensResponse{ - Tokens: []types.Token{token2, token1}, - } - }, - true, - }, - } - for _, tc := range testCases { - suite.Run(fmt.Sprintf("Case %s", tc.name), func() { - suite.SetupTest() // reset - - ctx := suite.ctx - tc.malleate() - - res, err := suite.queryClient.Tokens(ctx, req) - if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(expRes.Tokens, res.Tokens) - suite.Require().ElementsMatch(expRes.Tokens, res.Tokens) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index 74b812e0..c470a714 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -17,17 +17,19 @@ import ( type Keeper struct { cdc codec.Codec storeService store.KVStoreService - bankKeeper types.BankKeeper + bk types.BankKeeper ak types.AccountKeeper - allowAddrs map[string]bool // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. authority string - Schema collections.Schema - Params collections.Item[types.Params] - Token collections.Map[string, types.Token] + Schema collections.Schema + Params collections.Item[types.Params] + Token collections.Map[string, types.Token] + TokenManagement collections.Map[string, types.TokenManagement] + TokenDistribution collections.Map[string, types.TokenDistribution] + WhitelistAddresses collections.Map[sdk.AccAddress, bool] } // NewKeeper returns a new Keeper object with a given codec, dedicated @@ -36,21 +38,21 @@ type Keeper struct { func NewKeeper( cdc codec.Codec, storeService store.KVStoreService, - bankKeeper types.BankKeeper, + bk types.BankKeeper, ak types.AccountKeeper, - allowAddrs map[string]bool, authority string, ) *Keeper { sb := collections.NewSchemaBuilder(storeService) k := Keeper{ - cdc: cdc, - storeService: storeService, - authority: authority, - bankKeeper: bankKeeper, - ak: ak, - allowAddrs: allowAddrs, - Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), - Token: collections.NewMap(sb, types.TokenKeyPrefix, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), + cdc: cdc, + storeService: storeService, + authority: authority, + bk: bk, + ak: ak, + Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), + Token: collections.NewMap(sb, types.TokenKeyPrefix, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), + TokenManagement: collections.NewMap(sb, types.TokenKeyPrefix, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), + TokenDistribution: collections.NewMap(sb, types.TokenKeyPrefix, "token_distribution", collections.StringKey, codec.CollValue[types.TokenDistribution](cdc)), } schema, err := sb.Build() @@ -66,11 +68,11 @@ func (k Keeper) Logger(ctx context.Context) log.Logger { return sdkCtx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -func (k Keeper) IsAddressAuthorizedToSend(ctx context.Context, symbol string, address sdk.AccAddress) (authorized bool) { - token, err := k.Token.Get(ctx, types.TokenKey(symbol)) +func (k Keeper) GetWhitelistAddress(ctx context.Context, accAddr sdk.AccAddress) bool { + found, err := k.WhitelistAddresses.Get(ctx, accAddr) if err != nil { return false } - return token.AddressIsAuthorized(address) + return found } diff --git a/x/asset/keeper/keeper_test.go b/x/asset/keeper/keeper_test.go deleted file mode 100644 index 33ab9127..00000000 --- a/x/asset/keeper/keeper_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - "github.com/cometbft/cometbft/crypto/tmhash" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmversion "github.com/cometbft/cometbft/proto/tendermint/version" - "github.com/cometbft/cometbft/version" - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/evmos/os/crypto/ethsecp256k1" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "github.com/realiotech/realio-network/app" - realiotypes "github.com/realiotech/realio-network/types" - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" - - "github.com/realiotech/realio-network/testutil" -) - -type KeeperTestSuite struct { - suite.Suite - app *app.RealioNetwork - ctx sdk.Context - queryClient types.QueryClient - testUser1Acc sdk.AccAddress - testUser1Address string - testUser2Acc sdk.AccAddress - testUser2Address string - testUser3Acc sdk.AccAddress - testUser3Address string -} - -func (suite *KeeperTestSuite) SetupTest() { - suite.DoSetupTest(suite.T()) -} - -func (suite *KeeperTestSuite) DoSetupTest(t *testing.T) { - checkTx := false - - // user 1 key - suite.testUser1Acc = testutil.GenAddress() - suite.testUser1Address = suite.testUser1Acc.String() - - // user 2 key - suite.testUser2Acc = testutil.GenAddress() - suite.testUser2Address = suite.testUser2Acc.String() - - // user 3 key - suite.testUser3Acc = testutil.GenAddress() - suite.testUser3Address = suite.testUser3Acc.String() - - // consensus key - priv, err := ethsecp256k1.GenerateKey() - require.NoError(t, err) - consAddress := sdk.ConsAddress(priv.PubKey().Address()) - - // init app - suite.app = app.Setup(checkTx, nil, 1) - - // Set Context - suite.ctx = suite.app.BaseApp.NewContextLegacy(checkTx, tmproto.Header{ - Height: 1, - ChainID: realiotypes.TestnetChainID, - Time: time.Now().UTC(), - ProposerAddress: consAddress.Bytes(), - - Version: tmversion.Consensus{ - Block: version.BlockProtocol, - }, - LastBlockId: tmproto.BlockID{ - Hash: tmhash.Sum([]byte("block_id")), - PartSetHeader: tmproto.PartSetHeader{ - Total: 11, - Hash: tmhash.Sum([]byte("partset_header")), - }, - }, - AppHash: tmhash.Sum([]byte("app")), - DataHash: tmhash.Sum([]byte("data")), - EvidenceHash: tmhash.Sum([]byte("evidence")), - ValidatorsHash: tmhash.Sum([]byte("validators")), - NextValidatorsHash: tmhash.Sum([]byte("next_validators")), - ConsensusHash: tmhash.Sum([]byte("consensus")), - LastResultsHash: tmhash.Sum([]byte("last_result")), - }) - - queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) - types.RegisterQueryServer(queryHelper, keeper.NewQueryServerImpl(suite.app.AssetKeeper)) - suite.queryClient = types.NewQueryClient(queryHelper) -} - -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) -} diff --git a/x/asset/keeper/migrator.go b/x/asset/keeper/migrator.go deleted file mode 100644 index 1d994f6c..00000000 --- a/x/asset/keeper/migrator.go +++ /dev/null @@ -1,29 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/realiotech/realio-network/x/asset/exported" - v2 "github.com/realiotech/realio-network/x/asset/migrations/v2" -) - -// Migrator is a struct for handling in-place state migrations. -type Migrator struct { - keeper Keeper - legacySubspace exported.Subspace -} - -// NewMigrator returns Migrator instance for the state migration. -func NewMigrator(k Keeper, ss exported.Subspace) Migrator { - return Migrator{ - keeper: k, - legacySubspace: ss, - } -} - -// Migrate1to2 migrates the x/mint module state from the consensus version 1 to -// version 2. Specifically, it takes the parameters that are currently stored -// and managed by the x/params modules and stores them directly into the x/mint -// module state. -func (m Migrator) Migrate1to2(ctx sdk.Context) error { - return v2.Migrate(ctx, m.keeper.storeService.OpenKVStore(ctx), m.legacySubspace, m.keeper.cdc) -} diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index 4cb7f0eb..e5cee653 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -2,9 +2,15 @@ package keeper import ( "context" + "fmt" + "strings" - "cosmossdk.io/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/realiotech/realio-network/x/asset/types" ) @@ -20,10 +26,120 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { var _ types.MsgServer = msgServer{} +// CreateToken allow issuer to define new token. +func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) (*types.MsgCreateTokenResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + issuerAddr, err := ms.ak.AddressCodec().StringToBytes(msg.Issuer) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrAccAddress, err.Error()) + } + + if !ms.GetWhitelistAddress(ctx, issuerAddr) { + return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not in whitelisted addresses") + } + + lowerCaseName := strings.ToLower(msg.Name) + lowerCaseSymbol := strings.ToLower(msg.Symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, msg.Issuer, lowerCaseSymbol) + + isFound := ms.bk.HasSupply(ctx, tokenId) + if isFound { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "token with id %s already exists", tokenId) + } + + // TODO: create evm precompile here + + token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer) + err = ms.Token.Set(ctx, tokenId, token) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenSet, err.Error()) + } + + tokenManagement := types.NewTokenManagement(msg.Managers, msg.AllowNewExtensions, msg.ExtensionsList) + err = ms.TokenManagement.Set(ctx, tokenId, tokenManagement) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) + } + + tokenDistribution := types.NewTokenDistribution(msg.Distributors, msg.MaxSupply) + err = ms.TokenDistribution.Set(ctx, tokenId, tokenDistribution) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) + } + + ms.bk.SetDenomMetaData(ctx, banktypes.Metadata{ + Base: tokenId, Symbol: lowerCaseSymbol, Name: lowerCaseName, + DenomUnits: []*banktypes.DenomUnit{{Denom: lowerCaseSymbol, Exponent: msg.Decimal}, {Denom: tokenId, Exponent: 0}}, + }) + + sdkCtx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeTokenCreated, + sdk.NewAttribute(types.AttributeKeyTokenId, tokenId), + sdk.NewAttribute(types.AttributeKeyAddress, msg.Issuer), + ), + ) + + return &types.MsgCreateTokenResponse{ + TokenId: tokenId, + }, nil +} + +func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) (*types.MsgAssignRolesResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + token, err := ms.Token.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) + } + + if msg.Issuer != token.Issuer { + return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") + } + + tokenManagement, err := ms.TokenManagement.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) + } + tokenManagement.Managers = msg.Managers + err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) + } + + tokenDistribution, err := ms.TokenDistribution.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenDistributionGet, err.Error()) + } + tokenDistribution.Distributors = msg.Distributors + err = ms.TokenDistribution.Set(ctx, msg.TokenId, tokenDistribution) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) + } + + sdkCtx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeTokenAuthorizeUpdated, + sdk.NewAttribute(types.AttributeKeyTokenId, msg.TokenId), + ), + ) + + return &types.MsgAssignRolesResponse{}, nil +} + // UpdateParams updates the params. func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if ms.authority != msg.Authority { - return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.authority, msg.Authority) + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.authority, msg.Authority) } if err := msg.Params.Validate(); err != nil { diff --git a/x/asset/keeper/msg_server_authorize_address.go b/x/asset/keeper/msg_server_authorize_address.go deleted file mode 100644 index f9ccc251..00000000 --- a/x/asset/keeper/msg_server_authorize_address.go +++ /dev/null @@ -1,46 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (ms msgServer) AuthorizeAddress(goCtx context.Context, msg *types.MsgAuthorizeAddress) (*types.MsgAuthorizeAddressResponse, error) { - // Check if the value exists - token, err := ms.Token.Get(goCtx, types.TokenKey(msg.Symbol)) - if err != nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "symbol %s does not exists : %s", msg.Symbol, err.Error()) - } - - // assert that the manager account is the only signer of the message - if msg.Manager != token.Manager { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "caller not authorized") - } - - accAddress, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid address") - } - - token.AuthorizeAddress(accAddress) - err = ms.Token.Set(goCtx, types.TokenKey(msg.Symbol), token) - if err != nil { - return nil, types.ErrSetTokenUnable - } - - ctx := sdk.UnwrapSDKContext(goCtx) - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTokenAuthorized, - sdk.NewAttribute(types.AttributeKeySymbol, msg.Symbol), - sdk.NewAttribute(types.AttributeKeyAddress, msg.Address), - ), - ) - - return &types.MsgAuthorizeAddressResponse{}, nil -} diff --git a/x/asset/keeper/msg_server_create_token.go b/x/asset/keeper/msg_server_create_token.go deleted file mode 100644 index fb3ab977..00000000 --- a/x/asset/keeper/msg_server_create_token.go +++ /dev/null @@ -1,83 +0,0 @@ -package keeper - -import ( - "context" - "fmt" - "strings" - - errorsmod "cosmossdk.io/errors" - bank "github.com/cosmos/cosmos-sdk/x/bank/types" - - realionetworktypes "github.com/realiotech/realio-network/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "cosmossdk.io/math" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (ms msgServer) CreateToken(goCtx context.Context, msg *types.MsgCreateToken) (*types.MsgCreateTokenResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // Check if the value already exists - lowerCaseSymbol := strings.ToLower(msg.Symbol) - lowerCaseName := strings.ToLower(msg.Name) - baseDenom := fmt.Sprintf("a%s", lowerCaseSymbol) - - isFound := ms.bankKeeper.HasSupply(ctx, baseDenom) - if isFound { - return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "token with denom %s already exists", baseDenom) - } - - managerAccAddress, err := sdk.AccAddressFromBech32(msg.Manager) - if err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid manager address") - } - - token := types.NewToken(lowerCaseName, lowerCaseSymbol, msg.Total, msg.Manager, msg.AuthorizationRequired) - - if msg.AuthorizationRequired { - // create authorization for module account and manager - assetModuleAddress := ms.ak.GetModuleAddress(types.ModuleName) - moduleAuthorization := types.NewAuthorization(assetModuleAddress) - newAuthorizationManager := types.NewAuthorization(managerAccAddress) - token.Authorized = append(token.Authorized, moduleAuthorization, newAuthorizationManager) - } - - err = ms.Token.Set(goCtx, types.TokenKey(lowerCaseSymbol), token) - if err != nil { - return nil, types.ErrSetTokenUnable - } - - ms.bankKeeper.SetDenomMetaData(ctx, bank.Metadata{ - Base: baseDenom, Symbol: lowerCaseSymbol, Name: lowerCaseName, - DenomUnits: []*bank.DenomUnit{{Denom: lowerCaseSymbol, Exponent: 18}, {Denom: baseDenom, Exponent: 0}}, - }) - - // mint coins for the current module - // normalize into chains 10^18 denomination - totalInt, _ := math.NewIntFromString(msg.Total) - canonicalAmount := totalInt.Mul(realionetworktypes.PowerReduction) - coin := sdk.Coins{{Denom: baseDenom, Amount: canonicalAmount}} - - err = ms.bankKeeper.MintCoins(ctx, types.ModuleName, coin) - if err != nil { - panic(err) - } - - err = ms.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, managerAccAddress, coin) - if err != nil { - panic(err) - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTokenCreated, - sdk.NewAttribute(sdk.AttributeKeyAmount, fmt.Sprint(msg.Total)), - sdk.NewAttribute(types.AttributeKeySymbol, msg.Symbol), - ), - ) - - return &types.MsgCreateTokenResponse{}, nil -} diff --git a/x/asset/keeper/msg_server_token_test.go b/x/asset/keeper/msg_server_token_test.go deleted file mode 100644 index 8d2d4335..00000000 --- a/x/asset/keeper/msg_server_token_test.go +++ /dev/null @@ -1,408 +0,0 @@ -package keeper_test - -import ( - "strconv" - "strings" - - "cosmossdk.io/math" - realionetworktypes "github.com/realiotech/realio-network/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -// Prevent strconv unused error -var _ = strconv.IntSize - -func (suite *KeeperTestSuite) TestTokenMsgServerCreate() { - testCases := []struct { - name string - msg *types.MsgCreateToken - expectErr bool - errString string - }{ - { - name: "valid MsgCreateToken", - msg: &types.MsgCreateToken{ - Manager: suite.testUser1Address, - Symbol: "FOO", Total: "1000", - }, - expectErr: false, - }, - { - name: "invalid MsgCreateToken; duplicated denom ario", - msg: &types.MsgCreateToken{ - Manager: suite.testUser1Address, - Symbol: "RIO", Total: "100", - }, - expectErr: true, - errString: "token with denom ario already exists: invalid request", - }, - { - name: "invalid MsgCreateToken; duplicated denom abar", - msg: &types.MsgCreateToken{ - Manager: suite.testUser1Address, - Symbol: "BAR", Total: "100", - }, - expectErr: true, - errString: "token with denom abar already exists: invalid request", - }, - { - name: "invalid MsgCreateToken; invalid manager address", - msg: &types.MsgCreateToken{ - Manager: "invalid address", - Symbol: "FOO", Total: "100", - }, - expectErr: true, - errString: "invalid manager address: invalid address", - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - - // we created a token here with symbol "BAR" - // there's a test case to make sure we CANNOT create tokens with the same symbol - _, err := srv.CreateToken(wctx, &types.MsgCreateToken{ - Manager: suite.testUser1Address, - Symbol: "BAR", Total: "999999", - }) - suite.Require().NoError(err) - - _, err = srv.CreateToken(wctx, tc.msg) - if tc.expectErr { - suite.Require().EqualError(err, tc.errString) - } else { - suite.Require().NoError(err) - - token, err := suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(tc.msg.Symbol), - ) - suite.Require().NoError(err) - suite.Require().Equal(token.Manager, tc.msg.Manager) - suite.Require().Equal(token.Symbol, strings.ToLower(tc.msg.Symbol)) - suite.Require().Equal(token.Total, tc.msg.Total) - suite.Require().Equal(token.AuthorizationRequired, tc.msg.AuthorizationRequired) - } - }) - } -} - -func (suite *KeeperTestSuite) TestTokenMsgServerCreateInvalidSender() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := "invalid" - expected := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err := srv.CreateToken(wctx, expected) - suite.Require().ErrorIs(err, sdkerrors.ErrInvalidAddress) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerCreateAuthorizationDefaultFalse() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - expected := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err := srv.CreateToken(wctx, expected) - suite.Require().NoError(err) - token, _ := suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(expected.Symbol), - ) - suite.Require().False(token.AuthorizationRequired) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerCreateErrorDupIndex() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - t2 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err2 := srv.CreateToken(wctx, t2) - suite.Require().Error(err2) - suite.Require().ErrorIs(err2, sdkerrors.ErrInvalidRequest) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerCreateVerifyDistribution() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "RST", Total: "1000", - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - totalInt, _ := math.NewIntFromString("1000") - canonicalAmount := totalInt.Mul(realionetworktypes.PowerReduction) - - account, _ := sdk.AccAddressFromBech32(manager) - managerBalance := suite.app.BankKeeper.GetBalance(suite.ctx, account, "arst") - suite.Require().Equal(managerBalance.Amount, canonicalAmount) - - totalbalance := suite.app.BankKeeper.GetSupply(suite.ctx, "arst") - suite.Require().Equal(totalbalance.Amount, canonicalAmount) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerUpdate() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - token, _ := suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().False(token.AuthorizationRequired) - - updateMsg := &types.MsgUpdateToken{ - Manager: manager, - Symbol: "BTC", AuthorizationRequired: true, - } - - _, err = srv.UpdateToken(wctx, updateMsg) - - token, _ = suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().NoError(err) - suite.Require().True(token.AuthorizationRequired) - suite.Require().Equal(token.Total, "1000") -} - -func (suite *KeeperTestSuite) TestTokenMsgServerUpdateNotFound() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - updateMsg := &types.MsgUpdateToken{ - Manager: manager, - Symbol: "RST", AuthorizationRequired: true, - } - - _, err = srv.UpdateToken(wctx, updateMsg) - suite.Require().ErrorIs(err, sdkerrors.ErrKeyNotFound) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerAuthorizeAddress() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - testUser := suite.testUser2Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - token, _ := suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().True(token.AddressIsAuthorized(suite.testUser1Acc)) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "BTC", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - token, _ = suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().NotNil(token.Authorized) - suite.Require().True(token.AddressIsAuthorized(suite.testUser1Acc)) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerAuthorizeTokenNotFound() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - testUser := suite.testUser2Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - - suite.Require().ErrorIs(err, sdkerrors.ErrKeyNotFound) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerAuthorizeAddressSenderUnauthorized() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - manager2 := suite.testUser2Address - testUser := suite.testUser3Address - - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager2, - Symbol: "BTC", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - - suite.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerUnAuthorizeAddress() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - testUser := suite.testUser2Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - token, _ := suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().True(token.AddressIsAuthorized(suite.testUser1Acc)) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "BTC", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - token, _ = suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().True(token.AddressIsAuthorized(suite.testUser2Acc)) - - unAuthUserMsg := &types.MsgUnAuthorizeAddress{ - Manager: manager, - Symbol: "BTC", Address: testUser, - } - - _, err = srv.UnAuthorizeAddress(wctx, unAuthUserMsg) - suite.Require().NoError(err) - - token, _ = suite.app.AssetKeeper.Token.Get(suite.ctx, - types.TokenKey(t1.Symbol), - ) - suite.Require().False(token.AddressIsAuthorized(suite.testUser2Acc)) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerUnAuthorizeTokenNotFound() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - testUser := suite.testUser2Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - unAuthUserMsg := &types.MsgUnAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: testUser, - } - - _, err = srv.UnAuthorizeAddress(wctx, unAuthUserMsg) - - suite.Require().ErrorIs(err, sdkerrors.ErrKeyNotFound) -} - -func (suite *KeeperTestSuite) TestTokenMsgServerUnAuthorizeAddressSenderUnauthorized() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - manager2 := suite.testUser2Address - testUser := suite.testUser3Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "BTC", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - unAuthUserMsg := &types.MsgUnAuthorizeAddress{ - Manager: manager2, - Symbol: "BTC", Address: testUser, - } - - _, err = srv.UnAuthorizeAddress(wctx, unAuthUserMsg) - - suite.Require().ErrorIs(err, sdkerrors.ErrUnauthorized) -} diff --git a/x/asset/keeper/msg_server_transfer_token.go b/x/asset/keeper/msg_server_transfer_token.go deleted file mode 100644 index d1d01642..00000000 --- a/x/asset/keeper/msg_server_transfer_token.go +++ /dev/null @@ -1,63 +0,0 @@ -package keeper - -import ( - "context" - "fmt" - "strings" - - errorsmod "cosmossdk.io/errors" - "cosmossdk.io/math" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/realiotech/realio-network/x/asset/types" -) - -func (ms msgServer) TransferToken(goCtx context.Context, msg *types.MsgTransferToken) (*types.MsgTransferTokenResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - var fromAddress, toAddress sdk.AccAddress - isAuthorizedFrom, isAuthorizedTo := true, true - - lowerCaseSymbol := strings.ToLower(msg.Symbol) - - fromAddress, _ = sdk.AccAddressFromBech32(msg.From) - toAddress, _ = sdk.AccAddressFromBech32(msg.To) - // Check if the value already exists - token, err := ms.Token.Get( - ctx, - types.TokenKey(msg.Symbol), - ) - if err != nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "token %s not found: %s", lowerCaseSymbol, err.Error()) - } - - if ms.bankKeeper.BlockedAddr(toAddress) { - return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.To) - } - - if token.AuthorizationRequired { - isAuthorizedFrom = ms.IsAddressAuthorizedToSend(ctx, lowerCaseSymbol, fromAddress) - isAuthorizedTo = ms.IsAddressAuthorizedToSend(ctx, lowerCaseSymbol, toAddress) - } - - if isAuthorizedFrom && isAuthorizedTo { - totalInt, totalIsValid := math.NewIntFromString(msg.Amount) - if !totalIsValid { - return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "invalid coin amount %s", msg.Amount) - } - - baseDenom := fmt.Sprintf("a%s", lowerCaseSymbol) - coin := sdk.Coins{{Denom: baseDenom, Amount: totalInt}} - err := ms.bankKeeper.SendCoins(ctx, fromAddress, toAddress, coin) - if err != nil { - return nil, err - } - } else { - return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s transfer not authorized", lowerCaseSymbol) - } - - return &types.MsgTransferTokenResponse{}, nil -} diff --git a/x/asset/keeper/msg_server_transfer_token_test.go b/x/asset/keeper/msg_server_transfer_token_test.go deleted file mode 100644 index 260182ad..00000000 --- a/x/asset/keeper/msg_server_transfer_token_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package keeper_test - -import ( - "fmt" - "strconv" - - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -// Prevent strconv unused error -var _ = strconv.IntSize - -func (suite *KeeperTestSuite) TestTransferToken() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - - manager := suite.testUser1Address - testUser := suite.testUser2Address - - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "rst", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "rst", Address: manager, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - authUser2Msg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUser2Msg) - suite.Require().NoError(err) - - amount := "50000000000000000000" - expected := &types.MsgTransferToken{Symbol: "RST", From: manager, To: testUser, Amount: amount} - - _, err = srv.TransferToken(wctx, expected) - suite.Require().NoError(err) - - balance := suite.app.BankKeeper.GetBalance(suite.ctx, suite.testUser2Acc, "arst") - suite.Require().Equal(balance.String(), fmt.Sprintf("%s%s", amount, "arst")) -} - -func (suite *KeeperTestSuite) TestTransferTokenInvalidAmount() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - - manager := suite.testUser1Address - testUser := suite.testUser2Address - - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "rst", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "rst", Address: manager, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - authUser2Msg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "rst", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUser2Msg) - suite.Require().NoError(err) - - // amount is invalid, all amounts should be in base 10^18 amount - amount := "50000000000000000000.00" - expected := &types.MsgTransferToken{Symbol: "rst", From: manager, To: testUser, Amount: amount} - - _, err = srv.TransferToken(wctx, expected) - suite.Require().Error(err) -} - -func (suite *KeeperTestSuite) TestTransferTokenSenderBalanceToSmall() { - suite.SetupTest() - - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - - manager := suite.testUser1Address - testUser := suite.testUser2Address - - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "RST", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: manager, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - authUser2Msg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUser2Msg) - suite.Require().NoError(err) - - // amount is invalid, all amounts should be in base 10^18 amount - amount := "1001000000000000000000" - expected := &types.MsgTransferToken{Symbol: "RST", From: manager, To: testUser, Amount: amount} - - _, err = srv.TransferToken(wctx, expected) - suite.Require().Error(err) - suite.Require().Equal(err.Error(), "spendable balance 1000000000000000000000arst is smaller than 1001000000000000000000arst: insufficient funds") -} diff --git a/x/asset/keeper/msg_server_un_authorize_address.go b/x/asset/keeper/msg_server_un_authorize_address.go deleted file mode 100644 index 0b9e17c5..00000000 --- a/x/asset/keeper/msg_server_un_authorize_address.go +++ /dev/null @@ -1,46 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (ms msgServer) UnAuthorizeAddress(goCtx context.Context, msg *types.MsgUnAuthorizeAddress) (*types.MsgUnAuthorizeAddressResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // Check if the value exists - token, err := ms.Token.Get(ctx, types.TokenKey(msg.Symbol)) - if err != nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "symbol %s does not exists: %s", msg.Symbol, err.Error()) - } - - // assert that the manager account is the only signer of the message - if msg.Manager != token.Manager { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "caller not authorized") - } - - accAddress, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid address") - } - - token.UnAuthorizeAddress(accAddress) - err = ms.Token.Set(goCtx, types.TokenKey(msg.Symbol), token) - if err != nil { - return nil, types.ErrSetTokenUnable - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTokenUnAuthorized, - sdk.NewAttribute(types.AttributeKeySymbol, msg.Symbol), - sdk.NewAttribute(types.AttributeKeyAddress, msg.Address), - ), - ) - - return &types.MsgUnAuthorizeAddressResponse{}, nil -} diff --git a/x/asset/keeper/msg_server_update_token.go b/x/asset/keeper/msg_server_update_token.go deleted file mode 100644 index 4d9c85b4..00000000 --- a/x/asset/keeper/msg_server_update_token.go +++ /dev/null @@ -1,48 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (ms msgServer) UpdateToken(goCtx context.Context, msg *types.MsgUpdateToken) (*types.MsgUpdateTokenResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - existing, err := ms.Token.Get(ctx, types.TokenKey(msg.Symbol)) - if err != nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "symbol %s does not exists: %s", msg.Symbol, err.Error()) - } - - // assert that the manager account is the only signer of the message - if msg.Manager != existing.Manager { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "caller not authorized") - } - - // only Authorization Flag is updatable at this time - token := types.Token{ - Name: existing.Name, - Symbol: existing.Symbol, - Total: existing.Total, - Manager: existing.Manager, - AuthorizationRequired: msg.AuthorizationRequired, - } - - err = ms.Token.Set(goCtx, types.TokenKey(msg.Symbol), token) - if err != nil { - return nil, types.ErrSetTokenUnable - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTokenUpdated, - sdk.NewAttribute(types.AttributeKeySymbol, msg.Symbol), - ), - ) - - return &types.MsgUpdateTokenResponse{}, nil -} diff --git a/x/asset/keeper/restrictions.go b/x/asset/keeper/restrictions.go deleted file mode 100644 index fd70bc60..00000000 --- a/x/asset/keeper/restrictions.go +++ /dev/null @@ -1,56 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (k Keeper) AssetSendRestriction(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (newToAddr sdk.AccAddress, err error) { - newToAddr = toAddr - - // module whitelisted addresses can send coins without restrictions - if allow := k.AllowAddr(fromAddr) || k.AllowAddr(toAddr); allow { - return newToAddr, nil - } - - for _, coin := range amt { - // Check if the value already exists - // fetch bank metadata to get symbol from denom - symbol := coin.Denom - tokenMetadata, found := k.bankKeeper.GetDenomMetaData(ctx, coin.Denom) - if found { - symbol = tokenMetadata.Symbol - } - token, err := k.Token.Get( - ctx, - types.TokenKey(symbol), - ) - if err != nil { - continue - } - - var isAuthorizedFrom, isAuthorizedTo bool - if token.AuthorizationRequired { - isAuthorizedFrom = k.IsAddressAuthorizedToSend(ctx, symbol, fromAddr) - isAuthorizedTo = k.IsAddressAuthorizedToSend(ctx, symbol, toAddr) - } else { - continue - } - - if isAuthorizedFrom && isAuthorizedTo { - continue - } else { //nolint:revive // superfluous else, could fix, but not worth it? - err := errorsmod.Wrapf(types.ErrNotAuthorized, "%s is not authorized to transact with %s", fromAddr, coin.Denom) - return nil, err - } - } - return newToAddr, nil -} - -// AllowAddr addr checks if a given address is in the list of allowAddrs to skip restrictions -func (k Keeper) AllowAddr(addr sdk.AccAddress) bool { - return k.allowAddrs[addr.String()] -} diff --git a/x/asset/keeper/restrictions_test.go b/x/asset/keeper/restrictions_test.go deleted file mode 100644 index 51501f1f..00000000 --- a/x/asset/keeper/restrictions_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package keeper_test - -import ( - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -func (suite *KeeperTestSuite) TestRestrictions() { - srv := keeper.NewMsgServerImpl(suite.app.AssetKeeper) - wctx := suite.ctx - manager := suite.testUser1Address - testUser := suite.testUser2Address - t1 := &types.MsgCreateToken{ - Manager: manager, - Symbol: "RST", Total: "1000", AuthorizationRequired: true, - } - _, err := srv.CreateToken(wctx, t1) - suite.Require().NoError(err) - - authUserMsg := &types.MsgAuthorizeAddress{ - Manager: manager, - Symbol: "RST", Address: testUser, - } - - _, err = srv.AuthorizeAddress(wctx, authUserMsg) - suite.Require().NoError(err) - - cases := []struct { - name string - from sdk.AccAddress - to sdk.AccAddress - amount sdk.Coins - expPass bool - }{ - { - "module accounts can send to any account", - suite.app.AccountKeeper.GetModuleAddress(stakingtypes.BondedPoolName), - suite.testUser1Acc, - sdk.NewCoins(sdk.NewCoin("arst", math.NewInt(100))), - true, - }, - { - "module accounts can send to any account", - suite.app.AccountKeeper.GetModuleAddress(stakingtypes.NotBondedPoolName), - suite.testUser1Acc, - sdk.NewCoins(sdk.NewCoin("arst", math.NewInt(100))), - true, - }, - { - "module accounts can send to any account", - suite.app.AccountKeeper.GetModuleAddress(stakingtypes.BondedPoolName), - suite.testUser1Acc, - sdk.NewCoins(sdk.NewCoin("arst", math.NewInt(100))), - true, - }, - { - "unauthorized accounts cannot send", - suite.testUser3Acc, - suite.testUser1Acc, - sdk.NewCoins(sdk.NewCoin("arst", math.NewInt(100))), - false, - }, - } - - for _, tc := range cases { - toAddr, err := suite.app.AssetKeeper.AssetSendRestriction(suite.ctx, tc.from, tc.to, tc.amount) - if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(toAddr, tc.to) - } else { - suite.Require().Error(err) - } - } -} diff --git a/x/asset/migrations/v2/migrate.go b/x/asset/migrations/v2/migrate.go deleted file mode 100644 index ca7d57fb..00000000 --- a/x/asset/migrations/v2/migrate.go +++ /dev/null @@ -1,38 +0,0 @@ -package v2 - -import ( - storetypes "cosmossdk.io/core/store" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/realiotech/realio-network/x/asset/exported" - "github.com/realiotech/realio-network/x/asset/types" -) - -const ( - ModuleName = "asset" -) - -var ParamsKey = []byte{0x00} - -// Migrate migrates the x/mint module state from the consensus version 1 to -// version 2. Specifically, it takes the parameters that are currently stored -// and managed by the x/params modules and stores them directly into the x/mint -// module state. -func Migrate( - ctx sdk.Context, - store storetypes.KVStore, - legacySubspace exported.Subspace, - cdc codec.BinaryCodec, -) error { - var currParams types.Params - legacySubspace.GetParamSet(ctx, &currParams) - - if err := currParams.Validate(); err != nil { - return err - } - - bz := cdc.MustMarshal(&currParams) - return store.Set(ParamsKey, bz) -} diff --git a/x/asset/migrations/v2/migrator_test.go b/x/asset/migrations/v2/migrator_test.go deleted file mode 100644 index 85f8b2ae..00000000 --- a/x/asset/migrations/v2/migrator_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package v2_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - storetypes "cosmossdk.io/store/types" - - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil" - sdk "github.com/cosmos/cosmos-sdk/types" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - - "github.com/realiotech/realio-network/x/asset" - "github.com/realiotech/realio-network/x/asset/exported" - v2 "github.com/realiotech/realio-network/x/asset/migrations/v2" - "github.com/realiotech/realio-network/x/asset/types" -) - -type mockSubspace struct { - ps types.Params -} - -func newMockSubspace(ps types.Params) mockSubspace { - return mockSubspace{ps: ps} -} - -func (ms mockSubspace) GetParamSet(_ sdk.Context, ps exported.ParamSet) { - *ps.(*types.Params) = ms.ps -} - -func TestMigrate(t *testing.T) { - encCfg := moduletestutil.MakeTestEncodingConfig(asset.AppModuleBasic{}) - cdc := encCfg.Codec - - storeKey := storetypes.NewKVStoreKey(v2.ModuleName) - tKey := storetypes.NewTransientStoreKey("transient_test") - ctx := testutil.DefaultContext(storeKey, tKey) - kvStoreService := runtime.NewKVStoreService(storeKey) - store := kvStoreService.OpenKVStore(ctx) - - legacySubspace := newMockSubspace(types.DefaultParams()) - require.NoError(t, v2.Migrate(ctx, store, legacySubspace, cdc)) - - var res types.Params - bz, err := store.Get(v2.ParamsKey) - require.NoError(t, err) - require.NoError(t, cdc.Unmarshal(bz, &res)) - require.Equal(t, legacySubspace.ps, res) -} diff --git a/x/asset/module.go b/x/asset/module.go deleted file mode 100644 index eeb832d5..00000000 --- a/x/asset/module.go +++ /dev/null @@ -1,190 +0,0 @@ -package asset - -import ( - "context" - "encoding/json" - "fmt" - - // this line is used by starport scaffolding # 1 - - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" - - "cosmossdk.io/core/appmodule" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - - "github.com/realiotech/realio-network/x/asset/client/cli" - "github.com/realiotech/realio-network/x/asset/exported" - "github.com/realiotech/realio-network/x/asset/keeper" - "github.com/realiotech/realio-network/x/asset/types" -) - -var ( - _ module.AppModuleBasic = AppModule{} - _ module.AppModuleSimulation = AppModule{} - _ module.HasGenesis = AppModule{} - _ module.HasServices = AppModule{} - - _ appmodule.AppModule = AppModule{} -) - -// ConsensusVersion defines the current x/asset module consensus version. -const ConsensusVersion = 2 - -// ---------------------------------------------------------------------------- -// AppModuleBasic -// ---------------------------------------------------------------------------- - -// AppModuleBasic implements the AppModuleBasic interface for the capability module. -type AppModuleBasic struct { - cdc codec.BinaryCodec -} - -var _ module.AppModuleBasic = AppModuleBasic{} - -func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { - return AppModuleBasic{cdc: cdc} -} - -// Name returns the capability module's name. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { - types.RegisterCodec(cdc) -} - -func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - types.RegisterCodec(cdc) -} - -// RegisterInterfaces registers the module's interface types -func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { - types.RegisterInterfaces(reg) -} - -// DefaultGenesis returns the capability module's default genesis state. -func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - return cdc.MustMarshalJSON(types.DefaultGenesis()) -} - -// ValidateGenesis performs genesis state validation for the capability module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { - var genState types.GenesisState - if err := cdc.UnmarshalJSON(bz, &genState); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) - } - return genState.Validate() -} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { - panic(err) - } -} - -// GetTxCmd returns the capability module's root tx command. -func (a AppModuleBasic) GetTxCmd() *cobra.Command { - return cli.GetTxCmd() -} - -// GetQueryCmd returns the capability module's root query command. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return cli.GetQueryCmd() -} - -// ---------------------------------------------------------------------------- -// AppModule -// ---------------------------------------------------------------------------- - -// AppModule implements the AppModule interface for the capability module. -type AppModule struct { - AppModuleBasic - - // legacySubspace is used solely for migration of x/params managed parameters - legacySubspace exported.Subspace - - keeper keeper.Keeper - bankKeeper types.BankKeeper -} - -func NewAppModule( - cdc codec.Codec, - keeper keeper.Keeper, - bankKeeper types.BankKeeper, - ss exported.Subspace, -) AppModule { - return AppModule{ - AppModuleBasic: NewAppModuleBasic(cdc), - keeper: keeper, - bankKeeper: bankKeeper, - legacySubspace: ss, - } -} - -// IsOnePerModuleType implements the depinject.OnePerModuleType interface. -func (AppModule) IsOnePerModuleType() {} - -// IsAppModule implements the appmodule.AppModule interface. -func (AppModule) IsAppModule() {} - -// Name returns the capability module's name. -func (am AppModule) Name() string { - return am.AppModuleBasic.Name() -} - -// 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(), keeper.NewQueryServerImpl(am.keeper)) - - m := keeper.NewMigrator(am.keeper, am.legacySubspace) - - if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { - panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", types.ModuleName, err)) - } -} - -// RegisterInvariants registers the capability module's invariants. -func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// InitGenesis performs the capability module's genesis initialization It returns -// no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) { - var genState types.GenesisState - // Initialize global index to index in genesis state - cdc.MustUnmarshalJSON(gs, &genState) - - InitGenesis(ctx, am.keeper, genState) -} - -// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. -func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - genState := ExportGenesis(ctx, am.keeper) - return cdc.MustMarshalJSON(genState) -} - -// ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion } - -func (am AppModule) GenerateGenesisState(_ *module.SimulationState) { -} - -func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { - return []simtypes.WeightedProposalMsg{} -} - -func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) { -} - -func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { - return []simtypes.WeightedOperation{} -} diff --git a/x/asset/types/codec.go b/x/asset/types/codec.go deleted file mode 100644 index c643b5f6..00000000 --- a/x/asset/types/codec.go +++ /dev/null @@ -1,43 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/msgservice" -) - -func RegisterCodec(cdc *codec.LegacyAmino) { - cdc.RegisterConcrete(&MsgCreateToken{}, "asset/CreateToken", nil) - cdc.RegisterConcrete(&MsgUpdateToken{}, "asset/UpdateToken", nil) - cdc.RegisterConcrete(&MsgAuthorizeAddress{}, "asset/AuthorizeAddress", nil) - cdc.RegisterConcrete(&MsgUnAuthorizeAddress{}, "asset/UnAuthorizeAddress", nil) - cdc.RegisterConcrete(&MsgTransferToken{}, "asset/TransferToken", nil) - // this line is used by starport scaffolding # 2 -} - -func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgCreateToken{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUpdateToken{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgAuthorizeAddress{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgUnAuthorizeAddress{}, - ) - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgTransferToken{}, - ) - // this line is used by starport scaffolding # 3 - - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) -} - -var ( - Amino = codec.NewLegacyAmino() - ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) -) diff --git a/x/asset/types/errors.go b/x/asset/types/errors.go index ed8cc25c..2f84afe5 100644 --- a/x/asset/types/errors.go +++ b/x/asset/types/errors.go @@ -8,9 +8,12 @@ import ( // x/asset module sentinel errors var ( - ErrSample = errorsmod.Register(ModuleName, 1100, "sample error") - ErrInvalidPacketTimeout = errorsmod.Register(ModuleName, 1500, "invalid packet timeout") - ErrInvalidVersion = errorsmod.Register(ModuleName, 1501, "invalid version") - ErrNotAuthorized = errorsmod.Register(ModuleName, 1502, "transaction not authorized") - ErrSetTokenUnable = errorsmod.Register(ModuleName, 1503, "token is unable to be set") + ErrUnauthorize = errorsmod.Register(ModuleName, 1501, "unauthorized address") + ErrTokenSet = errorsmod.Register(ModuleName, 1502, "token is unable to be set") + ErrTokenManagementSet = errorsmod.Register(ModuleName, 1503, "token management is unable to be set") + ErrTokenDistributionSet = errorsmod.Register(ModuleName, 1504, "token distribution is unable to be set") + ErrTokenGet = errorsmod.Register(ModuleName, 1505, "token is unable to be get") + ErrTokenManagementGet = errorsmod.Register(ModuleName, 1506, "token management is unable to be get") + ErrTokenDistributionGet = errorsmod.Register(ModuleName, 1507, "token distribution is unable to be get") + ErrAccAddress = errorsmod.Register(ModuleName, 1508, "unable to convert string to acc address") ) diff --git a/x/asset/types/events.go b/x/asset/types/events.go index a61b5afa..9a8cb6ea 100644 --- a/x/asset/types/events.go +++ b/x/asset/types/events.go @@ -2,12 +2,10 @@ package types // staking module event types const ( - EventTypeTokenCreated = "create_token" - EventTypeTokenUpdated = "update_token" - EventTypeTokenAuthorized = "authorize_token" - EventTypeTokenUnAuthorized = "unauthorize_token" + EventTypeTokenCreated = "create_token" + EventTypeTokenAuthorizeUpdated = "update_authorize_token" - AttributeKeySymbol = "symbol" + AttributeKeyTokenId = "token_id" AttributeKeyIndex = "index" AttributeKeyAddress = "address" diff --git a/x/asset/types/expected_keepers.go b/x/asset/types/expected_keepers.go index bfd59e4a..cee33cfb 100644 --- a/x/asset/types/expected_keepers.go +++ b/x/asset/types/expected_keepers.go @@ -3,12 +3,14 @@ package types import ( "context" + "cosmossdk.io/core/address" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) // AccountKeeper defines the expected account keeper type AccountKeeper interface { + AddressCodec() address.Codec GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI GetModuleAddress(moduleName string) sdk.AccAddress // Methods imported from account should be defined here diff --git a/x/asset/types/genesis.go b/x/asset/types/genesis.go deleted file mode 100644 index a6ac6f97..00000000 --- a/x/asset/types/genesis.go +++ /dev/null @@ -1,21 +0,0 @@ -package types - -// DefaultIndex is the default capability global index -const DefaultIndex uint64 = 1 - -// DefaultGenesis returns the default Capability genesis state -func DefaultGenesis() *GenesisState { - return &GenesisState{ - // this line is used by starport scaffolding # genesis/types/default - Params: DefaultParams(), - Tokens: []Token{}, - } -} - -// Validate performs basic genesis state validation returning an error upon any -// failure. -func (gs GenesisState) Validate() error { - // this line is used by starport scaffolding # genesis/types/validate - - return gs.Params.Validate() -} diff --git a/x/asset/types/genesis_test.go b/x/asset/types/genesis_test.go deleted file mode 100644 index 31e32dae..00000000 --- a/x/asset/types/genesis_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/realiotech/realio-network/x/asset/types" -) - -func TestGenesisState_Validate(t *testing.T) { - for _, tc := range []struct { - desc string - genState *types.GenesisState - valid bool - }{ - { - desc: "default is valid", - genState: types.DefaultGenesis(), - valid: true, - }, - { - desc: "valid genesis state", - genState: &types.GenesisState{ - Tokens: []types.Token{}, - // this line is used by starport scaffolding # types/genesis/validField - }, - valid: true, - }, - // this line is used by starport scaffolding # types/genesis/testcase - } { - t.Run(tc.desc, func(t *testing.T) { - err := tc.genState.Validate() - if tc.valid { - require.NoError(t, err) - } else { - require.Error(t, err) - } - }) - } -} diff --git a/x/asset/types/keys.go b/x/asset/types/keys.go index 7d38fe70..8e5a0431 100644 --- a/x/asset/types/keys.go +++ b/x/asset/types/keys.go @@ -1,14 +1,13 @@ package types import ( - "strings" - "cosmossdk.io/collections" ) var ( - ParamsKey = collections.NewPrefix(0) - TokenKeyPrefix = collections.NewPrefix("Token/value/") + ParamsKey = collections.NewPrefix(0) + TokenKeyPrefix = collections.NewPrefix(1) + IssuerPrefixKey = "issuer" ) const ( @@ -34,10 +33,3 @@ var PortKey = KeyPrefix("asset-port-") func KeyPrefix(p string) []byte { return []byte(p) } - -// TokenKey returns the store key to retrieve a Token from the index fields -func TokenKey( - index string, -) string { - return strings.ToLower(index) + "/" -} diff --git a/x/asset/types/message_authorize_address.go b/x/asset/types/message_authorize_address.go deleted file mode 100644 index ead47aea..00000000 --- a/x/asset/types/message_authorize_address.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgAuthorizeAddress = "authorize_address" - -var _ sdk.Msg = &MsgAuthorizeAddress{} - -func NewMsgAuthorizeAddress(manager string, symbol string, address string) *MsgAuthorizeAddress { - return &MsgAuthorizeAddress{ - Manager: manager, - Symbol: symbol, - Address: address, - } -} - -func (msg *MsgAuthorizeAddress) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s)", err) - } - return nil -} diff --git a/x/asset/types/message_create_token.go b/x/asset/types/message_create_token.go deleted file mode 100644 index 0b080bde..00000000 --- a/x/asset/types/message_create_token.go +++ /dev/null @@ -1,29 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgCreateToken = "create_token" - -var _ sdk.Msg = &MsgCreateToken{} - -func NewMsgCreateToken(manager string, name string, symbol string, total string, authorizationRequired bool) *MsgCreateToken { - return &MsgCreateToken{ - Manager: manager, - Name: name, - Symbol: symbol, - Total: total, - AuthorizationRequired: authorizationRequired, - } -} - -func (msg *MsgCreateToken) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s)", err) - } - return nil -} diff --git a/x/asset/types/message_test.go b/x/asset/types/message_test.go deleted file mode 100644 index 37e991d1..00000000 --- a/x/asset/types/message_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package types - -import ( - "testing" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/suite" - - "github.com/realiotech/realio-network/testutil" -) - -type MessageTestSuite struct { - suite.Suite -} - -func TestMessageAuthorizeTestSuite(t *testing.T) { - suite.Run(t, new(MessageTestSuite)) -} - -func (suite *MessageTestSuite) TestMsgAuthorizeAddress_ValidateBasic() { - tests := []struct { - name string - msg MsgAuthorizeAddress - err error - }{ - { - name: "invalid address", - msg: MsgAuthorizeAddress{ - Manager: "invalid_address", - }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "valid address", - msg: MsgAuthorizeAddress{ - Manager: testutil.GenAddress().String(), - }, - }, - } - for _, tt := range tests { - err := tt.msg.ValidateBasic() - if tt.err != nil { - suite.Require().ErrorIs(err, tt.err) - return - } - suite.Require().NoError(err) - } -} - -func (suite *MessageTestSuite) TestMsgCreateToken_ValidateBasic() { - tests := []struct { - name string - msg MsgCreateToken - err error - }{ - { - name: "invalid address", - msg: MsgCreateToken{ - Manager: "invalid_address", - }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "valid address", - msg: MsgCreateToken{ - Manager: testutil.GenAddress().String(), - }, - }, - } - for _, tt := range tests { - err := tt.msg.ValidateBasic() - if tt.err != nil { - suite.Require().ErrorIs(err, tt.err) - return - } - suite.Require().NoError(err) - } -} - -func (suite *MessageTestSuite) TestMsgTransferToken_ValidateBasic() { - tests := []struct { - name string - msg MsgTransferToken - err error - }{ - { - name: "invalid address", - msg: MsgTransferToken{ - From: "invalid_address", - }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "valid address", - msg: MsgTransferToken{ - To: testutil.GenAddress().String(), - From: testutil.GenAddress().String(), - }, - }, - } - for _, tt := range tests { - err := tt.msg.ValidateBasic() - if tt.err != nil { - suite.Require().ErrorIs(err, tt.err) - return - } - suite.Require().NoError(err) - } -} - -func (suite *MessageTestSuite) TestMsgUnAuthorizeAddress_ValidateBasic() { - tests := []struct { - name string - msg MsgUnAuthorizeAddress - err error - }{ - { - name: "invalid address", - msg: MsgUnAuthorizeAddress{ - Manager: "invalid_address", - }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "valid address", - msg: MsgUnAuthorizeAddress{ - Manager: testutil.GenAddress().String(), - }, - }, - } - for _, tt := range tests { - err := tt.msg.ValidateBasic() - if tt.err != nil { - suite.Require().ErrorIs(err, tt.err) - return - } - suite.Require().NoError(err) - } -} - -func (suite *MessageTestSuite) TestMsgUpdateToken_ValidateBasic() { - tests := []struct { - name string - msg MsgUpdateToken - err error - }{ - { - name: "invalid address", - msg: MsgUpdateToken{ - Manager: "invalid_address", - }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "valid address", - msg: MsgUpdateToken{ - Manager: testutil.GenAddress().String(), - }, - }, - } - for _, tt := range tests { - err := tt.msg.ValidateBasic() - if tt.err != nil { - suite.Require().ErrorIs(err, tt.err) - return - } - suite.Require().NoError(err) - } -} diff --git a/x/asset/types/message_transfer_token.go b/x/asset/types/message_transfer_token.go deleted file mode 100644 index 000ef3ef..00000000 --- a/x/asset/types/message_transfer_token.go +++ /dev/null @@ -1,31 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgTransferToken = "transfer_token" - -var _ sdk.Msg = &MsgTransferToken{} - -func NewMsgTransferToken(symbol string, from string, to string, amount string) *MsgTransferToken { - return &MsgTransferToken{ - Symbol: symbol, - From: from, - To: to, - Amount: amount, - } -} - -func (msg *MsgTransferToken) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(msg.From); err != nil { - return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %s", err) - } - - if _, err := sdk.AccAddressFromBech32(msg.To); err != nil { - return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) - } - - return nil -} diff --git a/x/asset/types/message_un_authorize_address.go b/x/asset/types/message_un_authorize_address.go deleted file mode 100644 index c62cd23c..00000000 --- a/x/asset/types/message_un_authorize_address.go +++ /dev/null @@ -1,29 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUnAuthorizeAddress = "un_authorize_address" - -var _ sdk.Msg = &MsgUnAuthorizeAddress{} - -func NewMsgUnAuthorizeAddress(manager string, symbol string, address string) *MsgUnAuthorizeAddress { - return &MsgUnAuthorizeAddress{ - Manager: manager, - Symbol: symbol, - Address: address, - } -} - -func (msg *MsgUnAuthorizeAddress) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(msg.Manager); err != nil { - return sdkerrors.ErrInvalidAddress.Wrapf("invalid manager address: %s", err) - } - if _, err := sdk.AccAddressFromBech32(msg.Address); err != nil { - return sdkerrors.ErrInvalidAddress.Wrapf("invalid address: %s", err) - } - - return nil -} diff --git a/x/asset/types/message_update_token.go b/x/asset/types/message_update_token.go deleted file mode 100644 index bc47e09d..00000000 --- a/x/asset/types/message_update_token.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -const TypeMsgUpdateToken = "update_token" - -var _ sdk.Msg = &MsgUpdateToken{} - -func NewMsgUpdateToken(manager string, symbol string, authorizationRequired bool) *MsgUpdateToken { - return &MsgUpdateToken{ - Manager: manager, - Symbol: symbol, - AuthorizationRequired: authorizationRequired, - } -} - -func (msg *MsgUpdateToken) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s)", err) - } - return nil -} diff --git a/x/asset/types/msgs.go b/x/asset/types/msgs.go new file mode 100644 index 00000000..4cd09bb5 --- /dev/null +++ b/x/asset/types/msgs.go @@ -0,0 +1,76 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var _ sdk.Msg = &MsgCreateToken{} + +func NewMsgCreateToken(issuer string, name string, symbol string, description string, decimal uint32, managers, distributors, extensionsList []string, allowNewExtensions bool) *MsgCreateToken { + return &MsgCreateToken{ + Issuer: issuer, + Name: name, + Symbol: symbol, + Description: description, + Decimal: decimal, + Managers: managers, + Distributors: distributors, + ExtensionsList: extensionsList, + AllowNewExtensions: allowNewExtensions, + } +} + +func (msg *MsgCreateToken) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Issuer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) + } + for _, manager := range msg.Managers { + _, err := sdk.AccAddressFromBech32(manager) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) + } + } + + for _, distributor := range msg.Distributors { + _, err := sdk.AccAddressFromBech32(distributor) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) + } + } + return nil +} + +func NewMsgAssignRoles(issuer string, tokenId string, managers []string, distributors []string) *MsgAssignRoles { + return &MsgAssignRoles{ + Issuer: issuer, + TokenId: tokenId, + Managers: managers, + Distributors: distributors, + } +} + +func (msg *MsgAssignRoles) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Issuer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) + } + + for _, manager := range msg.Managers { + _, err := sdk.AccAddressFromBech32(manager) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) + } + } + + for _, distributor := range msg.Distributors { + _, err := sdk.AccAddressFromBech32(distributor) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) + } + } + + return ValidateTokenId(msg.TokenId) +} diff --git a/x/asset/types/params.go b/x/asset/types/params.go index 5989f733..18f98de6 100644 --- a/x/asset/types/params.go +++ b/x/asset/types/params.go @@ -1,6 +1,10 @@ package types -import "gopkg.in/yaml.v2" +import ( + "fmt" + + "gopkg.in/yaml.v2" +) // NewParams creates a new Params instance func NewParams() Params { @@ -14,6 +18,11 @@ func DefaultParams() Params { // Validate validates the set of params func (p Params) Validate() error { + for _, extension := range p.AllowExtensions { + if extension == "" { + return fmt.Errorf("Extension can not be empty") + } + } return nil } diff --git a/x/asset/types/params.pb.go b/x/asset/types/params.pb.go index 1cdcd055..b96710a5 100644 --- a/x/asset/types/params.pb.go +++ b/x/asset/types/params.pb.go @@ -25,6 +25,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the module. type Params struct { + AllowExtensions []string `protobuf:"bytes,1,rep,name=allow_extensions,json=allowExtensions,proto3" json:"allow_extensions,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -59,6 +60,13 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetAllowExtensions() []string { + if m != nil { + return m.AllowExtensions + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "realionetwork.asset.v1.Params") } @@ -68,18 +76,20 @@ func init() { } var fileDescriptor_d68d5b1218748d2a = []byte{ - // 162 bytes of a gzipped FileDescriptorProto + // 195 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2e, 0x4a, 0x4d, 0xcc, 0xc9, 0xcc, 0xcf, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, 0xd6, 0x4f, 0x2c, 0x2e, 0x4e, 0x2d, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x43, 0x51, 0xa4, 0x07, 0x56, 0xa4, 0x57, 0x66, 0x28, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, - 0x56, 0xa2, 0x0f, 0x62, 0x41, 0x54, 0x2b, 0xf1, 0x71, 0xb1, 0x05, 0x80, 0x75, 0x5b, 0xb1, 0xcc, - 0x58, 0x20, 0xcf, 0xe0, 0xe4, 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, - 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, - 0x46, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x10, 0x2b, 0x4a, 0x52, - 0x93, 0x33, 0xa0, 0x4c, 0x5d, 0x98, 0x9b, 0x2a, 0xa0, 0xae, 0x2a, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, - 0x62, 0x03, 0x5b, 0x62, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x30, 0xc3, 0xf2, 0x1b, 0xb9, 0x00, - 0x00, 0x00, + 0x56, 0xa2, 0x0f, 0x62, 0x41, 0x54, 0x2b, 0x59, 0x72, 0xb1, 0x05, 0x80, 0x75, 0x0b, 0x69, 0x72, + 0x09, 0x24, 0xe6, 0xe4, 0xe4, 0x97, 0xc7, 0xa7, 0x56, 0x94, 0xa4, 0xe6, 0x15, 0x67, 0xe6, 0xe7, + 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6b, 0x70, 0x06, 0xf1, 0x83, 0xc5, 0x5d, 0xe1, 0xc2, 0x56, 0x2c, + 0x33, 0x16, 0xc8, 0x33, 0x38, 0xf9, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, + 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, + 0x94, 0x51, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xc4, 0x35, 0x25, + 0xa9, 0xc9, 0x19, 0x50, 0xa6, 0x2e, 0xcc, 0xf9, 0x15, 0x50, 0x0f, 0x94, 0x54, 0x16, 0xa4, 0x16, + 0x27, 0xb1, 0x81, 0xdd, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x28, 0xcd, 0xe4, + 0x00, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -102,6 +112,15 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AllowExtensions) > 0 { + for iNdEx := len(m.AllowExtensions) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AllowExtensions[iNdEx]) + copy(dAtA[i:], m.AllowExtensions[iNdEx]) + i = encodeVarintParams(dAtA, i, uint64(len(m.AllowExtensions[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } return len(dAtA) - i, nil } @@ -122,6 +141,12 @@ func (m *Params) Size() (n int) { } var l int _ = l + if len(m.AllowExtensions) > 0 { + for _, s := range m.AllowExtensions { + l = len(s) + n += 1 + l + sovParams(uint64(l)) + } + } return n } @@ -160,6 +185,38 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowExtensions", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowExtensions = append(m.AllowExtensions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) diff --git a/x/asset/types/params_legacy.go b/x/asset/types/params_legacy.go deleted file mode 100644 index 9d9c8e1a..00000000 --- a/x/asset/types/params_legacy.go +++ /dev/null @@ -1,17 +0,0 @@ -package types - -import ( - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -) - -var _ paramtypes.ParamSet = (*Params)(nil) - -// ParamKeyTable the param key table for launch module -func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) -} - -// ParamSetPairs get the params.ParamSet -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{} -} diff --git a/x/asset/types/query.go b/x/asset/types/query.go deleted file mode 100644 index 0946bcd7..00000000 --- a/x/asset/types/query.go +++ /dev/null @@ -1,6 +0,0 @@ -package types - -// NewQueryTokenRequest creates a new instance of QueryTokenRequest. -func NewQueryTokenRequest(symbol string) *QueryTokenRequest { - return &QueryTokenRequest{Symbol: symbol} -} diff --git a/x/asset/types/query.pb.go b/x/asset/types/query.pb.go index d811a746..024cf8ff 100644 --- a/x/asset/types/query.pb.go +++ b/x/asset/types/query.pb.go @@ -287,106 +287,6 @@ func (m *QueryTokenResponse) GetToken() Token { return Token{} } -// QueryParamsRequest is request type for the Query/Params RPC method. -type QueryIsAuthorizedRequest struct { - // symbol is the token symbol to query for. - Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"` - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *QueryIsAuthorizedRequest) Reset() { *m = QueryIsAuthorizedRequest{} } -func (m *QueryIsAuthorizedRequest) String() string { return proto.CompactTextString(m) } -func (*QueryIsAuthorizedRequest) ProtoMessage() {} -func (*QueryIsAuthorizedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_b6e3fc89e45a1671, []int{6} -} -func (m *QueryIsAuthorizedRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryIsAuthorizedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryIsAuthorizedRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryIsAuthorizedRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryIsAuthorizedRequest.Merge(m, src) -} -func (m *QueryIsAuthorizedRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryIsAuthorizedRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryIsAuthorizedRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryIsAuthorizedRequest proto.InternalMessageInfo - -func (m *QueryIsAuthorizedRequest) GetSymbol() string { - if m != nil { - return m.Symbol - } - return "" -} - -func (m *QueryIsAuthorizedRequest) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -// QueryParamsResponse is response type for the Query/Params RPC method. -type QueryIsAuthorizedResponse struct { - // params holds all the parameters of this module. - IsAuthorized bool `protobuf:"varint,1,opt,name=isAuthorized,proto3" json:"isAuthorized,omitempty"` -} - -func (m *QueryIsAuthorizedResponse) Reset() { *m = QueryIsAuthorizedResponse{} } -func (m *QueryIsAuthorizedResponse) String() string { return proto.CompactTextString(m) } -func (*QueryIsAuthorizedResponse) ProtoMessage() {} -func (*QueryIsAuthorizedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_b6e3fc89e45a1671, []int{7} -} -func (m *QueryIsAuthorizedResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryIsAuthorizedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryIsAuthorizedResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryIsAuthorizedResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryIsAuthorizedResponse.Merge(m, src) -} -func (m *QueryIsAuthorizedResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryIsAuthorizedResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryIsAuthorizedResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryIsAuthorizedResponse proto.InternalMessageInfo - -func (m *QueryIsAuthorizedResponse) GetIsAuthorized() bool { - if m != nil { - return m.IsAuthorized - } - return false -} - func init() { proto.RegisterType((*QueryParamsRequest)(nil), "realionetwork.asset.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "realionetwork.asset.v1.QueryParamsResponse") @@ -394,8 +294,6 @@ func init() { proto.RegisterType((*QueryTokensResponse)(nil), "realionetwork.asset.v1.QueryTokensResponse") proto.RegisterType((*QueryTokenRequest)(nil), "realionetwork.asset.v1.QueryTokenRequest") proto.RegisterType((*QueryTokenResponse)(nil), "realionetwork.asset.v1.QueryTokenResponse") - proto.RegisterType((*QueryIsAuthorizedRequest)(nil), "realionetwork.asset.v1.QueryIsAuthorizedRequest") - proto.RegisterType((*QueryIsAuthorizedResponse)(nil), "realionetwork.asset.v1.QueryIsAuthorizedResponse") } func init() { @@ -403,40 +301,34 @@ func init() { } var fileDescriptor_b6e3fc89e45a1671 = []byte{ - // 513 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6f, 0xd3, 0x30, - 0x14, 0xc7, 0x9b, 0xb1, 0x06, 0xf0, 0x76, 0xc1, 0x4c, 0x53, 0xa9, 0xc0, 0x4c, 0x46, 0x82, 0xfd, - 0x10, 0x31, 0x2d, 0x07, 0x34, 0x81, 0x34, 0xb1, 0x1b, 0xd2, 0x24, 0x20, 0x70, 0xe2, 0xe6, 0xae, - 0x56, 0x1a, 0xad, 0x8d, 0xb3, 0xd8, 0x1d, 0x94, 0x69, 0x17, 0x6e, 0x9c, 0x40, 0xe2, 0x5f, 0xe1, - 0x8f, 0xd8, 0x71, 0x12, 0x17, 0x4e, 0x08, 0xb5, 0x1c, 0xf8, 0x33, 0x50, 0x9e, 0x9d, 0xd0, 0x88, - 0xa6, 0x29, 0xb7, 0xe4, 0xe5, 0x7d, 0xdf, 0xe7, 0x63, 0xf9, 0x29, 0x88, 0x26, 0x82, 0xf7, 0x43, - 0x19, 0x09, 0xfd, 0x56, 0x26, 0x47, 0x8c, 0x2b, 0x25, 0x34, 0x3b, 0x69, 0xb1, 0xe3, 0xa1, 0x48, - 0x46, 0x5e, 0x9c, 0x48, 0x2d, 0xf1, 0x7a, 0xa1, 0xc7, 0x83, 0x1e, 0xef, 0xa4, 0xd5, 0x5c, 0x0b, - 0x64, 0x20, 0xa1, 0x85, 0xa5, 0x4f, 0xa6, 0xbb, 0x79, 0x33, 0x90, 0x32, 0xe8, 0x0b, 0xc6, 0xe3, - 0x90, 0xf1, 0x28, 0x92, 0x9a, 0xeb, 0x50, 0x46, 0xca, 0x7e, 0xbd, 0x53, 0xc2, 0x8b, 0x79, 0xc2, - 0x07, 0x59, 0x53, 0x99, 0x94, 0x96, 0x47, 0x22, 0x32, 0x3d, 0x74, 0x0d, 0xe1, 0x97, 0xa9, 0xe3, - 0x0b, 0x08, 0xfa, 0xe2, 0x78, 0x28, 0x94, 0xa6, 0xaf, 0xd0, 0xf5, 0x42, 0x55, 0xc5, 0x32, 0x52, - 0x02, 0x3f, 0x41, 0xae, 0x01, 0x34, 0x9c, 0x0d, 0x67, 0x73, 0xa5, 0x4d, 0xbc, 0xd9, 0x47, 0xf2, - 0x4c, 0x6e, 0x7f, 0xf9, 0xfc, 0xc7, 0xed, 0x9a, 0x6f, 0x33, 0x39, 0xea, 0x75, 0x8a, 0xcf, 0x51, - 0xbe, 0x45, 0x65, 0x55, 0x8b, 0x7a, 0x8c, 0x5c, 0xd0, 0x4c, 0x51, 0x97, 0x36, 0x57, 0xda, 0xb7, - 0xca, 0x50, 0x90, 0xcb, 0x48, 0x26, 0x42, 0x77, 0xd0, 0xb5, 0xbf, 0x33, 0x2d, 0x08, 0xaf, 0x23, - 0x57, 0x8d, 0x06, 0x1d, 0xd9, 0x07, 0xf9, 0xab, 0xbe, 0x7d, 0xa3, 0xcf, 0xa7, 0xb5, 0x72, 0xfe, - 0x2e, 0xaa, 0xc3, 0x30, 0x7b, 0xd2, 0x85, 0xf0, 0x26, 0x41, 0x0f, 0x50, 0x03, 0x06, 0x3e, 0x53, - 0x4f, 0x87, 0xba, 0x27, 0x93, 0xf0, 0xbd, 0xe8, 0x56, 0x48, 0xe0, 0x06, 0xba, 0xcc, 0xbb, 0xdd, - 0x44, 0x28, 0xd5, 0x58, 0x82, 0x0f, 0xd9, 0x2b, 0xdd, 0x43, 0x37, 0x66, 0x4c, 0xb3, 0x96, 0x14, - 0xad, 0x86, 0x53, 0x75, 0x18, 0x7a, 0xc5, 0x2f, 0xd4, 0xda, 0xbf, 0x97, 0x51, 0x1d, 0x26, 0xe0, - 0x8f, 0x0e, 0x72, 0xcd, 0xcd, 0xe0, 0xed, 0xb2, 0xf3, 0xfc, 0xbb, 0x0c, 0xcd, 0x9d, 0x85, 0x7a, - 0x8d, 0x11, 0xbd, 0xfb, 0xe1, 0xdb, 0xaf, 0x2f, 0x4b, 0x1b, 0x98, 0xb0, 0xb9, 0x1b, 0x0a, 0x2e, - 0xe6, 0xca, 0x2b, 0x5c, 0x0a, 0xdb, 0x52, 0xe1, 0x52, 0xdc, 0xa1, 0x6a, 0x17, 0xb3, 0x2e, 0xf8, - 0x93, 0x83, 0xea, 0x10, 0xc5, 0x5b, 0xd5, 0xe3, 0x33, 0x93, 0xed, 0x45, 0x5a, 0xad, 0x08, 0x03, - 0x91, 0x2d, 0x7c, 0x6f, 0xbe, 0x08, 0x3b, 0x35, 0xdb, 0x70, 0x86, 0xbf, 0x3a, 0x68, 0x75, 0xfa, - 0xc2, 0xf1, 0x83, 0xb9, 0xb4, 0x19, 0x9b, 0xd6, 0x6c, 0xfd, 0x47, 0xc2, 0x6a, 0xee, 0x81, 0xe6, - 0x2e, 0x7e, 0x54, 0xa6, 0x19, 0x2a, 0x9e, 0xa7, 0x72, 0x59, 0x76, 0x6a, 0x57, 0xf5, 0x6c, 0xff, - 0xe0, 0x7c, 0x4c, 0x9c, 0x8b, 0x31, 0x71, 0x7e, 0x8e, 0x89, 0xf3, 0x79, 0x42, 0x6a, 0x17, 0x13, - 0x52, 0xfb, 0x3e, 0x21, 0xb5, 0x37, 0xed, 0x20, 0xd4, 0xbd, 0x61, 0xc7, 0x3b, 0x94, 0x03, 0x3b, - 0x5c, 0x8b, 0xc3, 0x9e, 0x7d, 0xbc, 0x9f, 0x81, 0xde, 0x59, 0x94, 0x1e, 0xc5, 0x42, 0x75, 0x5c, - 0xf8, 0x43, 0x3d, 0xfc, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x45, 0x42, 0x94, 0x5c, 0x05, 0x00, - 0x00, + // 421 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6e, 0xda, 0x30, + 0x1c, 0xc7, 0x93, 0x31, 0x22, 0xcd, 0x9c, 0xe6, 0x21, 0x34, 0xa1, 0xcd, 0x43, 0x99, 0xb4, 0xf1, + 0x47, 0x8b, 0x45, 0x76, 0x9a, 0xd6, 0x13, 0xe7, 0x4a, 0x6d, 0xd3, 0x9e, 0x7a, 0x0b, 0xc8, 0x0a, + 0x11, 0x10, 0x87, 0xd8, 0xd0, 0xa2, 0xaa, 0x97, 0xde, 0x7a, 0x6a, 0xa5, 0x3e, 0x49, 0xdf, 0x82, + 0x23, 0x52, 0x2f, 0x3d, 0x55, 0x15, 0xf4, 0x41, 0xaa, 0xd8, 0x0e, 0x6d, 0xd4, 0x86, 0x70, 0x33, + 0xe6, 0xfb, 0xe7, 0x63, 0xff, 0x1c, 0x60, 0x46, 0xc4, 0x1d, 0xfa, 0x34, 0x20, 0xfc, 0x84, 0x46, + 0x03, 0xec, 0x32, 0x46, 0x38, 0x9e, 0xb6, 0xf1, 0x78, 0x42, 0xa2, 0x99, 0x15, 0x46, 0x94, 0x53, + 0x58, 0x49, 0x69, 0x2c, 0xa1, 0xb1, 0xa6, 0xed, 0x6a, 0xd9, 0xa3, 0x1e, 0x15, 0x12, 0x1c, 0xaf, + 0xa4, 0xba, 0xfa, 0xcd, 0xa3, 0xd4, 0x1b, 0x12, 0xec, 0x86, 0x3e, 0x76, 0x83, 0x80, 0x72, 0x97, + 0xfb, 0x34, 0x60, 0xea, 0xdf, 0x9f, 0x19, 0x7d, 0xa1, 0x1b, 0xb9, 0xa3, 0x44, 0x94, 0x05, 0xc5, + 0xe9, 0x80, 0x04, 0x52, 0x63, 0x96, 0x01, 0x3c, 0x88, 0x19, 0xf7, 0x85, 0xd1, 0x21, 0xe3, 0x09, + 0x61, 0xdc, 0x3c, 0x04, 0x5f, 0x52, 0xbb, 0x2c, 0xa4, 0x01, 0x23, 0x70, 0x07, 0x18, 0xb2, 0xe0, + 0xab, 0x5e, 0xd3, 0xeb, 0x25, 0x1b, 0x59, 0xef, 0x1f, 0xc9, 0x92, 0xbe, 0xce, 0xc7, 0xf9, 0xc3, + 0x0f, 0xcd, 0x51, 0x9e, 0x75, 0xd5, 0x51, 0x5c, 0xbf, 0xae, 0x72, 0x54, 0x55, 0xb2, 0xab, 0xaa, + 0xfe, 0x03, 0x43, 0x60, 0xc6, 0x55, 0x85, 0x7a, 0xc9, 0xfe, 0x9e, 0x55, 0x25, 0x7c, 0x49, 0x93, + 0xb4, 0x98, 0x2d, 0xf0, 0xf9, 0x25, 0x53, 0x15, 0xc1, 0x0a, 0x30, 0xd8, 0x6c, 0xd4, 0xa5, 0x43, + 0x01, 0xff, 0xc9, 0x51, 0xbf, 0xcc, 0xbd, 0xd7, 0x58, 0xeb, 0xfe, 0x7f, 0xa0, 0x28, 0xc2, 0xd4, + 0x49, 0xb7, 0xaa, 0x97, 0x0e, 0xfb, 0xb6, 0x00, 0x8a, 0x22, 0x11, 0x5e, 0xea, 0xc0, 0x90, 0x57, + 0x01, 0x9b, 0x59, 0x01, 0x6f, 0x6f, 0xbf, 0xda, 0xda, 0x4a, 0x2b, 0x41, 0xcd, 0x5f, 0x17, 0x77, + 0x4f, 0x37, 0x1f, 0x6a, 0x10, 0xe1, 0x8d, 0x4f, 0x42, 0xb0, 0xc8, 0x3b, 0xce, 0x61, 0x49, 0x8d, + 0x27, 0x87, 0x25, 0x3d, 0xb4, 0x7c, 0x16, 0x39, 0x1f, 0x78, 0xa5, 0x83, 0xa2, 0xb0, 0xc2, 0x46, + 0x7e, 0x7c, 0x42, 0xd2, 0xdc, 0x46, 0xaa, 0x40, 0xb0, 0x00, 0x69, 0xc0, 0xdf, 0x9b, 0x41, 0xf0, + 0x99, 0x7c, 0x03, 0xe7, 0x9d, 0xdd, 0xf9, 0x12, 0xe9, 0x8b, 0x25, 0xd2, 0x1f, 0x97, 0x48, 0xbf, + 0x5e, 0x21, 0x6d, 0xb1, 0x42, 0xda, 0xfd, 0x0a, 0x69, 0xc7, 0xb6, 0xe7, 0xf3, 0xfe, 0xa4, 0x6b, + 0xf5, 0xe8, 0x48, 0x85, 0x71, 0xd2, 0xeb, 0xab, 0xe5, 0x9f, 0x24, 0xf8, 0x54, 0x45, 0xf3, 0x59, + 0x48, 0x58, 0xd7, 0x10, 0xdf, 0xd6, 0xdf, 0xe7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6f, 0xf4, 0x3b, + 0x34, 0x16, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -457,8 +349,6 @@ type QueryClient interface { Tokens(ctx context.Context, in *QueryTokensRequest, opts ...grpc.CallOption) (*QueryTokensResponse, error) // Parameters queries the tokens of the module. Token(ctx context.Context, in *QueryTokenRequest, opts ...grpc.CallOption) (*QueryTokenResponse, error) - // Parameters queries the tokens of the module. - IsAuthorized(ctx context.Context, in *QueryIsAuthorizedRequest, opts ...grpc.CallOption) (*QueryIsAuthorizedResponse, error) } type queryClient struct { @@ -496,15 +386,6 @@ func (c *queryClient) Token(ctx context.Context, in *QueryTokenRequest, opts ... return out, nil } -func (c *queryClient) IsAuthorized(ctx context.Context, in *QueryIsAuthorizedRequest, opts ...grpc.CallOption) (*QueryIsAuthorizedResponse, error) { - out := new(QueryIsAuthorizedResponse) - err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Query/IsAuthorized", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // QueryServer is the server API for Query service. type QueryServer interface { // Parameters queries the parameters of the module. @@ -513,8 +394,6 @@ type QueryServer interface { Tokens(context.Context, *QueryTokensRequest) (*QueryTokensResponse, error) // Parameters queries the tokens of the module. Token(context.Context, *QueryTokenRequest) (*QueryTokenResponse, error) - // Parameters queries the tokens of the module. - IsAuthorized(context.Context, *QueryIsAuthorizedRequest) (*QueryIsAuthorizedResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -530,9 +409,6 @@ func (*UnimplementedQueryServer) Tokens(ctx context.Context, req *QueryTokensReq func (*UnimplementedQueryServer) Token(ctx context.Context, req *QueryTokenRequest) (*QueryTokenResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Token not implemented") } -func (*UnimplementedQueryServer) IsAuthorized(ctx context.Context, req *QueryIsAuthorizedRequest) (*QueryIsAuthorizedResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IsAuthorized not implemented") -} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -592,24 +468,6 @@ func _Query_Token_Handler(srv interface{}, ctx context.Context, dec func(interfa return interceptor(ctx, in, info, handler) } -func _Query_IsAuthorized_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryIsAuthorizedRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).IsAuthorized(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/realionetwork.asset.v1.Query/IsAuthorized", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).IsAuthorized(ctx, req.(*QueryIsAuthorizedRequest)) - } - return interceptor(ctx, in, info, handler) -} - var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "realionetwork.asset.v1.Query", HandlerType: (*QueryServer)(nil), @@ -626,10 +484,6 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Token", Handler: _Query_Token_Handler, }, - { - MethodName: "IsAuthorized", - Handler: _Query_IsAuthorized_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "realionetwork/asset/v1/query.proto", @@ -814,76 +668,6 @@ func (m *QueryTokenResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryIsAuthorizedRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryIsAuthorizedRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryIsAuthorizedRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0x12 - } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Symbol))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *QueryIsAuthorizedResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryIsAuthorizedResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryIsAuthorizedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.IsAuthorized { - i-- - if m.IsAuthorized { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -963,35 +747,6 @@ func (m *QueryTokenResponse) Size() (n int) { return n } -func (m *QueryIsAuthorizedRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Symbol) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.Address) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *QueryIsAuthorizedResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.IsAuthorized { - n += 2 - } - return n -} - func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1430,190 +1185,6 @@ func (m *QueryTokenResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryIsAuthorizedRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryIsAuthorizedRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryIsAuthorizedRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Symbol = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryIsAuthorizedResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryIsAuthorizedResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryIsAuthorizedResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsAuthorized", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.IsAuthorized = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/asset/types/query.pb.gw.go b/x/asset/types/query.pb.gw.go index e9d9ece9..4c943a0a 100644 --- a/x/asset/types/query.pb.gw.go +++ b/x/asset/types/query.pb.gw.go @@ -123,82 +123,6 @@ func local_request_Query_Token_0(ctx context.Context, marshaler runtime.Marshale } -func request_Query_IsAuthorized_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryIsAuthorizedRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["symbol"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "symbol") - } - - protoReq.Symbol, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "symbol", err) - } - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - msg, err := client.IsAuthorized(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_IsAuthorized_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryIsAuthorizedRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["symbol"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "symbol") - } - - protoReq.Symbol, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "symbol", err) - } - - val, ok = pathParams["address"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") - } - - protoReq.Address, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) - } - - msg, err := server.IsAuthorized(ctx, &protoReq) - return msg, metadata, err - -} - // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -274,29 +198,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_IsAuthorized_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_IsAuthorized_0(rctx, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_IsAuthorized_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -398,26 +299,6 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_IsAuthorized_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_IsAuthorized_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_IsAuthorized_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -427,8 +308,6 @@ var ( pattern_Query_Tokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"realionetwork", "asset", "v1", "tokens"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Token_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"realionetwork", "asset", "v1", "tokens", "symbol"}, "", runtime.AssumeColonVerbOpt(false))) - - pattern_Query_IsAuthorized_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"realionetwork", "asset", "v1", "isauthorized", "symbol", "address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -437,6 +316,4 @@ var ( forward_Query_Tokens_0 = runtime.ForwardResponseMessage forward_Query_Token_0 = runtime.ForwardResponseMessage - - forward_Query_IsAuthorized_0 = runtime.ForwardResponseMessage ) diff --git a/x/asset/types/token.go b/x/asset/types/token.go index 600cc100..88e7a608 100644 --- a/x/asset/types/token.go +++ b/x/asset/types/token.go @@ -1,53 +1,59 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + fmt "fmt" + "strings" -func NewToken(name string, symbol string, total string, manager string, authorizationRequired bool) Token { + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewToken creates a new Token instance +func NewToken(id, name string, decimal uint32, description string, symbol string, issuer string) Token { return Token{ - Name: name, - Symbol: symbol, - Total: total, - Manager: manager, - AuthorizationRequired: authorizationRequired, - Authorized: []*TokenAuthorization{}, + TokenId: id, + Name: name, + Decimal: decimal, + Description: description, + Symbol: symbol, + Issuer: issuer, } } -func NewAuthorization(address sdk.Address) *TokenAuthorization { - return &TokenAuthorization{Address: address.String(), Authorized: true} +func NewTokenManagement(managers []string, allowNewExtension bool, extensionList []string) TokenManagement { + return TokenManagement{ + Managers: managers, + AllowNewExtensions: allowNewExtension, + ExtensionsList: extensionList, + } } -func (t *Token) AuthorizeAddress(addr sdk.Address) *Token { - found := false - for _, a := range t.Authorized { - if a.Address == addr.String() { - a.Authorized = true - found = true - break - } - } - if !found { - newAuthorized := NewAuthorization(addr) - t.Authorized = append(t.Authorized, newAuthorized) +func NewTokenDistribution(distributors []string, maxSupply math.Int) TokenDistribution { + return TokenDistribution{ + Distributors: distributors, + MaxSupply: maxSupply, } - return t } -func (t *Token) UnAuthorizeAddress(addr sdk.Address) *Token { - for _, a := range t.Authorized { - if a.Address == addr.String() { - a.Authorized = false - break - } +func ValidateTokenId(tokenId string) error { + tokenParts := strings.Split(tokenId, "/") + if len(tokenParts) < 3 { + return fmt.Errorf("invalid token id format, should be asset/IssuerAddress/lowercaseTokenName") } - return t -} -func (t *Token) AddressIsAuthorized(addr sdk.AccAddress) bool { - for _, a := range t.Authorized { - if a.Address == addr.String() && a.Authorized { - return true - } + if tokenParts[0] != ModuleName { + return fmt.Errorf("invalid token id format, should be asset/IssuerAddress/lowercaseTokenName") } - return false + + _, err := sdk.AccAddressFromBech32(tokenParts[1]) + if err != nil { + return fmt.Errorf("invalid issuer address") + } + + tokenName := strings.Join(tokenParts[2:], "/") + if strings.ToLower(tokenName) != tokenName { + return fmt.Errorf("token name should be in lower case") + } + + return nil } diff --git a/x/asset/types/token.pb.go b/x/asset/types/token.pb.go index dac78eed..56b0ddd8 100644 --- a/x/asset/types/token.pb.go +++ b/x/asset/types/token.pb.go @@ -4,6 +4,7 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" @@ -23,14 +24,46 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type Role int32 + +const ( + // ROLE_UNSPECIFIED defines a no-op role. + EmptyRole Role = 0 + // ROLE_MANAGER defines a token manager role. + ManagerRole Role = 1 + // ROLE_DISTRIBUTOR defines a token distributor role. + DistributorRole Role = 2 +) + +var Role_name = map[int32]string{ + 0: "ROLE_UNSPECIFIED", + 1: "ROLE_MANAGER", + 2: "ROLE_DISTRIBUTOR", +} + +var Role_value = map[string]int32{ + "ROLE_UNSPECIFIED": 0, + "ROLE_MANAGER": 1, + "ROLE_DISTRIBUTOR": 2, +} + +func (x Role) String() string { + return proto.EnumName(Role_name, int32(x)) +} + +func (Role) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_2f83138fc60a3176, []int{0} +} + // Token represents an asset in the module 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 string `protobuf:"bytes,3,opt,name=total,proto3" json:"total,omitempty"` - AuthorizationRequired bool `protobuf:"varint,4,opt,name=authorizationRequired,proto3" json:"authorizationRequired,omitempty"` - Manager string `protobuf:"bytes,5,opt,name=manager,proto3" json:"manager,omitempty"` - Authorized []*TokenAuthorization `protobuf:"bytes,6,rep,name=authorized,proto3" json:"authorized,omitempty"` + TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` + Decimal uint32 `protobuf:"varint,5,opt,name=decimal,proto3" json:"decimal,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + EvmAddress string `protobuf:"bytes,9,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` } func (m *Token) Reset() { *m = Token{} } @@ -66,6 +99,20 @@ func (m *Token) XXX_DiscardUnknown() { var xxx_messageInfo_Token proto.InternalMessageInfo +func (m *Token) GetTokenId() string { + if m != nil { + return m.TokenId + } + return "" +} + +func (m *Token) GetIssuer() string { + if m != nil { + return m.Issuer + } + return "" +} + func (m *Token) GetName() string { if m != nil { return m.Name @@ -80,36 +127,139 @@ func (m *Token) GetSymbol() string { return "" } -func (m *Token) GetTotal() string { +func (m *Token) GetDecimal() uint32 { + if m != nil { + return m.Decimal + } + return 0 +} + +func (m *Token) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Token) GetEvmAddress() string { if m != nil { - return m.Total + return m.EvmAddress } return "" } -func (m *Token) GetAuthorizationRequired() bool { +// TokenManagement represents the asset manager's execute functions. +type TokenManagement struct { + Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` + AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` + ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` +} + +func (m *TokenManagement) Reset() { *m = TokenManagement{} } +func (m *TokenManagement) String() string { return proto.CompactTextString(m) } +func (*TokenManagement) ProtoMessage() {} +func (*TokenManagement) Descriptor() ([]byte, []int) { + return fileDescriptor_2f83138fc60a3176, []int{1} +} +func (m *TokenManagement) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenManagement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenManagement.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenManagement) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenManagement.Merge(m, src) +} +func (m *TokenManagement) XXX_Size() int { + return m.Size() +} +func (m *TokenManagement) XXX_DiscardUnknown() { + xxx_messageInfo_TokenManagement.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenManagement proto.InternalMessageInfo + +func (m *TokenManagement) GetManagers() []string { if m != nil { - return m.AuthorizationRequired + return m.Managers + } + return nil +} + +func (m *TokenManagement) GetAllowNewExtensions() bool { + if m != nil { + return m.AllowNewExtensions } return false } -func (m *Token) GetManager() string { +func (m *TokenManagement) GetExtensionsList() []string { if m != nil { - return m.Manager + return m.ExtensionsList } - return "" + return nil +} + +// TokenDistribution represents the asset manager's execute functions. +type TokenDistribution struct { + Distributors []string `protobuf:"bytes,1,rep,name=distributors,proto3" json:"distributors,omitempty"` + MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` } -func (m *Token) GetAuthorized() []*TokenAuthorization { +func (m *TokenDistribution) Reset() { *m = TokenDistribution{} } +func (m *TokenDistribution) String() string { return proto.CompactTextString(m) } +func (*TokenDistribution) ProtoMessage() {} +func (*TokenDistribution) Descriptor() ([]byte, []int) { + return fileDescriptor_2f83138fc60a3176, []int{2} +} +func (m *TokenDistribution) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenDistribution) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenDistribution.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TokenDistribution) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenDistribution.Merge(m, src) +} +func (m *TokenDistribution) XXX_Size() int { + return m.Size() +} +func (m *TokenDistribution) XXX_DiscardUnknown() { + xxx_messageInfo_TokenDistribution.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenDistribution proto.InternalMessageInfo + +func (m *TokenDistribution) GetDistributors() []string { if m != nil { - return m.Authorized + return m.Distributors } return nil } func init() { + proto.RegisterEnum("realionetwork.asset.v1.Role", Role_name, Role_value) proto.RegisterType((*Token)(nil), "realionetwork.asset.v1.Token") + proto.RegisterType((*TokenManagement)(nil), "realionetwork.asset.v1.TokenManagement") + proto.RegisterType((*TokenDistribution)(nil), "realionetwork.asset.v1.TokenDistribution") } func init() { @@ -117,25 +267,41 @@ func init() { } var fileDescriptor_2f83138fc60a3176 = []byte{ - // 286 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x10, 0x86, 0x6b, 0xda, 0x06, 0x30, 0x9b, 0x55, 0x2a, 0xab, 0x83, 0x15, 0x75, 0x8a, 0x90, 0x70, - 0xd4, 0xc2, 0x0b, 0xc0, 0x88, 0x98, 0x22, 0x26, 0x36, 0xa7, 0xb5, 0x92, 0xa8, 0x49, 0xae, 0x38, - 0x97, 0x42, 0x79, 0x0a, 0x1e, 0x8b, 0xb1, 0x23, 0x23, 0x4a, 0xc4, 0x7b, 0xa0, 0xba, 0x89, 0x44, - 0xa4, 0x8a, 0xed, 0xff, 0x7d, 0xff, 0xfd, 0x27, 0x7f, 0x74, 0x6a, 0xb4, 0x4a, 0x13, 0xc8, 0x35, - 0xbe, 0x82, 0x59, 0xf9, 0xaa, 0x28, 0x34, 0xfa, 0x9b, 0x99, 0x8f, 0xb0, 0xd2, 0xb9, 0x5c, 0x1b, - 0x40, 0x60, 0xe3, 0x4e, 0x46, 0xda, 0x8c, 0xdc, 0xcc, 0x26, 0xa3, 0x08, 0x22, 0xb0, 0x11, 0x7f, - 0xaf, 0x0e, 0xe9, 0x89, 0xff, 0x5f, 0xa3, 0x2a, 0x31, 0x06, 0x93, 0xbc, 0x2b, 0x4c, 0xa0, 0xa9, - 0x9f, 0xfe, 0x10, 0x3a, 0x7c, 0xda, 0x0f, 0x19, 0xa3, 0x83, 0x5c, 0x65, 0x9a, 0x13, 0x97, 0x78, - 0xe7, 0x81, 0xd5, 0x6c, 0x4c, 0x9d, 0x62, 0x9b, 0x85, 0x90, 0xf2, 0x13, 0xfb, 0xda, 0x38, 0x36, - 0xa2, 0x43, 0x04, 0x54, 0x29, 0xef, 0xdb, 0xe7, 0x83, 0x61, 0xb7, 0xf4, 0xb2, 0x73, 0x22, 0xd0, - 0x2f, 0x65, 0x62, 0xf4, 0x92, 0x0f, 0x5c, 0xe2, 0x9d, 0x05, 0xc7, 0x87, 0x8c, 0xd3, 0xd3, 0x4c, - 0xe5, 0x2a, 0xd2, 0x86, 0x0f, 0x6d, 0x5b, 0x6b, 0xd9, 0x03, 0xa5, 0xed, 0x8a, 0x5e, 0x72, 0xc7, - 0xed, 0x7b, 0x17, 0xf3, 0x2b, 0x79, 0x9c, 0x87, 0xb4, 0x9f, 0xb8, 0xeb, 0x5c, 0xf8, 0xb3, 0x7d, - 0xff, 0xf8, 0x59, 0x09, 0xb2, 0xab, 0x04, 0xf9, 0xae, 0x04, 0xf9, 0xa8, 0x45, 0x6f, 0x57, 0x8b, - 0xde, 0x57, 0x2d, 0x7a, 0xcf, 0xf3, 0x28, 0xc1, 0xb8, 0x0c, 0xe5, 0x02, 0xb2, 0x86, 0x1e, 0xea, - 0x45, 0xdc, 0xc8, 0xeb, 0x96, 0xe4, 0x5b, 0xc3, 0x12, 0xb7, 0x6b, 0x5d, 0x84, 0x8e, 0x85, 0x77, - 0xf3, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x66, 0x07, 0x38, 0xad, 0xc1, 0x01, 0x00, 0x00, + // 530 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x92, 0x3f, 0x6f, 0xd3, 0x40, + 0x18, 0xc6, 0xed, 0x36, 0x4d, 0x93, 0x4b, 0x4b, 0xc2, 0x51, 0x2a, 0x63, 0x09, 0xc7, 0x84, 0x81, + 0x80, 0x84, 0x4d, 0x61, 0x65, 0x49, 0x88, 0x41, 0x96, 0xd2, 0x14, 0x39, 0xe9, 0xc2, 0x62, 0x5d, + 0xe2, 0x53, 0x72, 0x8a, 0xcf, 0x67, 0xf9, 0x2e, 0xff, 0x26, 0xd6, 0x2a, 0x13, 0x5f, 0x20, 0x13, + 0x1f, 0x85, 0xa5, 0x63, 0x47, 0xc4, 0x50, 0xa1, 0xe4, 0x8b, 0xa0, 0x9c, 0xf3, 0x87, 0x6e, 0xef, + 0xf3, 0xbc, 0xbf, 0x7b, 0xf5, 0xbe, 0xa7, 0x07, 0x54, 0x12, 0x8c, 0x42, 0xc2, 0x22, 0x2c, 0x26, + 0x2c, 0x19, 0xda, 0x88, 0x73, 0x2c, 0xec, 0xf1, 0x85, 0x2d, 0xd8, 0x10, 0x47, 0x56, 0x9c, 0x30, + 0xc1, 0xe0, 0xf9, 0x03, 0xc6, 0x92, 0x8c, 0x35, 0xbe, 0xd0, 0xcf, 0xfa, 0xac, 0xcf, 0x24, 0x62, + 0xaf, 0xab, 0x94, 0xae, 0xfc, 0x52, 0xc1, 0x51, 0x67, 0xfd, 0x1a, 0x3e, 0x03, 0x39, 0x39, 0xc6, + 0x27, 0x81, 0xa6, 0x9a, 0x6a, 0x35, 0xef, 0x1d, 0x4b, 0xed, 0x06, 0xf0, 0x1c, 0x64, 0x09, 0xe7, + 0x23, 0x9c, 0x68, 0x07, 0xb2, 0xb1, 0x51, 0x10, 0x82, 0x4c, 0x84, 0x28, 0xd6, 0x0e, 0xa5, 0x2b, + 0xeb, 0x35, 0xcb, 0x67, 0xb4, 0xcb, 0x42, 0x2d, 0x93, 0xb2, 0xa9, 0x82, 0x1a, 0x38, 0x0e, 0x70, + 0x8f, 0x50, 0x14, 0x6a, 0x47, 0xa6, 0x5a, 0x3d, 0xf5, 0xb6, 0x12, 0x9a, 0xa0, 0x10, 0x60, 0xde, + 0x4b, 0x48, 0x2c, 0x08, 0x8b, 0xb4, 0xac, 0x7c, 0xf6, 0xbf, 0x05, 0xcb, 0xa0, 0x80, 0xc7, 0xd4, + 0x47, 0x41, 0x90, 0x60, 0xce, 0xb5, 0xbc, 0x24, 0x00, 0x1e, 0xd3, 0x5a, 0xea, 0x54, 0x6e, 0x54, + 0x50, 0x94, 0x57, 0x5c, 0xa2, 0x08, 0xf5, 0x31, 0xc5, 0x91, 0x80, 0x3a, 0xc8, 0x51, 0xa9, 0x12, + 0xae, 0xa9, 0xe6, 0x61, 0x35, 0xef, 0xed, 0x34, 0x7c, 0x07, 0xce, 0x50, 0x18, 0xb2, 0x89, 0x1f, + 0xe1, 0x89, 0x8f, 0xa7, 0x02, 0x47, 0x9c, 0xb0, 0x88, 0xcb, 0xf3, 0x72, 0x1e, 0x94, 0xbd, 0x16, + 0x9e, 0x38, 0xbb, 0x0e, 0x7c, 0x05, 0x8a, 0x7b, 0xce, 0x0f, 0x09, 0x17, 0xda, 0xa1, 0x1c, 0xfa, + 0x68, 0x6f, 0x37, 0x09, 0x17, 0x95, 0x11, 0x78, 0x2c, 0x37, 0x69, 0x10, 0x2e, 0x12, 0xd2, 0x1d, + 0xc9, 0x03, 0x2a, 0xe0, 0x24, 0xd8, 0x6a, 0xb6, 0xdb, 0xe7, 0x81, 0x07, 0x3f, 0x02, 0x40, 0xd1, + 0xd4, 0xe7, 0xa3, 0x38, 0x0e, 0x67, 0xe9, 0x47, 0xd7, 0x9f, 0xdf, 0xde, 0x97, 0x95, 0x3f, 0xf7, + 0xe5, 0xa7, 0x3d, 0xc6, 0x29, 0xe3, 0x3c, 0x18, 0x5a, 0x84, 0xd9, 0x14, 0x89, 0x81, 0xe5, 0x46, + 0xc2, 0xcb, 0x53, 0x34, 0x6d, 0x4b, 0xfe, 0xcd, 0x77, 0x90, 0xf1, 0x58, 0x88, 0xe1, 0x4b, 0x50, + 0xf2, 0xae, 0x9a, 0x8e, 0x7f, 0xdd, 0x6a, 0x7f, 0x75, 0x3e, 0xb9, 0x9f, 0x5d, 0xa7, 0x51, 0x52, + 0xf4, 0xd3, 0xf9, 0xc2, 0xcc, 0x3b, 0x34, 0x16, 0x33, 0x09, 0xbd, 0x00, 0x27, 0x12, 0xba, 0xac, + 0xb5, 0x6a, 0x5f, 0x1c, 0xaf, 0xa4, 0xea, 0xc5, 0xf9, 0xc2, 0x2c, 0xa4, 0x9f, 0x97, 0x48, 0xe4, + 0xf5, 0x66, 0x4e, 0xc3, 0x6d, 0x77, 0x3c, 0xb7, 0x7e, 0xdd, 0xb9, 0xf2, 0x4a, 0x07, 0xfa, 0x93, + 0xf9, 0xc2, 0x2c, 0x36, 0xf6, 0x5b, 0xaf, 0x51, 0x3d, 0x73, 0xf3, 0xd3, 0x50, 0xea, 0xcd, 0xdb, + 0xa5, 0xa1, 0xde, 0x2d, 0x0d, 0xf5, 0xef, 0xd2, 0x50, 0x7f, 0xac, 0x0c, 0xe5, 0x6e, 0x65, 0x28, + 0xbf, 0x57, 0x86, 0xf2, 0xed, 0x7d, 0x9f, 0x88, 0xc1, 0xa8, 0x6b, 0xf5, 0x18, 0xb5, 0xd3, 0x6c, + 0x0a, 0xdc, 0x1b, 0x6c, 0xca, 0xb7, 0xdb, 0x2c, 0x4f, 0x37, 0x69, 0x16, 0xb3, 0x18, 0xf3, 0x6e, + 0x56, 0xa6, 0xf3, 0xc3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x4c, 0x9a, 0x9f, 0xf1, 0x02, + 0x00, 0x00, } func (m *Token) Marshal() (dAtA []byte, err error) { @@ -158,61 +324,149 @@ func (m *Token) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Authorized) > 0 { - for iNdEx := len(m.Authorized) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Authorized[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintToken(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - } - if len(m.Manager) > 0 { - i -= len(m.Manager) - copy(dAtA[i:], m.Manager) - i = encodeVarintToken(dAtA, i, uint64(len(m.Manager))) + if len(m.EvmAddress) > 0 { + i -= len(m.EvmAddress) + copy(dAtA[i:], m.EvmAddress) + i = encodeVarintToken(dAtA, i, uint64(len(m.EvmAddress))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x4a } - if m.AuthorizationRequired { - i-- - if m.AuthorizationRequired { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintToken(dAtA, i, uint64(len(m.Description))) i-- - dAtA[i] = 0x20 + dAtA[i] = 0x32 } - if len(m.Total) > 0 { - i -= len(m.Total) - copy(dAtA[i:], m.Total) - i = encodeVarintToken(dAtA, i, uint64(len(m.Total))) + if m.Decimal != 0 { + i = encodeVarintToken(dAtA, i, uint64(m.Decimal)) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x28 } if len(m.Symbol) > 0 { i -= len(m.Symbol) copy(dAtA[i:], m.Symbol) i = encodeVarintToken(dAtA, i, uint64(len(m.Symbol))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x22 } if len(m.Name) > 0 { i -= len(m.Name) copy(dAtA[i:], m.Name) i = encodeVarintToken(dAtA, i, uint64(len(m.Name))) i-- + dAtA[i] = 0x1a + } + if len(m.Issuer) > 0 { + i -= len(m.Issuer) + copy(dAtA[i:], m.Issuer) + i = encodeVarintToken(dAtA, i, uint64(len(m.Issuer))) + i-- + dAtA[i] = 0x12 + } + if len(m.TokenId) > 0 { + i -= len(m.TokenId) + copy(dAtA[i:], m.TokenId) + i = encodeVarintToken(dAtA, i, uint64(len(m.TokenId))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } +func (m *TokenManagement) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenManagement) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenManagement) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ExtensionsList) > 0 { + for iNdEx := len(m.ExtensionsList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ExtensionsList[iNdEx]) + copy(dAtA[i:], m.ExtensionsList[iNdEx]) + i = encodeVarintToken(dAtA, i, uint64(len(m.ExtensionsList[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.AllowNewExtensions { + i-- + if m.AllowNewExtensions { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.Managers) > 0 { + for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Managers[iNdEx]) + copy(dAtA[i:], m.Managers[iNdEx]) + i = encodeVarintToken(dAtA, i, uint64(len(m.Managers[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TokenDistribution) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TokenDistribution) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenDistribution) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxSupply.Size() + i -= size + if _, err := m.MaxSupply.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Distributors) > 0 { + for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Distributors[iNdEx]) + copy(dAtA[i:], m.Distributors[iNdEx]) + i = encodeVarintToken(dAtA, i, uint64(len(m.Distributors[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintToken(dAtA []byte, offset int, v uint64) int { offset -= sovToken(v) base := offset @@ -230,6 +484,14 @@ func (m *Token) Size() (n int) { } var l int _ = l + l = len(m.TokenId) + if l > 0 { + n += 1 + l + sovToken(uint64(l)) + } + l = len(m.Issuer) + if l > 0 { + n += 1 + l + sovToken(uint64(l)) + } l = len(m.Name) if l > 0 { n += 1 + l + sovToken(uint64(l)) @@ -238,23 +500,58 @@ func (m *Token) Size() (n int) { if l > 0 { n += 1 + l + sovToken(uint64(l)) } - l = len(m.Total) + if m.Decimal != 0 { + n += 1 + sovToken(uint64(m.Decimal)) + } + l = len(m.Description) if l > 0 { n += 1 + l + sovToken(uint64(l)) } - if m.AuthorizationRequired { - n += 2 - } - l = len(m.Manager) + l = len(m.EvmAddress) if l > 0 { n += 1 + l + sovToken(uint64(l)) } - if len(m.Authorized) > 0 { - for _, e := range m.Authorized { - l = e.Size() + return n +} + +func (m *TokenManagement) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Managers) > 0 { + for _, s := range m.Managers { + l = len(s) + n += 1 + l + sovToken(uint64(l)) + } + } + if m.AllowNewExtensions { + n += 2 + } + if len(m.ExtensionsList) > 0 { + for _, s := range m.ExtensionsList { + l = len(s) + n += 1 + l + sovToken(uint64(l)) + } + } + return n +} + +func (m *TokenDistribution) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Distributors) > 0 { + for _, s := range m.Distributors { + l = len(s) n += 1 + l + sovToken(uint64(l)) } } + l = m.MaxSupply.Size() + n += 1 + l + sovToken(uint64(l)) return n } @@ -294,6 +591,70 @@ func (m *Token) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Issuer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } @@ -325,7 +686,7 @@ func (m *Token) Unmarshal(dAtA []byte) error { } m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) } @@ -357,9 +718,28 @@ func (m *Token) Unmarshal(dAtA []byte) error { } m.Symbol = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Decimal", wireType) + } + m.Decimal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Decimal |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -387,11 +767,125 @@ func (m *Token) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Total = string(dAtA[iNdEx:postIndex]) + m.Description = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EvmAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EvmAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TokenManagement) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenManagement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenManagement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AuthorizationRequired", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AllowNewExtensions", wireType) } var v int for shift := uint(0); ; shift += 7 { @@ -408,10 +902,10 @@ func (m *Token) Unmarshal(dAtA []byte) error { break } } - m.AuthorizationRequired = bool(v != 0) - case 5: + m.AllowNewExtensions = bool(v != 0) + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Manager", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExtensionsList", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -439,13 +933,63 @@ func (m *Token) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Manager = string(dAtA[iNdEx:postIndex]) + m.ExtensionsList = append(m.ExtensionsList, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 6: + default: + iNdEx = preIndex + skippy, err := skipToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TokenDistribution) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TokenDistribution: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenDistribution: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Authorized", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowToken @@ -455,23 +999,55 @@ func (m *Token) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthToken } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSupply", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthToken } if postIndex > l { return io.ErrUnexpectedEOF } - m.Authorized = append(m.Authorized, &TokenAuthorization{}) - if err := m.Authorized[len(m.Authorized)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MaxSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/asset/types/tokenauthorization.pb.go b/x/asset/types/tokenauthorization.pb.go deleted file mode 100644 index 97cb95de..00000000 --- a/x/asset/types/tokenauthorization.pb.go +++ /dev/null @@ -1,363 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: realionetwork/asset/v1/tokenauthorization.proto - -package types - -import ( - fmt "fmt" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// TokenAuthorization represents the current authorization state for an -// address:token -type TokenAuthorization struct { - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - Authorized bool `protobuf:"varint,3,opt,name=authorized,proto3" json:"authorized,omitempty"` -} - -func (m *TokenAuthorization) Reset() { *m = TokenAuthorization{} } -func (m *TokenAuthorization) String() string { return proto.CompactTextString(m) } -func (*TokenAuthorization) ProtoMessage() {} -func (*TokenAuthorization) Descriptor() ([]byte, []int) { - return fileDescriptor_082a161f7b2bd506, []int{0} -} -func (m *TokenAuthorization) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TokenAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TokenAuthorization.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TokenAuthorization) XXX_Merge(src proto.Message) { - xxx_messageInfo_TokenAuthorization.Merge(m, src) -} -func (m *TokenAuthorization) XXX_Size() int { - return m.Size() -} -func (m *TokenAuthorization) XXX_DiscardUnknown() { - xxx_messageInfo_TokenAuthorization.DiscardUnknown(m) -} - -var xxx_messageInfo_TokenAuthorization proto.InternalMessageInfo - -func (m *TokenAuthorization) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -func (m *TokenAuthorization) GetAuthorized() bool { - if m != nil { - return m.Authorized - } - return false -} - -func init() { - proto.RegisterType((*TokenAuthorization)(nil), "realionetwork.asset.v1.TokenAuthorization") -} - -func init() { - proto.RegisterFile("realionetwork/asset/v1/tokenauthorization.proto", fileDescriptor_082a161f7b2bd506) -} - -var fileDescriptor_082a161f7b2bd506 = []byte{ - // 207 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2f, 0x4a, 0x4d, 0xcc, - 0xc9, 0xcc, 0xcf, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, 0xd6, 0x4f, 0x2c, 0x2e, 0x4e, 0x2d, 0xd1, - 0x2f, 0x33, 0xd4, 0x2f, 0xc9, 0xcf, 0x4e, 0xcd, 0x4b, 0x2c, 0x2d, 0xc9, 0xc8, 0x2f, 0xca, 0xac, - 0x4a, 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x43, 0xd1, 0xa0, - 0x07, 0xd6, 0xa0, 0x57, 0x66, 0x28, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x56, 0xa2, 0x0f, 0x62, - 0x41, 0x54, 0x2b, 0xf9, 0x71, 0x09, 0x85, 0x80, 0x4c, 0x72, 0x44, 0x36, 0x49, 0x48, 0x82, 0x8b, - 0x3d, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x49, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, - 0x15, 0x92, 0xe3, 0xe2, 0x82, 0x59, 0x9a, 0x9a, 0x22, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0x11, 0x84, - 0x24, 0xe2, 0xe4, 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, - 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x46, 0xe9, - 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0x50, 0x3f, 0x95, 0xa4, 0x26, 0x67, 0x40, - 0x99, 0xba, 0x30, 0xff, 0x55, 0x40, 0x7d, 0x58, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x76, - 0xa4, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xa5, 0xcd, 0x3b, 0xfc, 0x05, 0x01, 0x00, 0x00, -} - -func (m *TokenAuthorization) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TokenAuthorization) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TokenAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Authorized { - i-- - if m.Authorized { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTokenauthorization(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} - -func encodeVarintTokenauthorization(dAtA []byte, offset int, v uint64) int { - offset -= sovTokenauthorization(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *TokenAuthorization) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovTokenauthorization(uint64(l)) - } - if m.Authorized { - n += 2 - } - return n -} - -func sovTokenauthorization(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTokenauthorization(x uint64) (n int) { - return sovTokenauthorization(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *TokenAuthorization) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TokenAuthorization: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TokenAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTokenauthorization - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTokenauthorization - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Address = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Authorized", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Authorized = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipTokenauthorization(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTokenauthorization - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipTokenauthorization(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTokenauthorization - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthTokenauthorization - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupTokenauthorization - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthTokenauthorization - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthTokenauthorization = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTokenauthorization = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupTokenauthorization = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/asset/types/tx.pb.go b/x/asset/types/tx.pb.go index b986b865..ede37d5f 100644 --- a/x/asset/types/tx.pb.go +++ b/x/asset/types/tx.pb.go @@ -5,6 +5,7 @@ package types import ( context "context" + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/cosmos-sdk/types/msgservice" @@ -31,11 +32,17 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type MsgCreateToken struct { - Manager string `protobuf:"bytes,1,opt,name=manager,proto3" json:"manager,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"` - Total string `protobuf:"bytes,4,opt,name=total,proto3" json:"total,omitempty"` - AuthorizationRequired bool `protobuf:"varint,6,opt,name=authorizationRequired,proto3" json:"authorizationRequired,omitempty"` + // issuer is the address that defines the token + Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Decimal uint32 `protobuf:"varint,3,opt,name=decimal,proto3" json:"decimal,omitempty"` + Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + Managers []string `protobuf:"bytes,6,rep,name=managers,proto3" json:"managers,omitempty"` + Distributors []string `protobuf:"bytes,7,rep,name=distributors,proto3" json:"distributors,omitempty"` + AllowNewExtensions bool `protobuf:"varint,8,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` + ExtensionsList []string `protobuf:"bytes,9,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` + MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,10,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` } func (m *MsgCreateToken) Reset() { *m = MsgCreateToken{} } @@ -71,9 +78,9 @@ func (m *MsgCreateToken) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateToken proto.InternalMessageInfo -func (m *MsgCreateToken) GetManager() string { +func (m *MsgCreateToken) GetIssuer() string { if m != nil { - return m.Manager + return m.Issuer } return "" } @@ -85,6 +92,13 @@ func (m *MsgCreateToken) GetName() string { return "" } +func (m *MsgCreateToken) GetDecimal() uint32 { + if m != nil { + return m.Decimal + } + return 0 +} + func (m *MsgCreateToken) GetSymbol() string { if m != nil { return m.Symbol @@ -92,21 +106,43 @@ func (m *MsgCreateToken) GetSymbol() string { return "" } -func (m *MsgCreateToken) GetTotal() string { +func (m *MsgCreateToken) GetDescription() string { if m != nil { - return m.Total + return m.Description } return "" } -func (m *MsgCreateToken) GetAuthorizationRequired() bool { +func (m *MsgCreateToken) GetManagers() []string { + if m != nil { + return m.Managers + } + return nil +} + +func (m *MsgCreateToken) GetDistributors() []string { + if m != nil { + return m.Distributors + } + return nil +} + +func (m *MsgCreateToken) GetAllowNewExtensions() bool { if m != nil { - return m.AuthorizationRequired + return m.AllowNewExtensions } return false } +func (m *MsgCreateToken) GetExtensionsList() []string { + if m != nil { + return m.ExtensionsList + } + return nil +} + type MsgCreateTokenResponse struct { + TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` } func (m *MsgCreateTokenResponse) Reset() { *m = MsgCreateTokenResponse{} } @@ -142,313 +178,33 @@ func (m *MsgCreateTokenResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateTokenResponse proto.InternalMessageInfo -type MsgUpdateToken struct { - Manager string `protobuf:"bytes,1,opt,name=manager,proto3" json:"manager,omitempty"` - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` - AuthorizationRequired bool `protobuf:"varint,3,opt,name=authorizationRequired,proto3" json:"authorizationRequired,omitempty"` -} - -func (m *MsgUpdateToken) Reset() { *m = MsgUpdateToken{} } -func (m *MsgUpdateToken) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateToken) ProtoMessage() {} -func (*MsgUpdateToken) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{2} -} -func (m *MsgUpdateToken) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateToken.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUpdateToken) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateToken.Merge(m, src) -} -func (m *MsgUpdateToken) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateToken) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateToken.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdateToken proto.InternalMessageInfo - -func (m *MsgUpdateToken) GetManager() string { - if m != nil { - return m.Manager - } - return "" -} - -func (m *MsgUpdateToken) GetSymbol() string { - if m != nil { - return m.Symbol - } - return "" -} - -func (m *MsgUpdateToken) GetAuthorizationRequired() bool { - if m != nil { - return m.AuthorizationRequired - } - return false -} - -type MsgUpdateTokenResponse struct { -} - -func (m *MsgUpdateTokenResponse) Reset() { *m = MsgUpdateTokenResponse{} } -func (m *MsgUpdateTokenResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateTokenResponse) ProtoMessage() {} -func (*MsgUpdateTokenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{3} -} -func (m *MsgUpdateTokenResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateTokenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateTokenResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUpdateTokenResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateTokenResponse.Merge(m, src) -} -func (m *MsgUpdateTokenResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateTokenResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateTokenResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUpdateTokenResponse proto.InternalMessageInfo - -type MsgAuthorizeAddress struct { - Manager string `protobuf:"bytes,1,opt,name=manager,proto3" json:"manager,omitempty"` - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` - Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *MsgAuthorizeAddress) Reset() { *m = MsgAuthorizeAddress{} } -func (m *MsgAuthorizeAddress) String() string { return proto.CompactTextString(m) } -func (*MsgAuthorizeAddress) ProtoMessage() {} -func (*MsgAuthorizeAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{4} -} -func (m *MsgAuthorizeAddress) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgAuthorizeAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgAuthorizeAddress.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgAuthorizeAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgAuthorizeAddress.Merge(m, src) -} -func (m *MsgAuthorizeAddress) XXX_Size() int { - return m.Size() -} -func (m *MsgAuthorizeAddress) XXX_DiscardUnknown() { - xxx_messageInfo_MsgAuthorizeAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgAuthorizeAddress proto.InternalMessageInfo - -func (m *MsgAuthorizeAddress) GetManager() string { - if m != nil { - return m.Manager - } - return "" -} - -func (m *MsgAuthorizeAddress) GetSymbol() string { - if m != nil { - return m.Symbol - } - return "" -} - -func (m *MsgAuthorizeAddress) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -type MsgAuthorizeAddressResponse struct { -} - -func (m *MsgAuthorizeAddressResponse) Reset() { *m = MsgAuthorizeAddressResponse{} } -func (m *MsgAuthorizeAddressResponse) String() string { return proto.CompactTextString(m) } -func (*MsgAuthorizeAddressResponse) ProtoMessage() {} -func (*MsgAuthorizeAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{5} -} -func (m *MsgAuthorizeAddressResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgAuthorizeAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgAuthorizeAddressResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgAuthorizeAddressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgAuthorizeAddressResponse.Merge(m, src) -} -func (m *MsgAuthorizeAddressResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgAuthorizeAddressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgAuthorizeAddressResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgAuthorizeAddressResponse proto.InternalMessageInfo - -type MsgUnAuthorizeAddress struct { - Manager string `protobuf:"bytes,1,opt,name=manager,proto3" json:"manager,omitempty"` - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` - Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` -} - -func (m *MsgUnAuthorizeAddress) Reset() { *m = MsgUnAuthorizeAddress{} } -func (m *MsgUnAuthorizeAddress) String() string { return proto.CompactTextString(m) } -func (*MsgUnAuthorizeAddress) ProtoMessage() {} -func (*MsgUnAuthorizeAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{6} -} -func (m *MsgUnAuthorizeAddress) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnAuthorizeAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnAuthorizeAddress.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnAuthorizeAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnAuthorizeAddress.Merge(m, src) -} -func (m *MsgUnAuthorizeAddress) XXX_Size() int { - return m.Size() -} -func (m *MsgUnAuthorizeAddress) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnAuthorizeAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnAuthorizeAddress proto.InternalMessageInfo - -func (m *MsgUnAuthorizeAddress) GetManager() string { +func (m *MsgCreateTokenResponse) GetTokenId() string { if m != nil { - return m.Manager + return m.TokenId } return "" } -func (m *MsgUnAuthorizeAddress) GetSymbol() string { - if m != nil { - return m.Symbol - } - return "" -} - -func (m *MsgUnAuthorizeAddress) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -type MsgUnAuthorizeAddressResponse struct { -} - -func (m *MsgUnAuthorizeAddressResponse) Reset() { *m = MsgUnAuthorizeAddressResponse{} } -func (m *MsgUnAuthorizeAddressResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUnAuthorizeAddressResponse) ProtoMessage() {} -func (*MsgUnAuthorizeAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{7} -} -func (m *MsgUnAuthorizeAddressResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUnAuthorizeAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUnAuthorizeAddressResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgUnAuthorizeAddressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUnAuthorizeAddressResponse.Merge(m, src) -} -func (m *MsgUnAuthorizeAddressResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUnAuthorizeAddressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUnAuthorizeAddressResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgUnAuthorizeAddressResponse proto.InternalMessageInfo - -type MsgTransferToken struct { - Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"` - From string `protobuf:"bytes,2,opt,name=from,proto3" json:"from,omitempty"` - To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` - Amount string `protobuf:"bytes,4,opt,name=amount,proto3" json:"amount,omitempty"` +type MsgAssignRoles struct { + // issuer is the address that defines the token + Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` + Distributors []string `protobuf:"bytes,4,rep,name=distributors,proto3" json:"distributors,omitempty"` } -func (m *MsgTransferToken) Reset() { *m = MsgTransferToken{} } -func (m *MsgTransferToken) String() string { return proto.CompactTextString(m) } -func (*MsgTransferToken) ProtoMessage() {} -func (*MsgTransferToken) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{8} +func (m *MsgAssignRoles) Reset() { *m = MsgAssignRoles{} } +func (m *MsgAssignRoles) String() string { return proto.CompactTextString(m) } +func (*MsgAssignRoles) ProtoMessage() {} +func (*MsgAssignRoles) Descriptor() ([]byte, []int) { + return fileDescriptor_1cfda60866e68e13, []int{2} } -func (m *MsgTransferToken) XXX_Unmarshal(b []byte) error { +func (m *MsgAssignRoles) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgTransferToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgAssignRoles) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgTransferToken.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgAssignRoles.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -458,61 +214,61 @@ func (m *MsgTransferToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, er return b[:n], nil } } -func (m *MsgTransferToken) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgTransferToken.Merge(m, src) +func (m *MsgAssignRoles) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssignRoles.Merge(m, src) } -func (m *MsgTransferToken) XXX_Size() int { +func (m *MsgAssignRoles) XXX_Size() int { return m.Size() } -func (m *MsgTransferToken) XXX_DiscardUnknown() { - xxx_messageInfo_MsgTransferToken.DiscardUnknown(m) +func (m *MsgAssignRoles) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssignRoles.DiscardUnknown(m) } -var xxx_messageInfo_MsgTransferToken proto.InternalMessageInfo +var xxx_messageInfo_MsgAssignRoles proto.InternalMessageInfo -func (m *MsgTransferToken) GetSymbol() string { +func (m *MsgAssignRoles) GetIssuer() string { if m != nil { - return m.Symbol + return m.Issuer } return "" } -func (m *MsgTransferToken) GetFrom() string { +func (m *MsgAssignRoles) GetTokenId() string { if m != nil { - return m.From + return m.TokenId } return "" } -func (m *MsgTransferToken) GetTo() string { +func (m *MsgAssignRoles) GetManagers() []string { if m != nil { - return m.To + return m.Managers } - return "" + return nil } -func (m *MsgTransferToken) GetAmount() string { +func (m *MsgAssignRoles) GetDistributors() []string { if m != nil { - return m.Amount + return m.Distributors } - return "" + return nil } -type MsgTransferTokenResponse struct { +type MsgAssignRolesResponse struct { } -func (m *MsgTransferTokenResponse) Reset() { *m = MsgTransferTokenResponse{} } -func (m *MsgTransferTokenResponse) String() string { return proto.CompactTextString(m) } -func (*MsgTransferTokenResponse) ProtoMessage() {} -func (*MsgTransferTokenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{9} +func (m *MsgAssignRolesResponse) Reset() { *m = MsgAssignRolesResponse{} } +func (m *MsgAssignRolesResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAssignRolesResponse) ProtoMessage() {} +func (*MsgAssignRolesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1cfda60866e68e13, []int{3} } -func (m *MsgTransferTokenResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgAssignRolesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgTransferTokenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgAssignRolesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgTransferTokenResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgAssignRolesResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -522,17 +278,17 @@ func (m *MsgTransferTokenResponse) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } -func (m *MsgTransferTokenResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgTransferTokenResponse.Merge(m, src) +func (m *MsgAssignRolesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssignRolesResponse.Merge(m, src) } -func (m *MsgTransferTokenResponse) XXX_Size() int { +func (m *MsgAssignRolesResponse) XXX_Size() int { return m.Size() } -func (m *MsgTransferTokenResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgTransferTokenResponse.DiscardUnknown(m) +func (m *MsgAssignRolesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssignRolesResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgTransferTokenResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgAssignRolesResponse proto.InternalMessageInfo type MsgUpdateParams struct { // authority is the address that controls the module (defaults to x/gov unless @@ -548,7 +304,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{10} + return fileDescriptor_1cfda60866e68e13, []int{4} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -598,7 +354,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{11} + return fileDescriptor_1cfda60866e68e13, []int{5} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -630,14 +386,8 @@ var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgCreateToken)(nil), "realionetwork.asset.v1.MsgCreateToken") proto.RegisterType((*MsgCreateTokenResponse)(nil), "realionetwork.asset.v1.MsgCreateTokenResponse") - proto.RegisterType((*MsgUpdateToken)(nil), "realionetwork.asset.v1.MsgUpdateToken") - proto.RegisterType((*MsgUpdateTokenResponse)(nil), "realionetwork.asset.v1.MsgUpdateTokenResponse") - proto.RegisterType((*MsgAuthorizeAddress)(nil), "realionetwork.asset.v1.MsgAuthorizeAddress") - proto.RegisterType((*MsgAuthorizeAddressResponse)(nil), "realionetwork.asset.v1.MsgAuthorizeAddressResponse") - proto.RegisterType((*MsgUnAuthorizeAddress)(nil), "realionetwork.asset.v1.MsgUnAuthorizeAddress") - proto.RegisterType((*MsgUnAuthorizeAddressResponse)(nil), "realionetwork.asset.v1.MsgUnAuthorizeAddressResponse") - proto.RegisterType((*MsgTransferToken)(nil), "realionetwork.asset.v1.MsgTransferToken") - proto.RegisterType((*MsgTransferTokenResponse)(nil), "realionetwork.asset.v1.MsgTransferTokenResponse") + proto.RegisterType((*MsgAssignRoles)(nil), "realionetwork.asset.v1.MsgAssignRoles") + proto.RegisterType((*MsgAssignRolesResponse)(nil), "realionetwork.asset.v1.MsgAssignRolesResponse") proto.RegisterType((*MsgUpdateParams)(nil), "realionetwork.asset.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "realionetwork.asset.v1.MsgUpdateParamsResponse") } @@ -645,47 +395,47 @@ func init() { func init() { proto.RegisterFile("realionetwork/asset/v1/tx.proto", fileDescriptor_1cfda60866e68e13) } var fileDescriptor_1cfda60866e68e13 = []byte{ - // 627 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x95, 0x4f, 0x4f, 0xdb, 0x30, - 0x18, 0xc6, 0x9b, 0x52, 0xca, 0x78, 0x61, 0x0c, 0x79, 0xfc, 0x09, 0xd9, 0x08, 0xa8, 0x93, 0x18, - 0x62, 0x22, 0x19, 0xb0, 0x5d, 0xd0, 0x2e, 0xb0, 0xeb, 0x2a, 0x4d, 0x15, 0xbb, 0xec, 0x32, 0xb9, - 0xad, 0x9b, 0x56, 0x6d, 0xe2, 0x62, 0xbb, 0x8c, 0x22, 0x4d, 0x9a, 0x76, 0xd8, 0x79, 0xdf, 0x61, - 0x5f, 0xa0, 0x1f, 0x83, 0x23, 0xc7, 0x9d, 0xa6, 0xa9, 0x3d, 0xf0, 0x35, 0xa6, 0xc4, 0x4e, 0xda, - 0x94, 0xb4, 0xb4, 0x3b, 0xec, 0xe6, 0xd7, 0x7e, 0xde, 0xf7, 0xf9, 0xc5, 0xf6, 0x1b, 0xc3, 0x16, - 0x23, 0xb8, 0x51, 0xa3, 0x1e, 0x11, 0x9f, 0x29, 0xab, 0xdb, 0x98, 0x73, 0x22, 0xec, 0x8b, 0x03, - 0x5b, 0x5c, 0x5a, 0x4d, 0x46, 0x05, 0x45, 0x6b, 0x31, 0x81, 0x15, 0x08, 0xac, 0x8b, 0x03, 0x63, - 0xc5, 0xa1, 0x0e, 0x0d, 0x24, 0xb6, 0x3f, 0x92, 0x6a, 0xe3, 0xd9, 0x88, 0x72, 0x4d, 0xcc, 0xb0, - 0xcb, 0x95, 0x68, 0xa3, 0x44, 0xb9, 0x4b, 0xf9, 0x27, 0x99, 0x2d, 0x03, 0xb5, 0xb4, 0x2e, 0x23, - 0xdb, 0xe5, 0x8e, 0x9f, 0xe6, 0x72, 0x47, 0x2e, 0xe4, 0x3a, 0x1a, 0x2c, 0xe5, 0xb9, 0xf3, 0x96, - 0x11, 0x2c, 0xc8, 0x19, 0xad, 0x13, 0x0f, 0xe9, 0x30, 0xe7, 0x62, 0x0f, 0x3b, 0x84, 0xe9, 0xda, - 0xb6, 0xb6, 0x3b, 0x5f, 0x08, 0x43, 0x84, 0x20, 0xe3, 0x61, 0x97, 0xe8, 0xe9, 0x60, 0x3a, 0x18, - 0xa3, 0x35, 0xc8, 0xf2, 0xb6, 0x5b, 0xa4, 0x0d, 0x7d, 0x26, 0x98, 0x55, 0x11, 0x5a, 0x81, 0x59, - 0x41, 0x05, 0x6e, 0xe8, 0x99, 0x60, 0x5a, 0x06, 0xe8, 0x15, 0xac, 0xe2, 0x96, 0xa8, 0x52, 0x56, - 0xbb, 0xc2, 0xa2, 0x46, 0xbd, 0x02, 0x39, 0x6f, 0xd5, 0x18, 0x29, 0xeb, 0xd9, 0x6d, 0x6d, 0xf7, - 0x41, 0x21, 0x79, 0xf1, 0x78, 0xf1, 0xdb, 0x6d, 0x67, 0x2f, 0xa4, 0xc8, 0xe9, 0xb0, 0x16, 0x27, - 0x2e, 0x10, 0xde, 0xa4, 0x1e, 0x27, 0xb9, 0xef, 0xf2, 0x63, 0x3e, 0x34, 0xcb, 0x13, 0x7c, 0x4c, - 0x1f, 0x3c, 0x1d, 0x03, 0x1f, 0x89, 0x38, 0x33, 0x2d, 0xe2, 0x00, 0x47, 0x84, 0x48, 0xe1, 0x71, - 0x9e, 0x3b, 0x27, 0xaa, 0x06, 0x39, 0x29, 0x97, 0x19, 0xe1, 0xfc, 0x1f, 0x30, 0x75, 0x98, 0xc3, - 0x32, 0x59, 0x6d, 0x7c, 0x18, 0x0e, 0xa1, 0x6c, 0xc2, 0x93, 0x04, 0xc3, 0x88, 0xe7, 0x1c, 0x56, - 0x7d, 0x52, 0xef, 0x3f, 0x12, 0x6d, 0xc1, 0x66, 0xa2, 0x65, 0xc4, 0x54, 0x81, 0xe5, 0x3c, 0x77, - 0xce, 0x18, 0xf6, 0x78, 0x85, 0x30, 0x79, 0x8e, 0x7d, 0x53, 0x2d, 0x66, 0x8a, 0x20, 0x53, 0x61, - 0xd4, 0x0d, 0xaf, 0xa4, 0x3f, 0x46, 0x4b, 0x90, 0x16, 0x54, 0x31, 0xa4, 0xfd, 0x56, 0x83, 0x2c, - 0x76, 0x69, 0xcb, 0x13, 0xea, 0x2e, 0xaa, 0x28, 0x67, 0x80, 0x3e, 0xec, 0x13, 0x31, 0x7c, 0x81, - 0x47, 0xd1, 0x09, 0xbe, 0x0f, 0x9a, 0x0c, 0x3d, 0x85, 0x79, 0x75, 0xf6, 0xa2, 0xad, 0x28, 0xfa, - 0x13, 0xe8, 0x0d, 0x64, 0x65, 0x33, 0x06, 0x28, 0x0b, 0x87, 0xa6, 0x95, 0xdc, 0xe0, 0x96, 0xac, - 0x76, 0x9a, 0xb9, 0xfe, 0xbd, 0x95, 0x2a, 0xa8, 0x9c, 0xe3, 0x25, 0x7f, 0x87, 0xfa, 0xd5, 0x72, - 0x1b, 0xb0, 0x3e, 0x64, 0x1f, 0x92, 0x1d, 0xfe, 0x9c, 0x85, 0x99, 0x3c, 0x77, 0x50, 0x15, 0x16, - 0x63, 0x78, 0xcf, 0x47, 0x19, 0x0e, 0x15, 0x32, 0xec, 0x09, 0x85, 0xa1, 0x23, 0x22, 0xb0, 0x30, - 0xf8, 0x7f, 0xd8, 0x19, 0x93, 0x3f, 0xa0, 0x33, 0xac, 0xc9, 0x74, 0x83, 0x36, 0x83, 0x9d, 0xbb, - 0x73, 0x2f, 0xe6, 0xfd, 0x36, 0x09, 0x1d, 0x88, 0x04, 0x2c, 0xdf, 0xb9, 0xec, 0x2f, 0xc6, 0xd4, - 0x18, 0x16, 0x1b, 0x47, 0x53, 0x88, 0x23, 0xd7, 0x2b, 0x40, 0x09, 0x4d, 0xb6, 0x3f, 0x8e, 0xfd, - 0x8e, 0xdc, 0x78, 0x3d, 0x95, 0x3c, 0xf2, 0xae, 0xc3, 0xc3, 0x78, 0x33, 0xed, 0x8e, 0xa9, 0x13, - 0x53, 0x1a, 0x2f, 0x27, 0x55, 0x86, 0x66, 0xc6, 0xec, 0xd7, 0xdb, 0xce, 0x9e, 0x76, 0xfa, 0xee, - 0xba, 0x6b, 0x6a, 0x37, 0x5d, 0x53, 0xfb, 0xd3, 0x35, 0xb5, 0x1f, 0x3d, 0x33, 0x75, 0xd3, 0x33, - 0x53, 0xbf, 0x7a, 0x66, 0xea, 0xe3, 0xa1, 0x53, 0x13, 0xd5, 0x56, 0xd1, 0x2a, 0x51, 0xd7, 0x96, - 0xc5, 0x05, 0x29, 0x55, 0xd5, 0x70, 0x3f, 0x7c, 0xe1, 0x2e, 0xd5, 0x1b, 0x27, 0xda, 0x4d, 0xc2, - 0x8b, 0xd9, 0xe0, 0xb1, 0x3a, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x7c, 0x60, 0x84, 0x13, 0x56, - 0x07, 0x00, 0x00, + // 635 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x41, 0x4f, 0xdb, 0x30, + 0x14, 0x6e, 0xda, 0x52, 0x5a, 0x97, 0x81, 0x64, 0x31, 0x08, 0xd5, 0x16, 0xaa, 0x4c, 0x1a, 0x15, + 0xd2, 0x92, 0x01, 0x37, 0xc4, 0x65, 0x4c, 0x3b, 0x20, 0xc1, 0x34, 0x65, 0xdb, 0x65, 0x97, 0xc8, + 0x6d, 0xac, 0xd4, 0x22, 0x8e, 0xa3, 0x3c, 0x97, 0xb6, 0x87, 0x49, 0xd3, 0x7e, 0x01, 0x3f, 0x85, + 0x1f, 0xb1, 0x03, 0x47, 0x8e, 0xd3, 0x0e, 0x68, 0x82, 0x03, 0xff, 0x60, 0xe7, 0x29, 0x4e, 0x4a, + 0x13, 0x46, 0x19, 0x37, 0xbf, 0xf7, 0x3e, 0x7f, 0xef, 0xf3, 0xf7, 0x6c, 0xa3, 0xf5, 0x98, 0x92, + 0x80, 0x89, 0x90, 0xca, 0xa1, 0x88, 0x8f, 0x6d, 0x02, 0x40, 0xa5, 0x7d, 0xb2, 0x65, 0xcb, 0x91, + 0x15, 0xc5, 0x42, 0x0a, 0xbc, 0x52, 0x00, 0x58, 0x0a, 0x60, 0x9d, 0x6c, 0xb5, 0x96, 0x7d, 0xe1, + 0x0b, 0x05, 0xb1, 0x93, 0x55, 0x8a, 0x6e, 0xbd, 0x98, 0x41, 0x17, 0x91, 0x98, 0x70, 0xc8, 0x40, + 0xe6, 0xac, 0x9e, 0xe2, 0x98, 0x86, 0x19, 0x66, 0xad, 0x27, 0x80, 0x0b, 0x70, 0xd3, 0x0e, 0x69, + 0x90, 0x95, 0x56, 0xd3, 0xc8, 0xe6, 0xe0, 0x27, 0xbb, 0x38, 0xf8, 0x69, 0xc1, 0xfc, 0x53, 0x46, + 0x8b, 0x47, 0xe0, 0xbf, 0x8d, 0x29, 0x91, 0xf4, 0x53, 0x42, 0x86, 0x57, 0x50, 0x8d, 0x01, 0x0c, + 0x68, 0xac, 0x6b, 0x6d, 0xad, 0xd3, 0x70, 0xb2, 0x08, 0x63, 0x54, 0x0d, 0x09, 0xa7, 0x7a, 0x59, + 0x65, 0xd5, 0x1a, 0xeb, 0x68, 0xde, 0xa3, 0x3d, 0xc6, 0x49, 0xa0, 0x57, 0xda, 0x5a, 0xe7, 0x89, + 0x33, 0x09, 0x13, 0x16, 0x18, 0xf3, 0xae, 0x08, 0xf4, 0x6a, 0xca, 0x92, 0x46, 0xb8, 0x8d, 0x9a, + 0x1e, 0x85, 0x5e, 0xcc, 0x22, 0xc9, 0x44, 0xa8, 0xcf, 0xa9, 0x62, 0x3e, 0x85, 0x5b, 0xa8, 0xce, + 0x49, 0x48, 0x7c, 0x1a, 0x83, 0x5e, 0x6b, 0x57, 0x3a, 0x0d, 0xe7, 0x36, 0xc6, 0x26, 0x5a, 0xf0, + 0x18, 0xc8, 0x98, 0x75, 0x07, 0x52, 0xc4, 0xa0, 0xcf, 0xab, 0x7a, 0x21, 0x87, 0x5f, 0xa3, 0x65, + 0x12, 0x04, 0x62, 0xe8, 0x86, 0x74, 0xe8, 0xd2, 0x91, 0xa4, 0x21, 0x30, 0x11, 0x82, 0x5e, 0x6f, + 0x6b, 0x9d, 0xba, 0x83, 0x55, 0xed, 0x3d, 0x1d, 0xbe, 0xbb, 0xad, 0xe0, 0x0d, 0xb4, 0x34, 0xc5, + 0xb9, 0x01, 0x03, 0xa9, 0x37, 0x14, 0xf1, 0xe2, 0x34, 0x7d, 0xc8, 0x40, 0xe2, 0x3d, 0x84, 0x38, + 0x19, 0xb9, 0x30, 0x88, 0xa2, 0x60, 0xac, 0xa3, 0x44, 0xfb, 0xfe, 0xf3, 0xf3, 0xcb, 0xf5, 0xd2, + 0xaf, 0xcb, 0xf5, 0xa7, 0xa9, 0xc5, 0xe0, 0x1d, 0x5b, 0x4c, 0xd8, 0x9c, 0xc8, 0xbe, 0x75, 0x10, + 0x4a, 0xa7, 0xc1, 0xc9, 0xe8, 0xa3, 0xc2, 0xef, 0x36, 0xbf, 0xdf, 0x9c, 0x6d, 0x66, 0x6e, 0x9a, + 0x3b, 0x68, 0xa5, 0xe8, 0xbb, 0x43, 0x21, 0x12, 0x21, 0x50, 0xbc, 0x86, 0xea, 0x6a, 0xaa, 0x2e, + 0xf3, 0xb2, 0x09, 0xcc, 0xab, 0xf8, 0xc0, 0x33, 0x4f, 0x35, 0x35, 0xad, 0x37, 0x00, 0xcc, 0x0f, + 0x1d, 0x11, 0x50, 0x98, 0x39, 0xad, 0x3c, 0x4b, 0xb9, 0xc0, 0x52, 0x30, 0xb8, 0xf2, 0x1f, 0x83, + 0xab, 0xff, 0x1a, 0x5c, 0x3c, 0x87, 0xae, 0xce, 0x91, 0x53, 0x34, 0x39, 0x87, 0xf9, 0x15, 0x2d, + 0x1d, 0x81, 0xff, 0x39, 0xf2, 0x88, 0xa4, 0x1f, 0xd4, 0x5d, 0xc6, 0xcf, 0x50, 0x83, 0x0c, 0x64, + 0x5f, 0xc4, 0x4c, 0x8e, 0x33, 0xbd, 0xd3, 0x04, 0xde, 0x43, 0xb5, 0xf4, 0xce, 0x2b, 0xc1, 0xcd, + 0x6d, 0xc3, 0xba, 0xff, 0x1d, 0x59, 0x29, 0xdb, 0x7e, 0x35, 0x71, 0xde, 0xc9, 0xf6, 0xec, 0x2e, + 0x26, 0xaa, 0xa6, 0x6c, 0xe6, 0x1a, 0x5a, 0xbd, 0xd3, 0x7e, 0xa2, 0x6c, 0xfb, 0x47, 0x19, 0x55, + 0x8e, 0xc0, 0xc7, 0x7d, 0xb4, 0x50, 0x90, 0xb7, 0x31, 0xab, 0xe1, 0x1d, 0xa2, 0x96, 0xfd, 0x48, + 0xe0, 0xed, 0x4c, 0x29, 0x6a, 0xe6, 0x9f, 0xd8, 0xcb, 0x07, 0xf6, 0xe7, 0x70, 0x2d, 0xeb, 0x71, + 0xb8, 0x7c, 0x9b, 0xfc, 0xdd, 0x78, 0xa8, 0x4d, 0x0e, 0xf7, 0x60, 0x9b, 0x7b, 0x26, 0xdb, 0x9a, + 0xfb, 0x76, 0x73, 0xb6, 0xa9, 0xed, 0x1f, 0x9e, 0x5f, 0x19, 0xda, 0xc5, 0x95, 0xa1, 0xfd, 0xbe, + 0x32, 0xb4, 0xd3, 0x6b, 0xa3, 0x74, 0x71, 0x6d, 0x94, 0x7e, 0x5e, 0x1b, 0xa5, 0x2f, 0xdb, 0x3e, + 0x93, 0xfd, 0x41, 0xd7, 0xea, 0x09, 0x6e, 0xa7, 0xd4, 0x92, 0xf6, 0xfa, 0xd9, 0xf2, 0xd5, 0xe4, + 0x13, 0x1b, 0x65, 0xdf, 0x98, 0x1c, 0x47, 0x14, 0xba, 0x35, 0xf5, 0x21, 0xed, 0xfc, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0xab, 0x09, 0x3e, 0x08, 0x5e, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -701,11 +451,9 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) + // this line is used by starport scaffolding # proto/tx/rpc CreateToken(ctx context.Context, in *MsgCreateToken, opts ...grpc.CallOption) (*MsgCreateTokenResponse, error) - UpdateToken(ctx context.Context, in *MsgUpdateToken, opts ...grpc.CallOption) (*MsgUpdateTokenResponse, error) - AuthorizeAddress(ctx context.Context, in *MsgAuthorizeAddress, opts ...grpc.CallOption) (*MsgAuthorizeAddressResponse, error) - UnAuthorizeAddress(ctx context.Context, in *MsgUnAuthorizeAddress, opts ...grpc.CallOption) (*MsgUnAuthorizeAddressResponse, error) - TransferToken(ctx context.Context, in *MsgTransferToken, opts ...grpc.CallOption) (*MsgTransferTokenResponse, error) + AssignRoles(ctx context.Context, in *MsgAssignRoles, opts ...grpc.CallOption) (*MsgAssignRolesResponse, error) } type msgClient struct { @@ -734,36 +482,9 @@ func (c *msgClient) CreateToken(ctx context.Context, in *MsgCreateToken, opts .. return out, nil } -func (c *msgClient) UpdateToken(ctx context.Context, in *MsgUpdateToken, opts ...grpc.CallOption) (*MsgUpdateTokenResponse, error) { - out := new(MsgUpdateTokenResponse) - err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/UpdateToken", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) AuthorizeAddress(ctx context.Context, in *MsgAuthorizeAddress, opts ...grpc.CallOption) (*MsgAuthorizeAddressResponse, error) { - out := new(MsgAuthorizeAddressResponse) - err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/AuthorizeAddress", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UnAuthorizeAddress(ctx context.Context, in *MsgUnAuthorizeAddress, opts ...grpc.CallOption) (*MsgUnAuthorizeAddressResponse, error) { - out := new(MsgUnAuthorizeAddressResponse) - err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/UnAuthorizeAddress", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) TransferToken(ctx context.Context, in *MsgTransferToken, opts ...grpc.CallOption) (*MsgTransferTokenResponse, error) { - out := new(MsgTransferTokenResponse) - err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/TransferToken", in, out, opts...) +func (c *msgClient) AssignRoles(ctx context.Context, in *MsgAssignRoles, opts ...grpc.CallOption) (*MsgAssignRolesResponse, error) { + out := new(MsgAssignRolesResponse) + err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/AssignRoles", in, out, opts...) if err != nil { return nil, err } @@ -773,11 +494,9 @@ func (c *msgClient) TransferToken(ctx context.Context, in *MsgTransferToken, opt // MsgServer is the server API for Msg service. type MsgServer interface { UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + // this line is used by starport scaffolding # proto/tx/rpc CreateToken(context.Context, *MsgCreateToken) (*MsgCreateTokenResponse, error) - UpdateToken(context.Context, *MsgUpdateToken) (*MsgUpdateTokenResponse, error) - AuthorizeAddress(context.Context, *MsgAuthorizeAddress) (*MsgAuthorizeAddressResponse, error) - UnAuthorizeAddress(context.Context, *MsgUnAuthorizeAddress) (*MsgUnAuthorizeAddressResponse, error) - TransferToken(context.Context, *MsgTransferToken) (*MsgTransferTokenResponse, error) + AssignRoles(context.Context, *MsgAssignRoles) (*MsgAssignRolesResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -790,17 +509,8 @@ func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateP func (*UnimplementedMsgServer) CreateToken(ctx context.Context, req *MsgCreateToken) (*MsgCreateTokenResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateToken not implemented") } -func (*UnimplementedMsgServer) UpdateToken(ctx context.Context, req *MsgUpdateToken) (*MsgUpdateTokenResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateToken not implemented") -} -func (*UnimplementedMsgServer) AuthorizeAddress(ctx context.Context, req *MsgAuthorizeAddress) (*MsgAuthorizeAddressResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method AuthorizeAddress not implemented") -} -func (*UnimplementedMsgServer) UnAuthorizeAddress(ctx context.Context, req *MsgUnAuthorizeAddress) (*MsgUnAuthorizeAddressResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UnAuthorizeAddress not implemented") -} -func (*UnimplementedMsgServer) TransferToken(ctx context.Context, req *MsgTransferToken) (*MsgTransferTokenResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method TransferToken not implemented") +func (*UnimplementedMsgServer) AssignRoles(ctx context.Context, req *MsgAssignRoles) (*MsgAssignRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AssignRoles not implemented") } func RegisterMsgServer(s grpc1.Server, srv MsgServer) { @@ -843,116 +553,50 @@ func _Msg_CreateToken_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } -func _Msg_UpdateToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUpdateToken) +func _Msg_AssignRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAssignRoles) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).UpdateToken(ctx, in) + return srv.(MsgServer).AssignRoles(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/realionetwork.asset.v1.Msg/UpdateToken", + FullMethod: "/realionetwork.asset.v1.Msg/AssignRoles", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UpdateToken(ctx, req.(*MsgUpdateToken)) + return srv.(MsgServer).AssignRoles(ctx, req.(*MsgAssignRoles)) } return interceptor(ctx, in, info, handler) } -func _Msg_AuthorizeAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgAuthorizeAddress) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).AuthorizeAddress(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/realionetwork.asset.v1.Msg/AuthorizeAddress", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).AuthorizeAddress(ctx, req.(*MsgAuthorizeAddress)) - } - return interceptor(ctx, in, info, handler) +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "realionetwork.asset.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + { + MethodName: "CreateToken", + Handler: _Msg_CreateToken_Handler, + }, + { + MethodName: "AssignRoles", + Handler: _Msg_AssignRoles_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "realionetwork/asset/v1/tx.proto", } -func _Msg_UnAuthorizeAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUnAuthorizeAddress) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UnAuthorizeAddress(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/realionetwork.asset.v1.Msg/UnAuthorizeAddress", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UnAuthorizeAddress(ctx, req.(*MsgUnAuthorizeAddress)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_TransferToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgTransferToken) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).TransferToken(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/realionetwork.asset.v1.Msg/TransferToken", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).TransferToken(ctx, req.(*MsgTransferToken)) - } - return interceptor(ctx, in, info, handler) -} - -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "realionetwork.asset.v1.Msg", - HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "UpdateParams", - Handler: _Msg_UpdateParams_Handler, - }, - { - MethodName: "CreateToken", - Handler: _Msg_CreateToken_Handler, - }, - { - MethodName: "UpdateToken", - Handler: _Msg_UpdateToken_Handler, - }, - { - MethodName: "AuthorizeAddress", - Handler: _Msg_AuthorizeAddress_Handler, - }, - { - MethodName: "UnAuthorizeAddress", - Handler: _Msg_UnAuthorizeAddress_Handler, - }, - { - MethodName: "TransferToken", - Handler: _Msg_TransferToken_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "realionetwork/asset/v1/tx.proto", -} - -func (m *MsgCreateToken) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { +func (m *MsgCreateToken) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { return nil, err } return dAtA[:n], nil @@ -968,29 +612,71 @@ func (m *MsgCreateToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.AuthorizationRequired { + { + size := m.MaxSupply.Size() + i -= size + if _, err := m.MaxSupply.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + if len(m.ExtensionsList) > 0 { + for iNdEx := len(m.ExtensionsList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ExtensionsList[iNdEx]) + copy(dAtA[i:], m.ExtensionsList[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.ExtensionsList[iNdEx]))) + i-- + dAtA[i] = 0x4a + } + } + if m.AllowNewExtensions { i-- - if m.AuthorizationRequired { + if m.AllowNewExtensions { dAtA[i] = 1 } else { dAtA[i] = 0 } i-- - dAtA[i] = 0x30 - } - if len(m.Total) > 0 { - i -= len(m.Total) - copy(dAtA[i:], m.Total) - i = encodeVarintTx(dAtA, i, uint64(len(m.Total))) + dAtA[i] = 0x40 + } + if len(m.Distributors) > 0 { + for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Distributors[iNdEx]) + copy(dAtA[i:], m.Distributors[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } + if len(m.Managers) > 0 { + for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Managers[iNdEx]) + copy(dAtA[i:], m.Managers[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Managers[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintTx(dAtA, i, uint64(len(m.Description))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a } if len(m.Symbol) > 0 { i -= len(m.Symbol) copy(dAtA[i:], m.Symbol) i = encodeVarintTx(dAtA, i, uint64(len(m.Symbol))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 + } + if m.Decimal != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Decimal)) + i-- + dAtA[i] = 0x18 } if len(m.Name) > 0 { i -= len(m.Name) @@ -999,10 +685,10 @@ func (m *MsgCreateToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.Manager) > 0 { - i -= len(m.Manager) - copy(dAtA[i:], m.Manager) - i = encodeVarintTx(dAtA, i, uint64(len(m.Manager))) + if len(m.Issuer) > 0 { + i -= len(m.Issuer) + copy(dAtA[i:], m.Issuer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Issuer))) i-- dAtA[i] = 0xa } @@ -1029,214 +715,17 @@ func (m *MsgCreateTokenResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUpdateToken) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateToken) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.AuthorizationRequired { - i-- - if m.AuthorizationRequired { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintTx(dAtA, i, uint64(len(m.Symbol))) - i-- - dAtA[i] = 0x12 - } - if len(m.Manager) > 0 { - i -= len(m.Manager) - copy(dAtA[i:], m.Manager) - i = encodeVarintTx(dAtA, i, uint64(len(m.Manager))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUpdateTokenResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateTokenResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateTokenResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgAuthorizeAddress) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgAuthorizeAddress) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgAuthorizeAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0x1a - } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintTx(dAtA, i, uint64(len(m.Symbol))) - i-- - dAtA[i] = 0x12 - } - if len(m.Manager) > 0 { - i -= len(m.Manager) - copy(dAtA[i:], m.Manager) - i = encodeVarintTx(dAtA, i, uint64(len(m.Manager))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgAuthorizeAddressResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgAuthorizeAddressResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgAuthorizeAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUnAuthorizeAddress) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnAuthorizeAddress) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnAuthorizeAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) - i-- - dAtA[i] = 0x1a - } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintTx(dAtA, i, uint64(len(m.Symbol))) - i-- - dAtA[i] = 0x12 - } - if len(m.Manager) > 0 { - i -= len(m.Manager) - copy(dAtA[i:], m.Manager) - i = encodeVarintTx(dAtA, i, uint64(len(m.Manager))) + if len(m.TokenId) > 0 { + i -= len(m.TokenId) + copy(dAtA[i:], m.TokenId) + i = encodeVarintTx(dAtA, i, uint64(len(m.TokenId))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgUnAuthorizeAddressResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUnAuthorizeAddressResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnAuthorizeAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgTransferToken) Marshal() (dAtA []byte, err error) { +func (m *MsgAssignRoles) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1246,48 +735,52 @@ func (m *MsgTransferToken) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgTransferToken) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAssignRoles) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgTransferToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAssignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Amount) > 0 { - i -= len(m.Amount) - copy(dAtA[i:], m.Amount) - i = encodeVarintTx(dAtA, i, uint64(len(m.Amount))) - i-- - dAtA[i] = 0x22 - } - if len(m.To) > 0 { - i -= len(m.To) - copy(dAtA[i:], m.To) - i = encodeVarintTx(dAtA, i, uint64(len(m.To))) - i-- - dAtA[i] = 0x1a - } - if len(m.From) > 0 { - i -= len(m.From) - copy(dAtA[i:], m.From) - i = encodeVarintTx(dAtA, i, uint64(len(m.From))) + if len(m.Distributors) > 0 { + for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Distributors[iNdEx]) + copy(dAtA[i:], m.Distributors[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Managers) > 0 { + for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Managers[iNdEx]) + copy(dAtA[i:], m.Managers[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Managers[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.TokenId) > 0 { + i -= len(m.TokenId) + copy(dAtA[i:], m.TokenId) + i = encodeVarintTx(dAtA, i, uint64(len(m.TokenId))) i-- dAtA[i] = 0x12 } - if len(m.Symbol) > 0 { - i -= len(m.Symbol) - copy(dAtA[i:], m.Symbol) - i = encodeVarintTx(dAtA, i, uint64(len(m.Symbol))) + if len(m.Issuer) > 0 { + i -= len(m.Issuer) + copy(dAtA[i:], m.Issuer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Issuer))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgTransferTokenResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgAssignRolesResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1297,12 +790,12 @@ func (m *MsgTransferTokenResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgTransferTokenResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAssignRolesResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgTransferTokenResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAssignRolesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1390,7 +883,7 @@ func (m *MsgCreateToken) Size() (n int) { } var l int _ = l - l = len(m.Manager) + l = len(m.Issuer) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -1398,17 +891,40 @@ func (m *MsgCreateToken) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.Decimal != 0 { + n += 1 + sovTx(uint64(m.Decimal)) + } l = len(m.Symbol) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Total) + l = len(m.Description) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.AuthorizationRequired { + if len(m.Managers) > 0 { + for _, s := range m.Managers { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.Distributors) > 0 { + for _, s := range m.Distributors { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if m.AllowNewExtensions { n += 2 } + if len(m.ExtensionsList) > 0 { + for _, s := range m.ExtensionsList { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + l = m.MaxSupply.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1418,595 +934,82 @@ func (m *MsgCreateTokenResponse) Size() (n int) { } var l int _ = l + l = len(m.TokenId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } -func (m *MsgUpdateToken) Size() (n int) { +func (m *MsgAssignRoles) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Manager) + l = len(m.Issuer) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Symbol) + l = len(m.TokenId) if l > 0 { n += 1 + l + sovTx(uint64(l)) - } - if m.AuthorizationRequired { - n += 2 - } - return n -} - -func (m *MsgUpdateTokenResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgAuthorizeAddress) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Manager) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Symbol) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Address) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgAuthorizeAddressResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUnAuthorizeAddress) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Manager) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Symbol) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Address) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgUnAuthorizeAddressResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgTransferToken) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Symbol) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.From) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.To) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Amount) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgTransferTokenResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUpdateParams) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = m.Params.Size() - n += 1 + l + sovTx(uint64(l)) - return n -} - -func (m *MsgUpdateParamsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgCreateToken: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCreateToken: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Manager", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Manager = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Symbol = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Total = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AuthorizationRequired", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.AuthorizationRequired = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgCreateTokenResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgCreateTokenResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCreateTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateToken) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateToken: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateToken: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Manager", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Manager = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Symbol = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AuthorizationRequired", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.AuthorizationRequired = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateTokenResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateTokenResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy + } + if len(m.Managers) > 0 { + for _, s := range m.Managers { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.Distributors) > 0 { + for _, s := range m.Distributors { + l = len(s) + n += 1 + l + sovTx(uint64(l)) } } + return n +} - if iNdEx > l { - return io.ErrUnexpectedEOF +func (m *MsgAssignRolesResponse) Size() (n int) { + if m == nil { + return 0 } - return nil + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *MsgAuthorizeAddress) Unmarshal(dAtA []byte) error { +func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2029,15 +1032,15 @@ func (m *MsgAuthorizeAddress) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAuthorizeAddress: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCreateToken: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAuthorizeAddress: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCreateToken: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Manager", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2065,11 +1068,11 @@ func (m *MsgAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Manager = string(dAtA[iNdEx:postIndex]) + m.Issuer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2097,11 +1100,30 @@ func (m *MsgAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Symbol = string(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Decimal", wireType) + } + m.Decimal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Decimal |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2129,111 +1151,75 @@ func (m *MsgAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.Symbol = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgAuthorizeAddressResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgAuthorizeAddressResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAuthorizeAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if (skippy < 0) || (iNdEx+skippy) < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUnAuthorizeAddress) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUnAuthorizeAddress: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnAuthorizeAddress: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Manager", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2261,11 +1247,31 @@ func (m *MsgUnAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Manager = string(dAtA[iNdEx:postIndex]) + m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 2: + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowNewExtensions", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AllowNewExtensions = bool(v != 0) + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExtensionsList", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2293,11 +1299,11 @@ func (m *MsgUnAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Symbol = string(dAtA[iNdEx:postIndex]) + m.ExtensionsList = append(m.ExtensionsList, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 3: + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxSupply", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2325,7 +1331,9 @@ func (m *MsgUnAuthorizeAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + if err := m.MaxSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -2348,7 +1356,7 @@ func (m *MsgUnAuthorizeAddress) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUnAuthorizeAddressResponse) Unmarshal(dAtA []byte) error { +func (m *MsgCreateTokenResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2371,12 +1379,44 @@ func (m *MsgUnAuthorizeAddressResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUnAuthorizeAddressResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCreateTokenResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnAuthorizeAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCreateTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -2398,7 +1438,7 @@ func (m *MsgUnAuthorizeAddressResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { +func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2421,15 +1461,15 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTransferToken: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAssignRoles: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTransferToken: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAssignRoles: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2457,11 +1497,11 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Symbol = string(dAtA[iNdEx:postIndex]) + m.Issuer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TokenId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2489,11 +1529,11 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.From = string(dAtA[iNdEx:postIndex]) + m.TokenId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2521,11 +1561,11 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.To = string(dAtA[iNdEx:postIndex]) + m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2553,7 +1593,7 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Amount = string(dAtA[iNdEx:postIndex]) + m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex default: iNdEx = preIndex @@ -2576,7 +1616,7 @@ func (m *MsgTransferToken) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgTransferTokenResponse) Unmarshal(dAtA []byte) error { +func (m *MsgAssignRolesResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2599,10 +1639,10 @@ func (m *MsgTransferTokenResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgTransferTokenResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAssignRolesResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgTransferTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAssignRolesResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/x/asset/types/types.go b/x/asset/types/types.go deleted file mode 100644 index ab1254f4..00000000 --- a/x/asset/types/types.go +++ /dev/null @@ -1 +0,0 @@ -package types From 230b6fdb1687745b6b0342d91bd68776c7b2d02d Mon Sep 17 00:00:00 2001 From: Trinity Date: Thu, 16 Jan 2025 12:23:40 +0700 Subject: [PATCH 17/53] Add unassign msg handler --- proto/realionetwork/asset/v1/tx.proto | 13 + x/asset/keeper/keeper.go | 25 +- x/asset/keeper/msg_server.go | 72 +++- x/asset/types/keys.go | 8 +- x/asset/types/msgs.go | 32 ++ x/asset/types/tx.pb.go | 575 ++++++++++++++++++++++++-- 6 files changed, 658 insertions(+), 67 deletions(-) diff --git a/proto/realionetwork/asset/v1/tx.proto b/proto/realionetwork/asset/v1/tx.proto index 9122e935..99e455e5 100644 --- a/proto/realionetwork/asset/v1/tx.proto +++ b/proto/realionetwork/asset/v1/tx.proto @@ -16,6 +16,7 @@ service Msg { // this line is used by starport scaffolding # proto/tx/rpc rpc CreateToken(MsgCreateToken) returns (MsgCreateTokenResponse); rpc AssignRoles(MsgAssignRoles) returns (MsgAssignRolesResponse); + rpc UnassignRoles(MsgUnassignRoles) returns (MsgUnassignRolesResponse); } message MsgCreateToken { @@ -53,6 +54,18 @@ message MsgAssignRoles { message MsgAssignRolesResponse {} +message MsgUnassignRoles { + option (cosmos.msg.v1.signer) = "issuer"; + // issuer is the address that defines the token + string issuer = 1; + + string token_id = 2; + repeated string managers = 3; + repeated string distributors = 4; +} + +message MsgUnassignRolesResponse {} + message MsgUpdateParams { option (cosmos.msg.v1.signer) = "authority"; // authority is the address that controls the module (defaults to x/gov unless diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index c470a714..b8320295 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -29,7 +29,7 @@ type Keeper struct { Token collections.Map[string, types.Token] TokenManagement collections.Map[string, types.TokenManagement] TokenDistribution collections.Map[string, types.TokenDistribution] - WhitelistAddresses collections.Map[sdk.AccAddress, bool] + WhitelistAddresses collections.Map[string, bool] } // NewKeeper returns a new Keeper object with a given codec, dedicated @@ -44,15 +44,16 @@ func NewKeeper( ) *Keeper { sb := collections.NewSchemaBuilder(storeService) k := Keeper{ - cdc: cdc, - storeService: storeService, - authority: authority, - bk: bk, - ak: ak, - Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), - Token: collections.NewMap(sb, types.TokenKeyPrefix, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), - TokenManagement: collections.NewMap(sb, types.TokenKeyPrefix, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), - TokenDistribution: collections.NewMap(sb, types.TokenKeyPrefix, "token_distribution", collections.StringKey, codec.CollValue[types.TokenDistribution](cdc)), + cdc: cdc, + storeService: storeService, + authority: authority, + bk: bk, + ak: ak, + Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), + Token: collections.NewMap(sb, types.TokenKey, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), + TokenManagement: collections.NewMap(sb, types.TokenManagementKey, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), + TokenDistribution: collections.NewMap(sb, types.TokenDistributionKey, "token_distribution", collections.StringKey, codec.CollValue[types.TokenDistribution](cdc)), + WhitelistAddresses: collections.NewMap(sb, types.WhitelistAddressesKey, "whitelist_addresses", collections.StringKey, collections.BoolValue), } schema, err := sb.Build() @@ -68,8 +69,8 @@ func (k Keeper) Logger(ctx context.Context) log.Logger { return sdkCtx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -func (k Keeper) GetWhitelistAddress(ctx context.Context, accAddr sdk.AccAddress) bool { - found, err := k.WhitelistAddresses.Get(ctx, accAddr) +func (k Keeper) GetWhitelistAddress(ctx context.Context, address string) bool { + found, err := k.WhitelistAddresses.Get(ctx, address) if err != nil { return false } diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index e5cee653..c51de54f 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -3,6 +3,7 @@ package keeper import ( "context" "fmt" + "slices" "strings" errorsmod "cosmossdk.io/errors" @@ -34,12 +35,7 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) return nil, err } - issuerAddr, err := ms.ak.AddressCodec().StringToBytes(msg.Issuer) - if err != nil { - return nil, errorsmod.Wrapf(types.ErrAccAddress, err.Error()) - } - - if !ms.GetWhitelistAddress(ctx, issuerAddr) { + if !ms.GetWhitelistAddress(ctx, msg.Issuer) { return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not in whitelisted addresses") } @@ -55,7 +51,7 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) // TODO: create evm precompile here token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer) - err = ms.Token.Set(ctx, tokenId, token) + err := ms.Token.Set(ctx, tokenId, token) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenSet, err.Error()) } @@ -110,7 +106,10 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) if err != nil { return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) } - tokenManagement.Managers = msg.Managers + newManagers := append(tokenManagement.Managers, msg.Managers...) + slices.Sort(newManagers) + tokenManagement.Managers = slices.Compact(newManagers) + err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) @@ -120,7 +119,10 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) if err != nil { return nil, errorsmod.Wrapf(types.ErrTokenDistributionGet, err.Error()) } - tokenDistribution.Distributors = msg.Distributors + newDistributors := append(tokenDistribution.Distributors, msg.Distributors...) + slices.Sort(newDistributors) + tokenDistribution.Distributors = slices.Compact(newDistributors) + err = ms.TokenDistribution.Set(ctx, msg.TokenId, tokenDistribution) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) @@ -136,6 +138,58 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) return &types.MsgAssignRolesResponse{}, nil } +func (ms msgServer) UnassignRoles(ctx context.Context, msg *types.MsgUnassignRoles) (*types.MsgUnassignRolesResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + token, err := ms.Token.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) + } + + if msg.Issuer != token.Issuer { + return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") + } + + tokenManagement, err := ms.TokenManagement.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) + } + tokenManagement.Managers = slices.DeleteFunc(tokenManagement.Managers, func(manager string) bool { + return slices.Contains(msg.Managers, manager) + }) + + err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) + } + + tokenDistribution, err := ms.TokenDistribution.Get(ctx, msg.TokenId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrTokenDistributionGet, err.Error()) + } + + tokenDistribution.Distributors = slices.DeleteFunc(tokenDistribution.Distributors, func(distributor string) bool { + return slices.Contains(msg.Distributors, distributor) + }) + err = ms.TokenDistribution.Set(ctx, msg.TokenId, tokenDistribution) + if err != nil { + return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) + } + + sdkCtx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeTokenAuthorizeUpdated, + sdk.NewAttribute(types.AttributeKeyTokenId, msg.TokenId), + ), + ) + + return &types.MsgUnassignRolesResponse{}, nil +} + // UpdateParams updates the params. func (ms msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if ms.authority != msg.Authority { diff --git a/x/asset/types/keys.go b/x/asset/types/keys.go index 8e5a0431..17b3644e 100644 --- a/x/asset/types/keys.go +++ b/x/asset/types/keys.go @@ -5,9 +5,11 @@ import ( ) var ( - ParamsKey = collections.NewPrefix(0) - TokenKeyPrefix = collections.NewPrefix(1) - IssuerPrefixKey = "issuer" + ParamsKey = collections.NewPrefix(0) + TokenKey = collections.NewPrefix(1) + TokenManagementKey = collections.NewPrefix(2) + TokenDistributionKey = collections.NewPrefix(3) + WhitelistAddressesKey = collections.NewPrefix(4) ) const ( diff --git a/x/asset/types/msgs.go b/x/asset/types/msgs.go index 4cd09bb5..b1ee9b2e 100644 --- a/x/asset/types/msgs.go +++ b/x/asset/types/msgs.go @@ -74,3 +74,35 @@ func (msg *MsgAssignRoles) ValidateBasic() error { return ValidateTokenId(msg.TokenId) } + +func NewMsgUnassignRoles(issuer string, tokenId string, managers []string, distributors []string) *MsgUnassignRoles { + return &MsgUnassignRoles{ + Issuer: issuer, + TokenId: tokenId, + Managers: managers, + Distributors: distributors, + } +} + +func (msg *MsgUnassignRoles) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Issuer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) + } + + for _, manager := range msg.Managers { + _, err := sdk.AccAddressFromBech32(manager) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) + } + } + + for _, distributor := range msg.Distributors { + _, err := sdk.AccAddressFromBech32(distributor) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) + } + } + + return ValidateTokenId(msg.TokenId) +} diff --git a/x/asset/types/tx.pb.go b/x/asset/types/tx.pb.go index ede37d5f..618241d3 100644 --- a/x/asset/types/tx.pb.go +++ b/x/asset/types/tx.pb.go @@ -290,6 +290,111 @@ func (m *MsgAssignRolesResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAssignRolesResponse proto.InternalMessageInfo +type MsgUnassignRoles struct { + // issuer is the address that defines the token + Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` + Distributors []string `protobuf:"bytes,4,rep,name=distributors,proto3" json:"distributors,omitempty"` +} + +func (m *MsgUnassignRoles) Reset() { *m = MsgUnassignRoles{} } +func (m *MsgUnassignRoles) String() string { return proto.CompactTextString(m) } +func (*MsgUnassignRoles) ProtoMessage() {} +func (*MsgUnassignRoles) Descriptor() ([]byte, []int) { + return fileDescriptor_1cfda60866e68e13, []int{4} +} +func (m *MsgUnassignRoles) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUnassignRoles) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUnassignRoles.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUnassignRoles) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUnassignRoles.Merge(m, src) +} +func (m *MsgUnassignRoles) XXX_Size() int { + return m.Size() +} +func (m *MsgUnassignRoles) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUnassignRoles.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUnassignRoles proto.InternalMessageInfo + +func (m *MsgUnassignRoles) GetIssuer() string { + if m != nil { + return m.Issuer + } + return "" +} + +func (m *MsgUnassignRoles) GetTokenId() string { + if m != nil { + return m.TokenId + } + return "" +} + +func (m *MsgUnassignRoles) GetManagers() []string { + if m != nil { + return m.Managers + } + return nil +} + +func (m *MsgUnassignRoles) GetDistributors() []string { + if m != nil { + return m.Distributors + } + return nil +} + +type MsgUnassignRolesResponse struct { +} + +func (m *MsgUnassignRolesResponse) Reset() { *m = MsgUnassignRolesResponse{} } +func (m *MsgUnassignRolesResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUnassignRolesResponse) ProtoMessage() {} +func (*MsgUnassignRolesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1cfda60866e68e13, []int{5} +} +func (m *MsgUnassignRolesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUnassignRolesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUnassignRolesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUnassignRolesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUnassignRolesResponse.Merge(m, src) +} +func (m *MsgUnassignRolesResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUnassignRolesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUnassignRolesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUnassignRolesResponse proto.InternalMessageInfo + type MsgUpdateParams struct { // authority is the address that controls the module (defaults to x/gov unless // overwritten). @@ -304,7 +409,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{4} + return fileDescriptor_1cfda60866e68e13, []int{6} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -354,7 +459,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_1cfda60866e68e13, []int{5} + return fileDescriptor_1cfda60866e68e13, []int{7} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -388,6 +493,8 @@ func init() { proto.RegisterType((*MsgCreateTokenResponse)(nil), "realionetwork.asset.v1.MsgCreateTokenResponse") proto.RegisterType((*MsgAssignRoles)(nil), "realionetwork.asset.v1.MsgAssignRoles") proto.RegisterType((*MsgAssignRolesResponse)(nil), "realionetwork.asset.v1.MsgAssignRolesResponse") + proto.RegisterType((*MsgUnassignRoles)(nil), "realionetwork.asset.v1.MsgUnassignRoles") + proto.RegisterType((*MsgUnassignRolesResponse)(nil), "realionetwork.asset.v1.MsgUnassignRolesResponse") proto.RegisterType((*MsgUpdateParams)(nil), "realionetwork.asset.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "realionetwork.asset.v1.MsgUpdateParamsResponse") } @@ -395,47 +502,49 @@ func init() { func init() { proto.RegisterFile("realionetwork/asset/v1/tx.proto", fileDescriptor_1cfda60866e68e13) } var fileDescriptor_1cfda60866e68e13 = []byte{ - // 635 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x41, 0x4f, 0xdb, 0x30, - 0x14, 0x6e, 0xda, 0x52, 0x5a, 0x97, 0x81, 0x64, 0x31, 0x08, 0xd5, 0x16, 0xaa, 0x4c, 0x1a, 0x15, - 0xd2, 0x92, 0x01, 0x37, 0xc4, 0x65, 0x4c, 0x3b, 0x20, 0xc1, 0x34, 0x65, 0xdb, 0x65, 0x97, 0xc8, - 0x6d, 0xac, 0xd4, 0x22, 0x8e, 0xa3, 0x3c, 0x97, 0xb6, 0x87, 0x49, 0xd3, 0x7e, 0x01, 0x3f, 0x85, - 0x1f, 0xb1, 0x03, 0x47, 0x8e, 0xd3, 0x0e, 0x68, 0x82, 0x03, 0xff, 0x60, 0xe7, 0x29, 0x4e, 0x4a, - 0x13, 0x46, 0x19, 0x37, 0xbf, 0xf7, 0x3e, 0x7f, 0xef, 0xf3, 0xf7, 0x6c, 0xa3, 0xf5, 0x98, 0x92, - 0x80, 0x89, 0x90, 0xca, 0xa1, 0x88, 0x8f, 0x6d, 0x02, 0x40, 0xa5, 0x7d, 0xb2, 0x65, 0xcb, 0x91, - 0x15, 0xc5, 0x42, 0x0a, 0xbc, 0x52, 0x00, 0x58, 0x0a, 0x60, 0x9d, 0x6c, 0xb5, 0x96, 0x7d, 0xe1, - 0x0b, 0x05, 0xb1, 0x93, 0x55, 0x8a, 0x6e, 0xbd, 0x98, 0x41, 0x17, 0x91, 0x98, 0x70, 0xc8, 0x40, - 0xe6, 0xac, 0x9e, 0xe2, 0x98, 0x86, 0x19, 0x66, 0xad, 0x27, 0x80, 0x0b, 0x70, 0xd3, 0x0e, 0x69, - 0x90, 0x95, 0x56, 0xd3, 0xc8, 0xe6, 0xe0, 0x27, 0xbb, 0x38, 0xf8, 0x69, 0xc1, 0xfc, 0x53, 0x46, - 0x8b, 0x47, 0xe0, 0xbf, 0x8d, 0x29, 0x91, 0xf4, 0x53, 0x42, 0x86, 0x57, 0x50, 0x8d, 0x01, 0x0c, - 0x68, 0xac, 0x6b, 0x6d, 0xad, 0xd3, 0x70, 0xb2, 0x08, 0x63, 0x54, 0x0d, 0x09, 0xa7, 0x7a, 0x59, - 0x65, 0xd5, 0x1a, 0xeb, 0x68, 0xde, 0xa3, 0x3d, 0xc6, 0x49, 0xa0, 0x57, 0xda, 0x5a, 0xe7, 0x89, - 0x33, 0x09, 0x13, 0x16, 0x18, 0xf3, 0xae, 0x08, 0xf4, 0x6a, 0xca, 0x92, 0x46, 0xb8, 0x8d, 0x9a, - 0x1e, 0x85, 0x5e, 0xcc, 0x22, 0xc9, 0x44, 0xa8, 0xcf, 0xa9, 0x62, 0x3e, 0x85, 0x5b, 0xa8, 0xce, - 0x49, 0x48, 0x7c, 0x1a, 0x83, 0x5e, 0x6b, 0x57, 0x3a, 0x0d, 0xe7, 0x36, 0xc6, 0x26, 0x5a, 0xf0, - 0x18, 0xc8, 0x98, 0x75, 0x07, 0x52, 0xc4, 0xa0, 0xcf, 0xab, 0x7a, 0x21, 0x87, 0x5f, 0xa3, 0x65, - 0x12, 0x04, 0x62, 0xe8, 0x86, 0x74, 0xe8, 0xd2, 0x91, 0xa4, 0x21, 0x30, 0x11, 0x82, 0x5e, 0x6f, - 0x6b, 0x9d, 0xba, 0x83, 0x55, 0xed, 0x3d, 0x1d, 0xbe, 0xbb, 0xad, 0xe0, 0x0d, 0xb4, 0x34, 0xc5, - 0xb9, 0x01, 0x03, 0xa9, 0x37, 0x14, 0xf1, 0xe2, 0x34, 0x7d, 0xc8, 0x40, 0xe2, 0x3d, 0x84, 0x38, - 0x19, 0xb9, 0x30, 0x88, 0xa2, 0x60, 0xac, 0xa3, 0x44, 0xfb, 0xfe, 0xf3, 0xf3, 0xcb, 0xf5, 0xd2, - 0xaf, 0xcb, 0xf5, 0xa7, 0xa9, 0xc5, 0xe0, 0x1d, 0x5b, 0x4c, 0xd8, 0x9c, 0xc8, 0xbe, 0x75, 0x10, - 0x4a, 0xa7, 0xc1, 0xc9, 0xe8, 0xa3, 0xc2, 0xef, 0x36, 0xbf, 0xdf, 0x9c, 0x6d, 0x66, 0x6e, 0x9a, - 0x3b, 0x68, 0xa5, 0xe8, 0xbb, 0x43, 0x21, 0x12, 0x21, 0x50, 0xbc, 0x86, 0xea, 0x6a, 0xaa, 0x2e, - 0xf3, 0xb2, 0x09, 0xcc, 0xab, 0xf8, 0xc0, 0x33, 0x4f, 0x35, 0x35, 0xad, 0x37, 0x00, 0xcc, 0x0f, - 0x1d, 0x11, 0x50, 0x98, 0x39, 0xad, 0x3c, 0x4b, 0xb9, 0xc0, 0x52, 0x30, 0xb8, 0xf2, 0x1f, 0x83, - 0xab, 0xff, 0x1a, 0x5c, 0x3c, 0x87, 0xae, 0xce, 0x91, 0x53, 0x34, 0x39, 0x87, 0xf9, 0x15, 0x2d, - 0x1d, 0x81, 0xff, 0x39, 0xf2, 0x88, 0xa4, 0x1f, 0xd4, 0x5d, 0xc6, 0xcf, 0x50, 0x83, 0x0c, 0x64, - 0x5f, 0xc4, 0x4c, 0x8e, 0x33, 0xbd, 0xd3, 0x04, 0xde, 0x43, 0xb5, 0xf4, 0xce, 0x2b, 0xc1, 0xcd, - 0x6d, 0xc3, 0xba, 0xff, 0x1d, 0x59, 0x29, 0xdb, 0x7e, 0x35, 0x71, 0xde, 0xc9, 0xf6, 0xec, 0x2e, - 0x26, 0xaa, 0xa6, 0x6c, 0xe6, 0x1a, 0x5a, 0xbd, 0xd3, 0x7e, 0xa2, 0x6c, 0xfb, 0x47, 0x19, 0x55, - 0x8e, 0xc0, 0xc7, 0x7d, 0xb4, 0x50, 0x90, 0xb7, 0x31, 0xab, 0xe1, 0x1d, 0xa2, 0x96, 0xfd, 0x48, - 0xe0, 0xed, 0x4c, 0x29, 0x6a, 0xe6, 0x9f, 0xd8, 0xcb, 0x07, 0xf6, 0xe7, 0x70, 0x2d, 0xeb, 0x71, - 0xb8, 0x7c, 0x9b, 0xfc, 0xdd, 0x78, 0xa8, 0x4d, 0x0e, 0xf7, 0x60, 0x9b, 0x7b, 0x26, 0xdb, 0x9a, - 0xfb, 0x76, 0x73, 0xb6, 0xa9, 0xed, 0x1f, 0x9e, 0x5f, 0x19, 0xda, 0xc5, 0x95, 0xa1, 0xfd, 0xbe, - 0x32, 0xb4, 0xd3, 0x6b, 0xa3, 0x74, 0x71, 0x6d, 0x94, 0x7e, 0x5e, 0x1b, 0xa5, 0x2f, 0xdb, 0x3e, - 0x93, 0xfd, 0x41, 0xd7, 0xea, 0x09, 0x6e, 0xa7, 0xd4, 0x92, 0xf6, 0xfa, 0xd9, 0xf2, 0xd5, 0xe4, - 0x13, 0x1b, 0x65, 0xdf, 0x98, 0x1c, 0x47, 0x14, 0xba, 0x35, 0xf5, 0x21, 0xed, 0xfc, 0x0d, 0x00, - 0x00, 0xff, 0xff, 0xab, 0x09, 0x3e, 0x08, 0x5e, 0x05, 0x00, 0x00, + // 672 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcd, 0x4e, 0xdb, 0x4c, + 0x14, 0x8d, 0x49, 0x08, 0xc9, 0x84, 0x9f, 0x4f, 0x23, 0x3e, 0x30, 0x56, 0x6b, 0x22, 0x57, 0x2a, + 0x11, 0x52, 0x6d, 0x7e, 0x76, 0x88, 0x4d, 0xa9, 0xba, 0x40, 0x82, 0xaa, 0x72, 0xdb, 0x4d, 0x37, + 0xd1, 0x24, 0x1e, 0x39, 0xa3, 0xd8, 0x1e, 0xcb, 0x77, 0x42, 0x92, 0x45, 0xa5, 0xaa, 0x4f, 0x80, + 0xfa, 0x24, 0xf4, 0x2d, 0x58, 0xb2, 0xac, 0xba, 0x40, 0x15, 0x2c, 0x78, 0x83, 0xae, 0x2b, 0x8f, + 0x9d, 0xc4, 0xa6, 0x24, 0x65, 0xd9, 0xdd, 0xdc, 0x7b, 0xcf, 0x9c, 0x73, 0xe6, 0xce, 0x9d, 0x41, + 0x9b, 0x11, 0x25, 0x1e, 0xe3, 0x01, 0x15, 0x7d, 0x1e, 0x75, 0x2d, 0x02, 0x40, 0x85, 0x75, 0xb6, + 0x6b, 0x89, 0x81, 0x19, 0x46, 0x5c, 0x70, 0xbc, 0x96, 0x03, 0x98, 0x12, 0x60, 0x9e, 0xed, 0x6a, + 0xab, 0x2e, 0x77, 0xb9, 0x84, 0x58, 0xf1, 0x2a, 0x41, 0x6b, 0xcf, 0xa6, 0xd0, 0x85, 0x24, 0x22, + 0x3e, 0xa4, 0x20, 0x63, 0x9a, 0x26, 0xef, 0xd2, 0x20, 0xc5, 0x6c, 0xb4, 0x39, 0xf8, 0x1c, 0x9a, + 0x89, 0x42, 0x12, 0xa4, 0xa5, 0xf5, 0x24, 0xb2, 0x7c, 0x70, 0xe3, 0x5d, 0x3e, 0xb8, 0x49, 0xc1, + 0xf8, 0x35, 0x87, 0x96, 0x4f, 0xc1, 0x7d, 0x15, 0x51, 0x22, 0xe8, 0xfb, 0x98, 0x0c, 0xaf, 0xa1, + 0x32, 0x03, 0xe8, 0xd1, 0x48, 0x55, 0xea, 0x4a, 0xa3, 0x6a, 0xa7, 0x11, 0xc6, 0xa8, 0x14, 0x10, + 0x9f, 0xaa, 0x73, 0x32, 0x2b, 0xd7, 0x58, 0x45, 0x0b, 0x0e, 0x6d, 0x33, 0x9f, 0x78, 0x6a, 0xb1, + 0xae, 0x34, 0x96, 0xec, 0x51, 0x18, 0xb3, 0xc0, 0xd0, 0x6f, 0x71, 0x4f, 0x2d, 0x25, 0x2c, 0x49, + 0x84, 0xeb, 0xa8, 0xe6, 0x50, 0x68, 0x47, 0x2c, 0x14, 0x8c, 0x07, 0xea, 0xbc, 0x2c, 0x66, 0x53, + 0x58, 0x43, 0x15, 0x9f, 0x04, 0xc4, 0xa5, 0x11, 0xa8, 0xe5, 0x7a, 0xb1, 0x51, 0xb5, 0xc7, 0x31, + 0x36, 0xd0, 0xa2, 0xc3, 0x40, 0x44, 0xac, 0xd5, 0x13, 0x3c, 0x02, 0x75, 0x41, 0xd6, 0x73, 0x39, + 0xbc, 0x83, 0x56, 0x89, 0xe7, 0xf1, 0x7e, 0x33, 0xa0, 0xfd, 0x26, 0x1d, 0x08, 0x1a, 0x00, 0xe3, + 0x01, 0xa8, 0x95, 0xba, 0xd2, 0xa8, 0xd8, 0x58, 0xd6, 0xde, 0xd0, 0xfe, 0xeb, 0x71, 0x05, 0x6f, + 0xa1, 0x95, 0x09, 0xae, 0xe9, 0x31, 0x10, 0x6a, 0x55, 0x12, 0x2f, 0x4f, 0xd2, 0x27, 0x0c, 0x04, + 0x3e, 0x44, 0xc8, 0x27, 0x83, 0x26, 0xf4, 0xc2, 0xd0, 0x1b, 0xaa, 0x28, 0xf6, 0x7e, 0xf4, 0xf4, + 0xf2, 0x7a, 0xb3, 0xf0, 0xe3, 0x7a, 0xf3, 0xff, 0xa4, 0xc5, 0xe0, 0x74, 0x4d, 0xc6, 0x2d, 0x9f, + 0x88, 0x8e, 0x79, 0x1c, 0x08, 0xbb, 0xea, 0x93, 0xc1, 0x3b, 0x89, 0x3f, 0xa8, 0x7d, 0xb9, 0xbb, + 0xd8, 0x4e, 0xbb, 0x69, 0xec, 0xa3, 0xb5, 0x7c, 0xdf, 0x6d, 0x0a, 0x21, 0x0f, 0x80, 0xe2, 0x0d, + 0x54, 0x91, 0xb7, 0xda, 0x64, 0x4e, 0x7a, 0x03, 0x0b, 0x32, 0x3e, 0x76, 0x8c, 0x73, 0x45, 0xde, + 0xd6, 0x4b, 0x00, 0xe6, 0x06, 0x36, 0xf7, 0x28, 0x4c, 0xbd, 0xad, 0x2c, 0xcb, 0x5c, 0x8e, 0x25, + 0xd7, 0xe0, 0xe2, 0x5f, 0x1a, 0x5c, 0xfa, 0xb3, 0xc1, 0xf9, 0x73, 0xa8, 0xf2, 0x1c, 0x19, 0x47, + 0xa3, 0x73, 0x18, 0x5f, 0x15, 0xf4, 0xdf, 0x29, 0xb8, 0x1f, 0x02, 0xf2, 0x0f, 0xd9, 0xd5, 0x90, + 0x7a, 0xdf, 0xd3, 0xd8, 0xf0, 0x27, 0xb4, 0x12, 0xd7, 0x42, 0x87, 0x08, 0xfa, 0x56, 0x3e, 0x3e, + 0xfc, 0x04, 0x55, 0x49, 0x4f, 0x74, 0x78, 0xc4, 0xc4, 0x30, 0x75, 0x3c, 0x49, 0xe0, 0x43, 0x54, + 0x4e, 0x1e, 0xa9, 0xb4, 0x5c, 0xdb, 0xd3, 0xcd, 0x87, 0x1f, 0xbe, 0x99, 0xb0, 0x1d, 0x95, 0xe2, + 0x51, 0xb1, 0xd3, 0x3d, 0x07, 0xcb, 0xb1, 0xaf, 0x09, 0x9b, 0xb1, 0x81, 0xd6, 0xef, 0xc9, 0x8f, + 0x9c, 0xed, 0x7d, 0x2b, 0xa2, 0xe2, 0x29, 0xb8, 0xb8, 0x83, 0x16, 0x73, 0xf6, 0xb6, 0xa6, 0x09, + 0xde, 0x23, 0xd2, 0xac, 0x47, 0x02, 0xc7, 0x43, 0x48, 0x51, 0x2d, 0xfb, 0x27, 0x3c, 0x9f, 0xb1, + 0x3f, 0x83, 0xd3, 0xcc, 0xc7, 0xe1, 0xb2, 0x32, 0xd9, 0x61, 0x9e, 0x25, 0x93, 0xc1, 0xcd, 0x94, + 0x79, 0x60, 0x14, 0x71, 0x17, 0x2d, 0xe5, 0xc7, 0xb0, 0x31, 0xab, 0x1f, 0x59, 0xa4, 0xb6, 0xf3, + 0x58, 0xe4, 0x48, 0x4c, 0x9b, 0xff, 0x7c, 0x77, 0xb1, 0xad, 0x1c, 0x9d, 0x5c, 0xde, 0xe8, 0xca, + 0xd5, 0x8d, 0xae, 0xfc, 0xbc, 0xd1, 0x95, 0xf3, 0x5b, 0xbd, 0x70, 0x75, 0xab, 0x17, 0xbe, 0xdf, + 0xea, 0x85, 0x8f, 0x7b, 0x2e, 0x13, 0x9d, 0x5e, 0xcb, 0x6c, 0x73, 0xdf, 0x4a, 0xc8, 0x05, 0x6d, + 0x77, 0xd2, 0xe5, 0x8b, 0xd1, 0x17, 0x3f, 0x48, 0x3f, 0x79, 0x31, 0x0c, 0x29, 0xb4, 0xca, 0xf2, + 0xbb, 0xde, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x50, 0x6a, 0x7b, 0x32, 0x7c, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -454,6 +563,7 @@ type MsgClient interface { // this line is used by starport scaffolding # proto/tx/rpc CreateToken(ctx context.Context, in *MsgCreateToken, opts ...grpc.CallOption) (*MsgCreateTokenResponse, error) AssignRoles(ctx context.Context, in *MsgAssignRoles, opts ...grpc.CallOption) (*MsgAssignRolesResponse, error) + UnassignRoles(ctx context.Context, in *MsgUnassignRoles, opts ...grpc.CallOption) (*MsgUnassignRolesResponse, error) } type msgClient struct { @@ -491,12 +601,22 @@ func (c *msgClient) AssignRoles(ctx context.Context, in *MsgAssignRoles, opts .. return out, nil } +func (c *msgClient) UnassignRoles(ctx context.Context, in *MsgUnassignRoles, opts ...grpc.CallOption) (*MsgUnassignRolesResponse, error) { + out := new(MsgUnassignRolesResponse) + err := c.cc.Invoke(ctx, "/realionetwork.asset.v1.Msg/UnassignRoles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) // this line is used by starport scaffolding # proto/tx/rpc CreateToken(context.Context, *MsgCreateToken) (*MsgCreateTokenResponse, error) AssignRoles(context.Context, *MsgAssignRoles) (*MsgAssignRolesResponse, error) + UnassignRoles(context.Context, *MsgUnassignRoles) (*MsgUnassignRolesResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -512,6 +632,9 @@ func (*UnimplementedMsgServer) CreateToken(ctx context.Context, req *MsgCreateTo func (*UnimplementedMsgServer) AssignRoles(ctx context.Context, req *MsgAssignRoles) (*MsgAssignRolesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AssignRoles not implemented") } +func (*UnimplementedMsgServer) UnassignRoles(ctx context.Context, req *MsgUnassignRoles) (*MsgUnassignRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnassignRoles not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -571,6 +694,24 @@ func _Msg_AssignRoles_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Msg_UnassignRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUnassignRoles) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UnassignRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/realionetwork.asset.v1.Msg/UnassignRoles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UnassignRoles(ctx, req.(*MsgUnassignRoles)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "realionetwork.asset.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -587,6 +728,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "AssignRoles", Handler: _Msg_AssignRoles_Handler, }, + { + MethodName: "UnassignRoles", + Handler: _Msg_UnassignRoles_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "realionetwork/asset/v1/tx.proto", @@ -803,6 +948,84 @@ func (m *MsgAssignRolesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *MsgUnassignRoles) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUnassignRoles) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnassignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Distributors) > 0 { + for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Distributors[iNdEx]) + copy(dAtA[i:], m.Distributors[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.Managers) > 0 { + for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Managers[iNdEx]) + copy(dAtA[i:], m.Managers[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Managers[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.TokenId) > 0 { + i -= len(m.TokenId) + copy(dAtA[i:], m.TokenId) + i = encodeVarintTx(dAtA, i, uint64(len(m.TokenId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Issuer) > 0 { + i -= len(m.Issuer) + copy(dAtA[i:], m.Issuer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Issuer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUnassignRolesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUnassignRolesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnassignRolesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -979,6 +1202,44 @@ func (m *MsgAssignRolesResponse) Size() (n int) { return n } +func (m *MsgUnassignRoles) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Issuer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.TokenId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Managers) > 0 { + for _, s := range m.Managers { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.Distributors) > 0 { + for _, s := range m.Distributors { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgUnassignRolesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateParams) Size() (n int) { if m == nil { return 0 @@ -1666,6 +1927,234 @@ func (m *MsgAssignRolesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUnassignRoles: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnassignRoles: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Issuer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUnassignRolesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUnassignRolesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnassignRolesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From 2bfcac23e5e1c8a04ec6c89d8c2d1e4a31c7419d Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 20 Jan 2025 12:15:44 +0700 Subject: [PATCH 18/53] temp precompiles --- precompiles/erc20/IERC20.sol | 78 ++ precompiles/erc20/IERC20Metadata.sol | 28 + precompiles/erc20/IERC20MetadataAllowance.sol | 35 + precompiles/erc20/abi.json | 708 ++++++++++++++++++ precompiles/erc20/approve.go | 330 ++++++++ precompiles/erc20/erc20.go | 217 ++++++ precompiles/erc20/errors.go | 98 +++ precompiles/erc20/events.go | 96 +++ precompiles/erc20/query.go | 249 ++++++ precompiles/erc20/tx.go | 144 ++++ precompiles/erc20/types.go | 152 ++++ 11 files changed, 2135 insertions(+) create mode 100644 precompiles/erc20/IERC20.sol create mode 100644 precompiles/erc20/IERC20Metadata.sol create mode 100644 precompiles/erc20/IERC20MetadataAllowance.sol create mode 100644 precompiles/erc20/abi.json create mode 100644 precompiles/erc20/approve.go create mode 100644 precompiles/erc20/erc20.go create mode 100644 precompiles/erc20/errors.go create mode 100644 precompiles/erc20/events.go create mode 100644 precompiles/erc20/query.go create mode 100644 precompiles/erc20/tx.go create mode 100644 precompiles/erc20/types.go diff --git a/precompiles/erc20/IERC20.sol b/precompiles/erc20/IERC20.sol new file mode 100644 index 00000000..66c4e4d8 --- /dev/null +++ b/precompiles/erc20/IERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} diff --git a/precompiles/erc20/IERC20Metadata.sol b/precompiles/erc20/IERC20Metadata.sol new file mode 100644 index 00000000..982bc39e --- /dev/null +++ b/precompiles/erc20/IERC20Metadata.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + +import "./IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} diff --git a/precompiles/erc20/IERC20MetadataAllowance.sol b/precompiles/erc20/IERC20MetadataAllowance.sol new file mode 100644 index 00000000..4eb31bf7 --- /dev/null +++ b/precompiles/erc20/IERC20MetadataAllowance.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.18; + +import "./IERC20Metadata.sol"; + +/** + * @author Evmos Team + * @title ERC20 Metadata Allowance Interface + * @dev Interface for the optional metadata and allowance functions from the ERC20 standard. + */ +interface IERC20MetadataAllowance is IERC20Metadata { + /** @dev Atomically increases the allowance granted to spender by the caller. + * This is an alternative to approve that can be used as a mitigation for problems described in + * IERC20.approve. + * @param spender The address which will spend the funds. + * @param addedValue The amount of tokens added to the spender allowance. + * @return approved Boolean value to indicate if the approval was successful. + */ + function increaseAllowance( + address spender, + uint256 addedValue + ) external returns (bool approved); + + /** @dev Atomically decreases the allowance granted to spender by the caller. + * This is an alternative to approve that can be used as a mitigation for problems described in + * IERC20.approve. + * @param spender The address which will spend the funds. + * @param subtractedValue The amount to be subtracted from the spender allowance. + * @return approved Boolean value to indicate if the approval was successful. + */ + function decreaseAllowance( + address spender, + uint256 subtractedValue + ) external returns (bool approved); +} diff --git a/precompiles/erc20/abi.json b/precompiles/erc20/abi.json new file mode 100644 index 00000000..68edc8d3 --- /dev/null +++ b/precompiles/erc20/abi.json @@ -0,0 +1,708 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20MinterBurnerDecimals", + "sourceName": "solidity/ERC20MinterBurnerDecimals.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "BURNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAUSER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnCoins", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getRoleMember", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleMemberCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x", + "deployedBytecode": "0x", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/precompiles/erc20/approve.go b/precompiles/erc20/approve.go new file mode 100644 index 00000000..029ecfcf --- /dev/null +++ b/precompiles/erc20/approve.go @@ -0,0 +1,330 @@ +package erc20 + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "time" + + sdkerrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + auth "github.com/evmos/os/precompiles/authorization" + cmn "github.com/evmos/os/precompiles/common" + "github.com/evmos/os/x/evm/core/vm" +) + +// Approve sets the given amount as the allowance of the spender address over +// the caller’s tokens. It returns a boolean value indicating whether the +// operation succeeded and emits the Approval event on success. +// +// The Approve method handles 4 cases: +// 1. no authorization, amount negative -> return error +// 2. no authorization, amount positive -> create a new authorization +// 3. authorization exists, amount 0 or negative -> delete authorization +// 4. authorization exists, amount positive -> update authorization +// 5. no authorizaiton, amount 0 -> no-op but still emit Approval event +func (p Precompile) Approve( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + spender, amount, err := ParseApproveArgs(args) + if err != nil { + return nil, err + } + + grantee := spender + granter := contract.CallerAddress + + // NOTE: We do not support approvals if the grantee is the granter. + // This is different from the ERC20 standard but there is no reason to + // do so, since in that case the grantee can just transfer the tokens + // without authorization. + if bytes.Equal(grantee.Bytes(), granter.Bytes()) { + return nil, ErrSpenderIsOwner + } + + // TODO: owner should be the owner of the contract + authorization, expiration, _ := auth.CheckAuthzExists(ctx, p.AuthzKeeper, grantee, granter, SendMsgURL) //#nosec:G703 -- we are handling the error case (authorization == nil) in the switch statement below + + switch { + case authorization == nil && amount != nil && amount.Sign() < 0: + // case 1: no authorization, amount 0 or negative -> error + err = ErrNegativeAmount + case authorization == nil && amount != nil && amount.Sign() > 0: + // case 2: no authorization, amount positive -> create a new authorization + err = p.createAuthorization(ctx, grantee, granter, amount) + case authorization != nil && amount != nil && amount.Sign() <= 0: + // case 3: authorization exists, amount 0 or negative -> remove from spend limit and delete authorization if no spend limit left + err = p.removeSpendLimitOrDeleteAuthorization(ctx, grantee, granter, authorization, expiration) + case authorization != nil && amount != nil && amount.Sign() > 0: + // case 4: authorization exists, amount positive -> update authorization + sendAuthz, ok := authorization.(*banktypes.SendAuthorization) + if !ok { + return nil, authz.ErrUnknownAuthorizationType + } + + err = p.updateAuthorization(ctx, grantee, granter, amount, sendAuthz, expiration) + } + + if err != nil { + return nil, err + } + + // TODO: check owner? + if err := p.EmitApprovalEvent(ctx, stateDB, p.Address(), spender, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +// IncreaseAllowance increases the allowance of the spender address over +// the caller’s tokens by the given added value. It returns a boolean value +// indicating whether the operation succeeded and emits the Approval event on +// success. +// +// The IncreaseAllowance method handles 3 cases: +// 1. addedValue 0 or negative -> return error +// 2. no authorization, addedValue positive -> create a new authorization +// 3. authorization exists, addedValue positive -> update authorization +func (p Precompile) IncreaseAllowance( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + spender, addedValue, err := ParseApproveArgs(args) + if err != nil { + return nil, err + } + + grantee := spender + granter := contract.CallerAddress + + if bytes.Equal(grantee.Bytes(), granter.Bytes()) { + return nil, ErrSpenderIsOwner + } + + // TODO: owner should be the owner of the contract + authorization, expiration, _ := auth.CheckAuthzExists(ctx, p.AuthzKeeper, grantee, granter, SendMsgURL) //#nosec:G703 -- we are handling the error case (authorization == nil) in the switch statement below + + var amount *big.Int + switch { + case addedValue != nil && addedValue.Sign() <= 0: + // case 1: addedValue 0 or negative -> error + // TODO: (@fedekunze) check if this is correct by comparing behavior with + // regular ERC20 + err = ErrIncreaseNonPositiveValue + case authorization == nil && addedValue != nil && addedValue.Sign() > 0: + // case 2: no authorization, amount positive -> create a new authorization + amount = addedValue + err = p.createAuthorization(ctx, grantee, granter, addedValue) + case authorization != nil && addedValue != nil && addedValue.Sign() > 0: + // case 3: authorization exists, amount positive -> update authorization + amount, err = p.increaseAllowance(ctx, grantee, granter, addedValue, authorization, expiration) + } + + if err != nil { + return nil, err + } + + // TODO: check owner? + if err := p.EmitApprovalEvent(ctx, stateDB, p.Address(), spender, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +// DecreaseAllowance decreases the allowance of the spender address over +// the caller’s tokens by the given subtracted value. It returns a boolean value +// indicating whether the operation succeeded and emits the Approval event on +// success. +// +// The DecreaseAllowance method handles 4 cases: +// 1. subtractedValue 0 or negative -> return error +// 2. no authorization -> return error +// 3. authorization exists, subtractedValue positive and subtractedValue less than allowance -> update authorization +// 4. authorization exists, subtractedValue positive and subtractedValue equal to allowance -> delete authorization +// 5. authorization exists, subtractedValue positive but no allowance for given denomination -> return error +// 6. authorization exists, subtractedValue positive and subtractedValue higher than allowance -> return error +func (p Precompile) DecreaseAllowance( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + spender, subtractedValue, err := ParseApproveArgs(args) + if err != nil { + return nil, err + } + + grantee := spender + granter := contract.CallerAddress + + if bytes.Equal(grantee.Bytes(), granter.Bytes()) { + return nil, ErrSpenderIsOwner + } + // TODO: owner should be the owner of the contract + + authorization, expiration, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, grantee, granter, p.tokenPair.Denom) + + // TODO: (@fedekunze) check if this is correct by comparing behavior with + // regular ERC-20 + var amount *big.Int + switch { + case subtractedValue != nil && subtractedValue.Sign() <= 0: + // case 1. subtractedValue 0 or negative -> return error + err = ErrDecreaseNonPositiveValue + case err != nil: + // case 2. no authorization -> return error + err = sdkerrors.Wrap(err, fmt.Sprintf(ErrNoAllowanceForToken, p.tokenPair.Denom)) + case subtractedValue != nil && subtractedValue.Cmp(allowance) < 0: + // case 3. subtractedValue positive and subtractedValue less than allowance -> update authorization + amount, err = p.decreaseAllowance(ctx, grantee, granter, subtractedValue, authorization, expiration) + case subtractedValue != nil && subtractedValue.Cmp(allowance) == 0: + // case 4. subtractedValue positive and subtractedValue equal to allowance -> remove spend limit for token and delete authorization if no other denoms are approved for + err = p.removeSpendLimitOrDeleteAuthorization(ctx, grantee, granter, authorization, expiration) + amount = common.Big0 + case subtractedValue != nil && allowance.Sign() == 0: + // case 5. subtractedValue positive but no allowance for given denomination -> return error + err = fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + case subtractedValue != nil && subtractedValue.Cmp(allowance) > 0: + // case 6. subtractedValue positive and subtractedValue higher than allowance -> return error + err = ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.tokenPair.Denom, subtractedValue, allowance)) + } + + if err != nil { + return nil, err + } + + // TODO: check owner? + if err := p.EmitApprovalEvent(ctx, stateDB, p.Address(), spender, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +func (p Precompile) createAuthorization(ctx sdk.Context, grantee, granter common.Address, amount *big.Int) error { + if amount.BitLen() > sdkmath.MaxBitLen { + return fmt.Errorf(ErrIntegerOverflow, amount) + } + + coins := sdk.Coins{{Denom: p.tokenPair.Denom, Amount: sdkmath.NewIntFromBigInt(amount)}} + expiration := ctx.BlockTime().Add(p.ApprovalExpiration) + + // NOTE: we leave the allowed arg empty as all recipients are allowed (per ERC20 standard) + authorization := banktypes.NewSendAuthorization(coins, []sdk.AccAddress{}) + if err := authorization.ValidateBasic(); err != nil { + return err + } + + return p.AuthzKeeper.SaveGrant(ctx, grantee.Bytes(), granter.Bytes(), authorization, &expiration) +} + +func (p Precompile) updateAuthorization(ctx sdk.Context, grantee, granter common.Address, amount *big.Int, authorization *banktypes.SendAuthorization, expiration *time.Time) error { + authorization.SpendLimit = updateOrAddCoin(authorization.SpendLimit, sdk.Coin{Denom: p.tokenPair.Denom, Amount: sdkmath.NewIntFromBigInt(amount)}) + if err := authorization.ValidateBasic(); err != nil { + return err + } + + return p.AuthzKeeper.SaveGrant(ctx, grantee.Bytes(), granter.Bytes(), authorization, expiration) +} + +// removeSpendLimitOrDeleteAuthorization removes the spend limit for the given +// token and updates the grant or deletes the authorization if no spend limit in another +// denomination is set. +func (p Precompile) removeSpendLimitOrDeleteAuthorization(ctx sdk.Context, grantee, granter common.Address, authorization authz.Authorization, expiration *time.Time) error { + sendAuthz, ok := authorization.(*banktypes.SendAuthorization) + if !ok { + return authz.ErrUnknownAuthorizationType + } + + found, denomCoins := sendAuthz.SpendLimit.Find(p.tokenPair.Denom) + if !found { + return fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + } + + newSpendLimit, hasNeg := sendAuthz.SpendLimit.SafeSub(denomCoins) + // NOTE: safety check only, this should never happen since we only subtract what was found in the slice. + if hasNeg { + return ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, + p.tokenPair.Denom, denomCoins, sendAuthz.SpendLimit, + )) + } + + if newSpendLimit.IsZero() { + return p.AuthzKeeper.DeleteGrant(ctx, grantee.Bytes(), granter.Bytes(), SendMsgURL) + } + + sendAuthz.SpendLimit = newSpendLimit + return p.AuthzKeeper.SaveGrant(ctx, grantee.Bytes(), granter.Bytes(), sendAuthz, expiration) +} + +func (p Precompile) increaseAllowance( + ctx sdk.Context, + grantee, granter common.Address, + addedValue *big.Int, + authorization authz.Authorization, + expiration *time.Time, +) (amount *big.Int, err error) { + sendAuthz, ok := authorization.(*banktypes.SendAuthorization) + if !ok { + return nil, authz.ErrUnknownAuthorizationType + } + + allowance := sendAuthz.SpendLimit.AmountOfNoDenomValidation(p.tokenPair.Denom) + sdkAddedValue := sdkmath.NewIntFromBigInt(addedValue) + amount, overflow := cmn.SafeAdd(allowance, sdkAddedValue) + if overflow { + return nil, ConvertErrToERC20Error(errors.New(cmn.ErrIntegerOverflow)) + } + + if err := p.updateAuthorization(ctx, grantee, granter, amount, sendAuthz, expiration); err != nil { + return nil, err + } + + return amount, nil +} + +func (p Precompile) decreaseAllowance( + ctx sdk.Context, + grantee, granter common.Address, + subtractedValue *big.Int, + authorization authz.Authorization, + expiration *time.Time, +) (amount *big.Int, err error) { + sendAuthz, ok := authorization.(*banktypes.SendAuthorization) + if !ok { + return nil, authz.ErrUnknownAuthorizationType + } + + found, allowance := sendAuthz.SpendLimit.Find(p.tokenPair.Denom) + if !found { + return nil, fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + } + + amount = new(big.Int).Sub(allowance.Amount.BigInt(), subtractedValue) + // NOTE: Safety check only since this is checked in the DecreaseAllowance method already. + if amount.Sign() < 0 { + return nil, ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.tokenPair.Denom, subtractedValue, allowance.Amount)) + } + + if err := p.updateAuthorization(ctx, grantee, granter, amount, sendAuthz, expiration); err != nil { + return nil, err + } + + return amount, nil +} diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go new file mode 100644 index 00000000..a504c45f --- /dev/null +++ b/precompiles/erc20/erc20.go @@ -0,0 +1,217 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "embed" + "fmt" + + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/ethereum/go-ethereum/accounts/abi" + auth "github.com/evmos/os/precompiles/authorization" + cmn "github.com/evmos/os/precompiles/common" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/evmos/os/x/evm/core/vm" + transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" +) + +const ( + // abiPath defines the path to the ERC-20 precompile ABI JSON file. + abiPath = "abi.json" + + GasTransfer = 3_000_000 + GasApprove = 30_956 + GasIncreaseAllowance = 34_605 + GasDecreaseAllowance = 34_519 + GasName = 3_421 + GasSymbol = 3_464 + GasDecimals = 427 + GasTotalSupply = 2_477 + GasBalanceOf = 2_851 + GasAllowance = 3_246 +) + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +var _ vm.PrecompiledContract = &Precompile{} + +// Precompile defines the precompiled contract for ERC-20. +type Precompile struct { + cmn.Precompile + tokenPair erc20types.TokenPair + transferKeeper transferkeeper.Keeper + // BankKeeper is a public field so that the werc20 precompile can use it. + BankKeeper bankkeeper.Keeper +} + +// NewPrecompile creates a new ERC-20 Precompile instance as a +// PrecompiledContract interface. +func NewPrecompile( + tokenPair erc20types.TokenPair, + bankKeeper bankkeeper.Keeper, + authzKeeper authzkeeper.Keeper, + transferKeeper transferkeeper.Keeper, +) (*Precompile, error) { + newABI, err := cmn.LoadABI(f, abiPath) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: cmn.Precompile{ + ABI: newABI, + AuthzKeeper: authzKeeper, + ApprovalExpiration: cmn.DefaultExpirationDuration, + KvGasConfig: storetypes.GasConfig{}, + TransientKVGasConfig: storetypes.GasConfig{}, + }, + tokenPair: tokenPair, + BankKeeper: bankKeeper, + transferKeeper: transferKeeper, + } + // Address defines the address of the ERC-20 precompile contract. + p.SetAddress(p.tokenPair.GetERC20Contract()) + return p, nil +} + +// RequiredGas calculates the contract gas used for the +func (p Precompile) RequiredGas(input []byte) uint64 { + // NOTE: This check avoid panicking when trying to decode the method ID + if len(input) < 4 { + return 0 + } + + methodID := input[:4] + method, err := p.MethodById(methodID) + if err != nil { + return 0 + } + + // TODO: these values were obtained from Remix using the ERC20.sol from OpenZeppelin. + // We should execute the transactions using the ERC20MinterBurnerDecimals.sol from Evmos testnet + // to ensure parity in the values. + switch method.Name { + // ERC-20 transactions + case TransferMethod: + return GasTransfer + case TransferFromMethod: + return GasTransfer + case auth.ApproveMethod: + return GasApprove + case auth.IncreaseAllowanceMethod: + return GasIncreaseAllowance + case auth.DecreaseAllowanceMethod: + return GasDecreaseAllowance + // ERC-20 queries + case NameMethod: + return GasName + case SymbolMethod: + return GasSymbol + case DecimalsMethod: + return GasDecimals + case TotalSupplyMethod: + return GasTotalSupply + case BalanceOfMethod: + return GasBalanceOf + case auth.AllowanceMethod: + return GasAllowance + default: + return 0 + } +} + +// Run executes the precompiled contract ERC-20 methods defined in the ABI. +func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) { + // ERC20 precompiles cannot receive funds because they are not managed by an + // EOA and will not be possible to recover funds sent to an instance of + // them.This check is a safety measure because currently funds cannot be + // received due to the lack of a fallback handler. + if value := contract.Value(); value.Sign() == 1 { + return nil, fmt.Errorf(ErrCannotReceiveFunds, contract.Value().String()) + } + + ctx, stateDB, snapshot, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction) + if err != nil { + return nil, err + } + + // This handles any out of gas errors that may occur during the execution of a precompile tx or query. + // It avoids panics and returns the out of gas error so the EVM can continue gracefully. + defer cmn.HandleGasError(ctx, contract, initialGas, &err)() + + bz, err = p.HandleMethod(ctx, contract, stateDB, method, args) + if err != nil { + return nil, err + } + + cost := ctx.GasMeter().GasConsumed() - initialGas + + if !contract.UseGas(cost) { + return nil, vm.ErrOutOfGas + } + if err := p.AddJournalEntries(stateDB, snapshot); err != nil { + return nil, err + } + return bz, nil +} + +// IsTransaction checks if the given method name corresponds to a transaction or query. +func (Precompile) IsTransaction(method *abi.Method) bool { + switch method.Name { + case TransferMethod, + TransferFromMethod, + auth.ApproveMethod, + auth.IncreaseAllowanceMethod, + auth.DecreaseAllowanceMethod: + return true + default: + return false + } +} + +// HandleMethod handles the execution of each of the ERC-20 methods. +func (p *Precompile) HandleMethod( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) (bz []byte, err error) { + switch method.Name { + // ERC-20 transactions + case TransferMethod: + bz, err = p.Transfer(ctx, contract, stateDB, method, args) + case TransferFromMethod: + bz, err = p.TransferFrom(ctx, contract, stateDB, method, args) + case auth.ApproveMethod: + bz, err = p.Approve(ctx, contract, stateDB, method, args) + case auth.IncreaseAllowanceMethod: + bz, err = p.IncreaseAllowance(ctx, contract, stateDB, method, args) + case auth.DecreaseAllowanceMethod: + bz, err = p.DecreaseAllowance(ctx, contract, stateDB, method, args) + // ERC-20 queries + case NameMethod: + bz, err = p.Name(ctx, contract, stateDB, method, args) + case SymbolMethod: + bz, err = p.Symbol(ctx, contract, stateDB, method, args) + case DecimalsMethod: + bz, err = p.Decimals(ctx, contract, stateDB, method, args) + case TotalSupplyMethod: + bz, err = p.TotalSupply(ctx, contract, stateDB, method, args) + case BalanceOfMethod: + bz, err = p.BalanceOf(ctx, contract, stateDB, method, args) + case auth.AllowanceMethod: + bz, err = p.Allowance(ctx, contract, stateDB, method, args) + default: + return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) + } + + return bz, err +} diff --git a/precompiles/erc20/errors.go b/precompiles/erc20/errors.go new file mode 100644 index 00000000..1282505b --- /dev/null +++ b/precompiles/erc20/errors.go @@ -0,0 +1,98 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "errors" + "strings" + + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/os/ibc" + cmn "github.com/evmos/os/precompiles/common" + "github.com/evmos/os/x/evm/core/vm" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// Errors that have formatted information are defined here as a string. +const ( + ErrIntegerOverflow = "amount %s causes integer overflow" + ErrInvalidOwner = "invalid from address: %s" + ErrInvalidReceiver = "invalid to address: %s" + ErrNoAllowanceForToken = "allowance for token %s does not exist" + ErrSubtractMoreThanAllowance = "subtracted value cannot be greater than existing allowance for denom %s: %s > %s" + ErrCannotReceiveFunds = "cannot receive funds, received: %s" +) + +var ( + // errorSignature are the prefix bytes for the hex-encoded reason string. See UnpackRevert in ABI implementation in Geth. + errorSignature = crypto.Keccak256([]byte("Error(string)")) + + // Precompile errors + ErrDecreaseNonPositiveValue = errors.New("cannot decrease allowance with non-positive values") + ErrIncreaseNonPositiveValue = errors.New("cannot increase allowance with non-positive values") + ErrNegativeAmount = errors.New("cannot approve negative values") + ErrSpenderIsOwner = errors.New("spender cannot be the owner") + + // ERC20 errors + ErrDecreasedAllowanceBelowZero = errors.New("ERC20: decreased allowance below zero") + ErrInsufficientAllowance = errors.New("ERC20: insufficient allowance") + ErrTransferAmountExceedsBalance = errors.New("ERC20: transfer amount exceeds balance") +) + +// BuildExecRevertedErr returns a mocked error that should align with the +// behavior of the original ERC20 Solidity implementation. +// +// FIXME: This is not yet producing the correct reason bytes. Will fix on a follow up PR. +func BuildExecRevertedErr(reason string) (error, error) { + // This is reverse-engineering the ABI encoding of the revert reason. + typ, err := abi.NewType("string", "", nil) + if err != nil { + return nil, err + } + + packedReason, err := (abi.Arguments{{Type: typ}}).Pack(reason) + if err != nil { + return nil, errors.New("failed to pack revert reason") + } + + var reasonBytes []byte + reasonBytes = append(reasonBytes, errorSignature...) + reasonBytes = append(reasonBytes, packedReason...) + + return evmtypes.NewExecErrorWithReason(reasonBytes), nil +} + +// ConvertErrToERC20Error is a helper function which maps errors raised by the Cosmos SDK stack +// to the corresponding errors which are raised by an ERC20 contract. +// +// TODO: Create the full RevertError types instead of just the standard error type. +// +// TODO: Return ERC-6093 compliant errors. +func ConvertErrToERC20Error(err error) error { + switch { + case strings.Contains(err.Error(), "spendable balance"): + return ErrTransferAmountExceedsBalance + case strings.Contains(err.Error(), "requested amount is more than spend limit"): + return ErrInsufficientAllowance + case strings.Contains(err.Error(), authz.ErrNoAuthorizationFound.Error()): + return ErrInsufficientAllowance + case strings.Contains(err.Error(), "subtracted value cannot be greater than existing allowance"): + return ErrDecreasedAllowanceBelowZero + case strings.Contains(err.Error(), cmn.ErrIntegerOverflow): + return vm.ErrExecutionReverted + case errors.Is(err, ibc.ErrNoIBCVoucherDenom) || + errors.Is(err, ibc.ErrDenomTraceNotFound) || + strings.Contains(err.Error(), "invalid base denomination") || + strings.Contains(err.Error(), "display denomination not found") || + strings.Contains(err.Error(), "invalid decimals"): + // NOTE: These are the cases when trying to query metadata of a contract, which has no metadata available. + // The ERC20 contract raises an "execution reverted" error, without any further information here, which we + // reproduce (even though it's less verbose than the actual error). + return vm.ErrExecutionReverted + default: + return err + } +} diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go new file mode 100644 index 00000000..7b886bd5 --- /dev/null +++ b/precompiles/erc20/events.go @@ -0,0 +1,96 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/os/x/evm/core/vm" + + auth "github.com/evmos/os/precompiles/authorization" + cmn "github.com/evmos/os/precompiles/common" +) + +const ( + // EventTypeTransfer defines the event type for the ERC-20 Transfer and TransferFrom transactions. + EventTypeTransfer = "Transfer" +) + +// EmitTransferEvent creates a new Transfer event emitted on transfer and transferFrom transactions. +func (p Precompile) EmitTransferEvent(ctx sdk.Context, stateDB vm.StateDB, from, to common.Address, value *big.Int) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeTransfer] + topics := make([]common.Hash, 3) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(from) + if err != nil { + return err + } + + topics[2], err = cmn.MakeTopic(to) + if err != nil { + return err + } + + arguments := abi.Arguments{event.Inputs[2]} + packed, err := arguments.Pack(value) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + +// EmitApprovalEvent creates a new approval event emitted on Approve, IncreaseAllowance +// and DecreaseAllowance transactions. +func (p Precompile) EmitApprovalEvent(ctx sdk.Context, stateDB vm.StateDB, owner, spender common.Address, value *big.Int) error { + // Prepare the event topics + event := p.ABI.Events[auth.EventTypeApproval] + topics := make([]common.Hash, 3) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(owner) + if err != nil { + return err + } + + topics[2], err = cmn.MakeTopic(spender) + if err != nil { + return err + } + + arguments := abi.Arguments{event.Inputs[2]} + packed, err := arguments.Pack(value) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} diff --git a/precompiles/erc20/query.go b/precompiles/erc20/query.go new file mode 100644 index 00000000..f9c269c7 --- /dev/null +++ b/precompiles/erc20/query.go @@ -0,0 +1,249 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "bytes" + "fmt" + "math" + "math/big" + "strings" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/evmos/os/ibc" + auth "github.com/evmos/os/precompiles/authorization" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/x/evm/core/vm" +) + +const ( + // NameMethod defines the ABI method name for the ERC-20 Name + // query. + NameMethod = "name" + // SymbolMethod defines the ABI method name for the ERC-20 Symbol + // query. + SymbolMethod = "symbol" + // DecimalsMethod defines the ABI method name for the ERC-20 Decimals + // query. + DecimalsMethod = "decimals" + // TotalSupplyMethod defines the ABI method name for the ERC-20 TotalSupply + // query. + TotalSupplyMethod = "totalSupply" + // BalanceOfMethod defines the ABI method name for the ERC-20 BalanceOf + // query. + BalanceOfMethod = "balanceOf" +) + +// Name returns the name of the token. If the token metadata is registered in the +// bank module, it returns its name. Otherwise, it returns the base denomination of +// the token capitalized (e.g. uatom -> Atom). +func (p Precompile) Name( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + _ []interface{}, +) ([]byte, error) { + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + if found { + return method.Outputs.Pack(metadata.Name) + } + + baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.tokenPair.Denom) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + name := strings.ToUpper(string(baseDenom[1])) + baseDenom[2:] + return method.Outputs.Pack(name) +} + +// Symbol returns the symbol of the token. If the token metadata is registered in the +// bank module, it returns its symbol. Otherwise, it returns the base denomination of +// the token in uppercase (e.g. uatom -> ATOM). +func (p Precompile) Symbol( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + _ []interface{}, +) ([]byte, error) { + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + if found { + return method.Outputs.Pack(metadata.Symbol) + } + + baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.tokenPair.Denom) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + symbol := strings.ToUpper(baseDenom[1:]) + return method.Outputs.Pack(symbol) +} + +// Decimals returns the decimals places of the token. If the token metadata is registered in the +// bank module, it returns the display denomination exponent. Otherwise, it infers the decimal +// value from the first character of the base denomination (e.g. uatom -> 6). +func (p Precompile) Decimals( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + _ []interface{}, +) ([]byte, error) { + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + if !found { + denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, p.tokenPair.Denom) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + // we assume the decimal from the first character of the denomination + decimals, err := ibc.DeriveDecimalsFromDenom(denomTrace.BaseDenom) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + return method.Outputs.Pack(decimals) + } + + var ( + decimals uint32 + displayFound bool + ) + for i := len(metadata.DenomUnits) - 1; i >= 0; i-- { + if metadata.DenomUnits[i].Denom == metadata.Display { + decimals = metadata.DenomUnits[i].Exponent + displayFound = true + break + } + } + + if !displayFound { + return nil, ConvertErrToERC20Error(fmt.Errorf( + "display denomination not found for denom: %q", + p.tokenPair.Denom, + )) + } + + if decimals > math.MaxUint8 { + return nil, ConvertErrToERC20Error(fmt.Errorf( + "uint8 overflow: invalid decimals: %d", + decimals, + )) + } + + return method.Outputs.Pack(uint8(decimals)) //#nosec G115 // we are checking for overflow above +} + +// TotalSupply returns the amount of tokens in existence. It fetches the supply +// of the coin from the bank keeper and returns zero if not found. +func (p Precompile) TotalSupply( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + _ []interface{}, +) ([]byte, error) { + supply := p.BankKeeper.GetSupply(ctx, p.tokenPair.Denom) + + return method.Outputs.Pack(supply.Amount.BigInt()) +} + +// BalanceOf returns the amount of tokens owned by account. It fetches the balance +// of the coin from the bank keeper and returns zero if not found. +func (p Precompile) BalanceOf( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + account, err := ParseBalanceOfArgs(args) + if err != nil { + return nil, err + } + + balance := p.BankKeeper.GetBalance(ctx, account.Bytes(), p.tokenPair.Denom) + + return method.Outputs.Pack(balance.Amount.BigInt()) +} + +// Allowance returns the remaining allowance of a spender to the contract by +// checking the existence of a bank SendAuthorization. +func (p Precompile) Allowance( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + owner, spender, err := ParseAllowanceArgs(args) + if err != nil { + return nil, err + } + + // NOTE: In case the allowance is queried by the owner, we return the max uint256 value, which + // resembles an infinite allowance. + if bytes.Equal(owner.Bytes(), spender.Bytes()) { + return method.Outputs.Pack(abi.MaxUint256) + } + + _, _, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spender, owner, p.tokenPair.Denom) + if err != nil { + // NOTE: We are not returning the error here, because we want to align the behavior with + // standard ERC20 smart contracts, which return zero if an allowance is not found. + allowance = common.Big0 + } + + return method.Outputs.Pack(allowance) +} + +// GetAuthzExpirationAndAllowance returns the authorization, its expiration as well as the amount of denom +// that the grantee is allowed to spend on behalf of the granter. +func GetAuthzExpirationAndAllowance( + authzKeeper authzkeeper.Keeper, + ctx sdk.Context, + grantee, granter common.Address, + denom string, +) (authz.Authorization, *time.Time, *big.Int, error) { + authorization, expiration, err := auth.CheckAuthzExists(ctx, authzKeeper, grantee, granter, SendMsgURL) + if err != nil { + return nil, nil, common.Big0, err + } + + sendAuth, ok := authorization.(*banktypes.SendAuthorization) + if !ok { + return nil, nil, common.Big0, fmt.Errorf( + "expected authorization to be a %T", banktypes.SendAuthorization{}, + ) + } + + allowance := sendAuth.SpendLimit.AmountOfNoDenomValidation(denom) + return authorization, expiration, allowance.BigInt(), nil +} + +// getBaseDenomFromIBCVoucher returns the base denomination from the given IBC voucher denomination. +func (p Precompile) getBaseDenomFromIBCVoucher(ctx sdk.Context, denom string) (string, error) { + // Infer the denomination name from the coin denomination base denom + denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, denom) + if err != nil { + // FIXME: return 'not supported' (same error as when you call the method on an ERC20.sol) + return "", err + } + + // safety check + if len(denomTrace.BaseDenom) < 3 { + // FIXME: return not supported (same error as when you call the method on an ERC20.sol) + return "", fmt.Errorf("invalid base denomination; should be at least length 3; got: %q", denomTrace.BaseDenom) + } + + return denomTrace.BaseDenom, nil +} diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go new file mode 100644 index 00000000..c94f25d3 --- /dev/null +++ b/precompiles/erc20/tx.go @@ -0,0 +1,144 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "math/big" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + cmn "github.com/evmos/os/precompiles/common" + "github.com/evmos/os/x/evm/core/vm" + evmtypes "github.com/evmos/os/x/evm/types" +) + +const ( + // TransferMethod defines the ABI method name for the ERC-20 transfer + // transaction. + TransferMethod = "transfer" + // TransferFromMethod defines the ABI method name for the ERC-20 transferFrom + // transaction. + TransferFromMethod = "transferFrom" +) + +// SendMsgURL defines the authorization type for MsgSend +var SendMsgURL = sdk.MsgTypeURL(&banktypes.MsgSend{}) + +// Transfer executes a direct transfer from the caller address to the +// destination address. +func (p *Precompile) Transfer( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + from := contract.CallerAddress + to, amount, err := ParseTransferArgs(args) + if err != nil { + return nil, err + } + + return p.transfer(ctx, contract, stateDB, method, from, to, amount) +} + +// TransferFrom executes a transfer on behalf of the specified from address in +// the call data to the destination address. +func (p *Precompile) TransferFrom( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + from, to, amount, err := ParseTransferFromArgs(args) + if err != nil { + return nil, err + } + + return p.transfer(ctx, contract, stateDB, method, from, to, amount) +} + +// transfer is a common function that handles transfers for the ERC-20 Transfer +// and TransferFrom methods. It executes a bank Send message if the spender is +// the sender of the transfer, otherwise it executes an authorization. +func (p *Precompile) transfer( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + from, to common.Address, + amount *big.Int, +) (data []byte, err error) { + coins := sdk.Coins{{Denom: p.tokenPair.Denom, Amount: math.NewIntFromBigInt(amount)}} + + msg := banktypes.NewMsgSend(from.Bytes(), to.Bytes(), coins) + + if err = msg.Amount.Validate(); err != nil { + return nil, err + } + + isTransferFrom := method.Name == TransferFromMethod + owner := sdk.AccAddress(from.Bytes()) + spenderAddr := contract.CallerAddress + spender := sdk.AccAddress(spenderAddr.Bytes()) // aka. grantee + ownerIsSpender := spender.Equals(owner) + + var prevAllowance *big.Int + if ownerIsSpender { + msgSrv := bankkeeper.NewMsgServerImpl(p.BankKeeper) + _, err = msgSrv.Send(ctx, msg) + } else { + _, _, prevAllowance, err = GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spenderAddr, from, p.tokenPair.Denom) + if err != nil { + return nil, ConvertErrToERC20Error(errorsmod.Wrap(err, authz.ErrNoAuthorizationFound.Error())) + } + + _, err = p.AuthzKeeper.DispatchActions(ctx, spender, []sdk.Msg{msg}) + } + + if err != nil { + err = ConvertErrToERC20Error(err) + // This should return an error to avoid the contract from being executed and an event being emitted + return nil, err + } + + evmDenom := evmtypes.GetEVMCoinDenom() + if p.tokenPair.Denom == evmDenom { + convertedAmount := evmtypes.ConvertAmountTo18DecimalsBigInt(amount) + p.SetBalanceChangeEntries(cmn.NewBalanceChangeEntry(from, convertedAmount, cmn.Sub), + cmn.NewBalanceChangeEntry(to, convertedAmount, cmn.Add)) + } + + if err = p.EmitTransferEvent(ctx, stateDB, from, to, amount); err != nil { + return nil, err + } + + // NOTE: if it's a direct transfer, we return here but if used through transferFrom, + // we need to emit the approval event with the new allowance. + if !isTransferFrom { + return method.Outputs.Pack(true) + } + + var newAllowance *big.Int + if ownerIsSpender { + // NOTE: in case the spender is the owner we emit an approval event with + // the maxUint256 value. + newAllowance = abi.MaxUint256 + } else { + newAllowance = new(big.Int).Sub(prevAllowance, amount) + } + + if err = p.EmitApprovalEvent(ctx, stateDB, from, spenderAddr, newAllowance); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go new file mode 100644 index 00000000..399a7e31 --- /dev/null +++ b/precompiles/erc20/types.go @@ -0,0 +1,152 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" +) + +// EventTransfer defines the event data for the ERC20 Transfer events. +type EventTransfer struct { + From common.Address + To common.Address + Value *big.Int +} + +// EventApproval defines the event data for the ERC20 Approval events. +type EventApproval struct { + Owner common.Address + Spender common.Address + Value *big.Int +} + +// ParseTransferArgs parses the arguments from the transfer method and returns +// the destination address (to) and amount. +func ParseTransferArgs(args []interface{}) ( + to common.Address, amount *big.Int, err error, +) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + to, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid to address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return to, amount, nil +} + +// ParseTransferFromArgs parses the arguments from the transferFrom method and returns +// the sender address (from), destination address (to) and amount. +func ParseTransferFromArgs(args []interface{}) ( + from, to common.Address, amount *big.Int, err error, +) { + if len(args) != 3 { + return common.Address{}, common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 3; got: %d", len(args)) + } + + from, ok := args[0].(common.Address) + if !ok { + return common.Address{}, common.Address{}, nil, fmt.Errorf("invalid from address: %v", args[0]) + } + + to, ok = args[1].(common.Address) + if !ok { + return common.Address{}, common.Address{}, nil, fmt.Errorf("invalid to address: %v", args[1]) + } + + amount, ok = args[2].(*big.Int) + if !ok { + return common.Address{}, common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[2]) + } + + return from, to, amount, nil +} + +// ParseApproveArgs parses the approval arguments and returns the spender address +// and amount. +func ParseApproveArgs(args []interface{}) ( + spender common.Address, amount *big.Int, err error, +) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + spender, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid spender address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return spender, amount, nil +} + +// ParseAllowanceArgs parses the allowance arguments and returns the owner and +// the spender addresses. +func ParseAllowanceArgs(args []interface{}) ( + owner, spender common.Address, err error, +) { + if len(args) != 2 { + return common.Address{}, common.Address{}, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + owner, ok := args[0].(common.Address) + if !ok { + return common.Address{}, common.Address{}, fmt.Errorf("invalid owner address: %v", args[0]) + } + + spender, ok = args[1].(common.Address) + if !ok { + return common.Address{}, common.Address{}, fmt.Errorf("invalid spender address: %v", args[1]) + } + + return owner, spender, nil +} + +// ParseBalanceOfArgs parses the balanceOf arguments and returns the account address. +func ParseBalanceOfArgs(args []interface{}) (common.Address, error) { + if len(args) != 1 { + return common.Address{}, fmt.Errorf("invalid number of arguments; expected 1; got: %d", len(args)) + } + + account, ok := args[0].(common.Address) + if !ok { + return common.Address{}, fmt.Errorf("invalid account address: %v", args[0]) + } + + return account, nil +} + +// updateOrAddCoin replaces the coin of the given denomination in the coins slice or adds it if it +// does not exist yet. +// +// CONTRACT: Requires the coins struct to contain at most one coin of the given +// denom. +func updateOrAddCoin(coins sdk.Coins, coin sdk.Coin) sdk.Coins { + for idx, c := range coins { + if c.Denom == coin.Denom { + coins[idx] = coin + return coins + } + } + + // NOTE: if no coin with the correct denomination is in the coins slice, we + // add it here. + return coins.Add(coin) +} From b09b1bf95257f9c2967dcbb5a8df0e34adf6f027 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 20 Jan 2025 20:33:46 +0700 Subject: [PATCH 19/53] build --- x/asset/exported/exported.go | 18 ++++ x/asset/genesis.go | 45 ++++++++ x/asset/module.go | 187 +++++++++++++++++++++++++++++++++ x/asset/types/codec.go | 27 +++++ x/asset/types/genesis.go | 21 ++++ x/asset/types/params_legacy.go | 17 +++ 6 files changed, 315 insertions(+) create mode 100644 x/asset/exported/exported.go create mode 100644 x/asset/genesis.go create mode 100644 x/asset/module.go create mode 100644 x/asset/types/codec.go create mode 100644 x/asset/types/genesis.go create mode 100644 x/asset/types/params_legacy.go diff --git a/x/asset/exported/exported.go b/x/asset/exported/exported.go new file mode 100644 index 00000000..2eb9e7dd --- /dev/null +++ b/x/asset/exported/exported.go @@ -0,0 +1,18 @@ +package exported + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +type ( + ParamSet = paramtypes.ParamSet + + // Subspace defines an interface that implements the legacy x/params Subspace + // type. + // + // NOTE: This is used solely for migration of x/params managed parameters. + Subspace interface { + GetParamSet(ctx sdk.Context, ps ParamSet) + } +) \ No newline at end of file diff --git a/x/asset/genesis.go b/x/asset/genesis.go new file mode 100644 index 00000000..c88c4e3b --- /dev/null +++ b/x/asset/genesis.go @@ -0,0 +1,45 @@ +package asset + +import ( + "context" + + "github.com/realiotech/realio-network/x/asset/keeper" + "github.com/realiotech/realio-network/x/asset/types" +) + +// InitGenesis initializes the assets module's state from a provided genesis +// state. +func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisState) { + err := k.Params.Set(ctx, genState.Params) + if err != nil { + panic(err) + } + for _, token := range genState.Tokens { + err := k.Token.Set(ctx, token.Symbol, token) + if err != nil { + panic(err) + } + } +} + +// ExportGenesis returns the capability module's exported genesis. +func ExportGenesis(ctx context.Context, k keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + params, err := k.Params.Get(ctx) + if err != nil { + panic(err) + } + genesis.Params = params + tokens := []types.Token{} + err = k.Token.Walk(ctx, nil, func(_ string, token types.Token) (stop bool, err error) { + tokens = append(tokens, token) + return false, nil + }) + if err != nil { + panic(err) + } + genesis.Tokens = tokens + // this line is used by starport scaffolding # genesis/module/export + + return genesis +} \ No newline at end of file diff --git a/x/asset/module.go b/x/asset/module.go new file mode 100644 index 00000000..8f72efab --- /dev/null +++ b/x/asset/module.go @@ -0,0 +1,187 @@ +package asset + +import ( + "context" + "encoding/json" + + // this line is used by starport scaffolding # 1 + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + + "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/realiotech/realio-network/x/asset/exported" + "github.com/realiotech/realio-network/x/asset/keeper" + "github.com/realiotech/realio-network/x/asset/types" +) + +var ( + _ module.AppModuleBasic = AppModule{} + _ module.AppModuleSimulation = AppModule{} + // _ module.HasGenesis = AppModule{} + // _ module.HasServices = AppModule{} + + _ appmodule.AppModule = AppModule{} +) + +// ConsensusVersion defines the current x/asset module consensus version. +const ConsensusVersion = 2 + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +var _ module.AppModuleBasic = AppModuleBasic{} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +// func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { +// return cdc.MustMarshalJSON(types.DefaultGenesis()) +// } + +// ValidateGenesis performs genesis state validation for the capability module. +// func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { +// var genState types.GenesisState +// if err := cdc.UnmarshalJSON(bz, &genState); err != nil { +// return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) +// } +// return genState.Validate() +// } + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// GetTxCmd returns the capability module's root tx command. +// func (a AppModuleBasic) GetTxCmd() *cobra.Command { +// return cli.GetTxCmd() +// } + +// GetQueryCmd returns the capability module's root query command. +// func (AppModuleBasic) GetQueryCmd() *cobra.Command { +// return cli.GetQueryCmd() +// } + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + // legacySubspace is used solely for migration of x/params managed parameters + legacySubspace exported.Subspace + + keeper keeper.Keeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, + bankKeeper types.BankKeeper, + ss exported.Subspace, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + bankKeeper: bankKeeper, + legacySubspace: ss, + } +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (AppModule) IsAppModule() {} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// 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(), keeper.NewQueryServerImpl(am.keeper)) + +// m := keeper.NewMigrator(am.keeper, am.legacySubspace) + +// if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { +// panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", types.ModuleName, err)) +// } +// } + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion } + +func (am AppModule) GenerateGenesisState(_ *module.SimulationState) { +} + +func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{} +} + +func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) { +} + +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return []simtypes.WeightedOperation{} +} diff --git a/x/asset/types/codec.go b/x/asset/types/codec.go new file mode 100644 index 00000000..c4c0b559 --- /dev/null +++ b/x/asset/types/codec.go @@ -0,0 +1,27 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreateToken{}, "asset/CreateToken", nil) + // this line is used by starport scaffolding # 2 +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgCreateToken{}, + ) + // this line is used by starport scaffolding # 3 + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) \ No newline at end of file diff --git a/x/asset/types/genesis.go b/x/asset/types/genesis.go new file mode 100644 index 00000000..4492f761 --- /dev/null +++ b/x/asset/types/genesis.go @@ -0,0 +1,21 @@ +package types + +// DefaultIndex is the default capability global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + // this line is used by starport scaffolding # genesis/types/default + Params: DefaultParams(), + Tokens: []Token{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // this line is used by starport scaffolding # genesis/types/validate + + return gs.Params.Validate() +} \ No newline at end of file diff --git a/x/asset/types/params_legacy.go b/x/asset/types/params_legacy.go new file mode 100644 index 00000000..e20dde92 --- /dev/null +++ b/x/asset/types/params_legacy.go @@ -0,0 +1,17 @@ +package types + +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{} +} \ No newline at end of file From e0cb51a8e4587faaf0540aead0ed607faca37e77 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 20 Jan 2025 20:34:03 +0700 Subject: [PATCH 20/53] bump evm/os --- go.mod | 59 ++++++++++++++---------- go.sum | 139 +++++++++++++++++++++++++++++++++------------------------ 2 files changed, 115 insertions(+), 83 deletions(-) diff --git a/go.mod b/go.mod index 8a580324..693a2d38 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,14 @@ module github.com/realiotech/realio-network -go 1.22.5 +go 1.22.8 require ( cosmossdk.io/api v0.7.6 - cosmossdk.io/client/v2 v2.0.0-beta.4 + cosmossdk.io/client/v2 v2.0.0-beta.5 cosmossdk.io/collections v0.4.0 cosmossdk.io/core v0.11.1 cosmossdk.io/errors v1.0.1 - cosmossdk.io/log v1.4.1 + cosmossdk.io/log v1.5.0 cosmossdk.io/math v1.4.0 cosmossdk.io/simapp v0.0.0-20240805084742-3fc80745eef2 cosmossdk.io/store v1.1.1 @@ -17,13 +17,13 @@ require ( cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/tx v0.13.7 cosmossdk.io/x/upgrade v0.1.4 - github.com/cometbft/cometbft v0.38.12 + github.com/cometbft/cometbft v0.38.15 github.com/cosmos/cosmos-db v1.1.0 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.11 github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v8 v8.5.1 + github.com/cosmos/ibc-go/v8 v8.5.2 github.com/cosmos/rosetta v0.50.10 github.com/ethereum/go-ethereum v1.11.5 github.com/evmos/os v0.0.0-20241002122822-02a9121016ee @@ -35,11 +35,11 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 - github.com/stretchr/testify v1.9.0 - golang.org/x/sync v0.8.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 - google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.35.1 + github.com/stretchr/testify v1.10.0 + golang.org/x/sync v0.9.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,9 +72,13 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect + github.com/bytedance/sonic v1.12.3 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect @@ -83,7 +87,7 @@ require ( github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect - github.com/cometbft/cometbft-db v0.12.0 // indirect + github.com/cometbft/cometbft-db v0.14.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -161,16 +165,17 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.7 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.9.2 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -180,12 +185,12 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/petermattis/goid v0.0.0-20240607163614-bb94eb51e7a7 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.1 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.60.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/tsdb v0.10.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect @@ -196,7 +201,7 @@ require ( github.com/rs/zerolog v1.33.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect @@ -204,12 +209,13 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect - github.com/tidwall/gjson v1.17.3 // indirect + github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/hid v0.9.2 // indirect @@ -222,13 +228,14 @@ require ( go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.27.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.186.0 // indirect google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect @@ -247,6 +254,8 @@ replace ( cosmossdk.io/store => github.com/evmos/cosmos-sdk/store v0.0.0-20240718141609-414cbd051fbe // use Evmos geth fork github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc4 + + github.com/evmos/os => github.com/evmos/os v0.0.0-20250108125741-e95afb000453 // use Realio sdk v0.46.11-realio-4 // github.com/cosmos/cosmos-sdk => github.com/realiotech/cosmos-sdk v0.46.11-realio-4 github.com/evmos/os/example_chain => github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee @@ -261,4 +270,6 @@ replace ( // replace broken goleveldb github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + +// github.com/realiotech/realio-network/x/asset => ../realio-network-decentrio/x/asset ) diff --git a/go.sum b/go.sum index 34f67412..1cb84b49 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.6 h1:PC20PcXy1xYKH2KU4RMurVoFjjKkCgYRbVAD4PdqUuY= cosmossdk.io/api v0.7.6/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= -cosmossdk.io/client/v2 v2.0.0-beta.4 h1:LGIzWbVTOof/IHQZeoWwxPX0fq607ONXhsfA7eUrQIg= -cosmossdk.io/client/v2 v2.0.0-beta.4/go.mod h1:c753d0sBv3AQRx6X+BOKL1aGpKjZMTZAHGiLPbVi5TE= +cosmossdk.io/client/v2 v2.0.0-beta.5 h1:0LVv3nEByn//hFDIrYLs2WvsEU3HodOelh4SDHnA/1I= +cosmossdk.io/client/v2 v2.0.0-beta.5/go.mod h1:4p0P6o0ro+FizakJUYS9SeM94RNbv0thLmkHRw5o5as= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= cosmossdk.io/core v0.11.1 h1:h9WfBey7NAiFfIcUhDVNS503I2P2HdZLebJlUIs8LPA= @@ -198,8 +198,8 @@ cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E= cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= -cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= -cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= +cosmossdk.io/log v1.5.0 h1:dVdzPJW9kMrnAYyMf1duqacoidB9uZIl+7c6z0mnq0g= +cosmossdk.io/log v1.5.0/go.mod h1:Tr46PUJjiUthlwQ+hxYtUtPn4D/oCZXAkYevBeh5+FI= cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= cosmossdk.io/simapp v0.0.0-20240805084742-3fc80745eef2 h1:f2zS+kpAqxGEbY1xHUK7ytfKeCVkmu89FMYGAK+FbYA= @@ -252,8 +252,8 @@ github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= +github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -317,6 +317,11 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE= +github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= +github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -344,6 +349,10 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -373,10 +382,10 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg= -github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o= -github.com/cometbft/cometbft-db v0.12.0 h1:v77/z0VyfSU7k682IzZeZPFZrQAKiQwkqGN0QzAjMi0= -github.com/cometbft/cometbft-db v0.12.0/go.mod h1:aX2NbCrjNVd2ZajYxt1BsiFf/Z+TQ2MN0VxdicheYuw= +github.com/cometbft/cometbft v0.38.15 h1:5veFd8k1uXM27PBg9sMO3hAfRJ3vbh4OmmLf6cVrqXg= +github.com/cometbft/cometbft v0.38.15/go.mod h1:+wh6ap6xctVG+JOHwbl8pPKZ0GeqdPYqISu7F4b43cQ= +github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= +github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -402,8 +411,8 @@ github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v8 v8.5.1 h1:3JleEMKBjRKa3FeTKt4fjg22za/qygLBo7mDkoYTNBs= -github.com/cosmos/ibc-go/v8 v8.5.1/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= +github.com/cosmos/ibc-go/v8 v8.5.2 h1:27s9oeD2AxLQF3e9BQsYt9doONyZ7FwZi/qkBv6Sdks= +github.com/cosmos/ibc-go/v8 v8.5.2/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -492,8 +501,8 @@ github.com/evmos/cosmos-sdk/store v0.0.0-20240718141609-414cbd051fbe h1:CKvjP3Cc github.com/evmos/cosmos-sdk/store v0.0.0-20240718141609-414cbd051fbe/go.mod h1:Bm6h8ZkYgVTytHK5vhHOMKw9OHyiumm3b1UbkYIJ/Ug= github.com/evmos/go-ethereum v1.10.26-evmos-rc4 h1:vwDVMScuB2KSu8ze5oWUuxm6v3bMUp6dL3PWvJNJY+I= github.com/evmos/go-ethereum v1.10.26-evmos-rc4/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= -github.com/evmos/os v0.0.0-20241002122822-02a9121016ee h1:lPqHHT7ezQbrF7NLK2tCCjD8NQ31TeNXW7l4nNFWslI= -github.com/evmos/os v0.0.0-20241002122822-02a9121016ee/go.mod h1:uQQyppk8z2C7Ypk/zj8/wnJSrf74rY8cXLzsD8F1tEE= +github.com/evmos/os v0.0.0-20250108125741-e95afb000453 h1:ZwRIMj0RPxk37fXeHh6wRJr3S7tj5fxWG5Jf3ZyMCus= +github.com/evmos/os v0.0.0-20250108125741-e95afb000453/go.mod h1:BFkZxXO384jHZ++ETF7Vmh82MGNQ2wzzQV7LOA9cJJs= github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee h1:BZpePPAM2zYn8P9EkU14K0p4TTgwEQJLaQG4FjNh99Q= github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee/go.mod h1:+SPMqw9wtbWO3jG02uLbLtVVjMHBldmXTN51kxbWqJ8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -665,8 +674,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= -github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -826,6 +835,10 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -841,8 +854,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.9.2 h1:O3mzvO0wuzQ9mtlHbDrShixyVjVbmuqTjFrzlf43wZ8= @@ -872,8 +885,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -928,14 +941,14 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= -github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= -github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -961,9 +974,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/petermattis/goid v0.0.0-20240607163614-bb94eb51e7a7 h1:CtBLeckhC0zAXgp5V8uR30CNYH0JgCJoxCg5+6i2zQk= -github.com/petermattis/goid v0.0.0-20240607163614-bb94eb51e7a7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -984,8 +996,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= -github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1000,8 +1012,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1045,8 +1057,8 @@ github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= @@ -1098,8 +1110,9 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -1109,8 +1122,8 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= -github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -1123,6 +1136,8 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -1181,6 +1196,8 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -1190,6 +1207,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1201,8 +1220,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1302,8 +1321,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1329,8 +1348,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1345,8 +1364,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1356,7 +1375,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1443,15 +1461,17 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1462,8 +1482,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1530,8 +1550,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1710,8 +1730,8 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1755,8 +1775,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1773,8 +1793,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1822,6 +1842,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 18908da5716ca89bb95b4c3ca27b1c7b5c2fa13a Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 20 Jan 2025 20:35:10 +0700 Subject: [PATCH 21/53] port x/asset into erc20 keeper & precompile --- app/app.go | 8 ++------ app/mock_erc20.go | 41 +++++++++++++++++++++++++++++++++++--- precompiles/erc20/erc20.go | 10 +++++++--- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/app/app.go b/app/app.go index 2199b18f..5f29b03f 100644 --- a/app/app.go +++ b/app/app.go @@ -474,7 +474,7 @@ func New( app.EvmKeeper = evmkeeper.NewKeeper( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], authtypes.NewModuleAddress(govtypes.ModuleName), - app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper, MockErc20Keeper{}, + app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper, NewEmptyMockErc20Keeper(), tracer, app.GetSubspace(evmtypes.ModuleName), ) @@ -490,7 +490,6 @@ func New( runtime.NewKVStoreService(keys[assetmoduletypes.StoreKey]), app.BankKeeper, app.AccountKeeper, - app.ModuleAccountAddrs(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) @@ -502,9 +501,6 @@ func New( authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - // Add transfer restriction - app.BankKeeper.AppendSendRestriction(app.AssetKeeper.AssetSendRestriction) - // IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), @@ -801,7 +797,7 @@ func New( FeeMarketKeeper: app.FeeMarketKeeper, MaxTxGasWanted: maxGasWanted, ExtensionOptionChecker: ostypes.HasDynamicFeeExtensionOption, - TxFeeChecker: evmosanteevm.NewDynamicFeeChecker(app.EvmKeeper), + TxFeeChecker: evmosanteevm.NewDynamicFeeChecker(app.FeeMarketKeeper), } if err := options.Validate(); err != nil { diff --git a/app/mock_erc20.go b/app/mock_erc20.go index fdc903e9..f07a773c 100644 --- a/app/mock_erc20.go +++ b/app/mock_erc20.go @@ -2,12 +2,47 @@ package app import ( sdk "github.com/cosmos/cosmos-sdk/types" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/ethereum/go-ethereum/common" "github.com/evmos/os/x/evm/core/vm" + transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" + "github.com/realiotech/realio-network/precompiles/erc20" + assetkeeper "github.com/realiotech/realio-network/x/asset/keeper" ) -type MockErc20Keeper struct{} +type MockErc20Keeper struct { + ContractAddrs []string -func (k MockErc20Keeper) GetERC20PrecompileInstance(_ sdk.Context, _ common.Address) (contract vm.PrecompiledContract, found bool, err error) { - return nil, false, nil + bankKeeper bankkeeper.Keeper + authzKeeper authzkeeper.Keeper + transferKeeper *transferkeeper.Keeper + assetKeeper assetkeeper.Keeper +} + +func NewMockErc20KeeperWithAddrs(addrs []string) MockErc20Keeper { + return MockErc20Keeper{ContractAddrs: addrs} +} + +func NewEmptyMockErc20Keeper() MockErc20Keeper { + return MockErc20Keeper{} +} + +func (k MockErc20Keeper) GetERC20PrecompileInstance(ctx sdk.Context, addr common.Address) (contract vm.PrecompiledContract, found bool, err error) { + // Check if contract address in list + exist, err := k.assetKeeper.EVMContractExist(ctx, addr) + if err != nil || !exist { + return nil, false, nil + } + + precompile, err := erc20.NewPrecompile(addr, k.bankKeeper, k.authzKeeper, *k.transferKeeper, k.assetKeeper) + if err != nil { + return nil, false, nil + } + + return precompile, true, nil +} + +func (k MockErc20Keeper) AddContractAddress(_ sdk.Context, addr common.Address) { + k.ContractAddrs = append(k.ContractAddrs, addr.String()) } diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index a504c45f..9e463210 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -12,11 +12,13 @@ import ( authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" auth "github.com/evmos/os/precompiles/authorization" cmn "github.com/evmos/os/precompiles/common" erc20types "github.com/evmos/os/x/erc20/types" "github.com/evmos/os/x/evm/core/vm" transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" + assetkeeper "github.com/realiotech/realio-network/x/asset/keeper" ) const ( @@ -49,15 +51,17 @@ type Precompile struct { transferKeeper transferkeeper.Keeper // BankKeeper is a public field so that the werc20 precompile can use it. BankKeeper bankkeeper.Keeper + assetKeep assetkeeper.Keeper } // NewPrecompile creates a new ERC-20 Precompile instance as a // PrecompiledContract interface. func NewPrecompile( - tokenPair erc20types.TokenPair, + address common.Address, bankKeeper bankkeeper.Keeper, authzKeeper authzkeeper.Keeper, transferKeeper transferkeeper.Keeper, + assetKeeper assetkeeper.Keeper, ) (*Precompile, error) { newABI, err := cmn.LoadABI(f, abiPath) if err != nil { @@ -72,12 +76,12 @@ func NewPrecompile( KvGasConfig: storetypes.GasConfig{}, TransientKVGasConfig: storetypes.GasConfig{}, }, - tokenPair: tokenPair, BankKeeper: bankKeeper, transferKeeper: transferKeeper, + assetKeep: assetKeeper, } // Address defines the address of the ERC-20 precompile contract. - p.SetAddress(p.tokenPair.GetERC20Contract()) + p.SetAddress(address) return p, nil } From 14fe5769fcd9f7f3ddaa1d16ff887160704eea69 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 20 Jan 2025 20:35:33 +0700 Subject: [PATCH 22/53] get erc20 precompule func --- x/asset/keeper/keeper.go | 18 ++++++++++++++++++ x/asset/keeper/msg_server.go | 6 ++++-- x/asset/types/token.go | 3 ++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index b8320295..b47633ba 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" "github.com/realiotech/realio-network/x/asset/types" ) @@ -77,3 +78,20 @@ func (k Keeper) GetWhitelistAddress(ctx context.Context, address string) bool { return found } + +func (k Keeper) EVMContractExist(ctx context.Context, address common.Address) (bool, error) { + exist := false + err := k.Token.Walk(ctx, nil, func(key string, token types.Token) (stop bool, err error) { + if token.EvmAddress == address.String() { + exist = true + return true, nil + } + return false, nil + }) + + if err != nil { + return false, err + } + + return exist, nil +} diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index c51de54f..8a68d510 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -13,6 +13,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/realiotech/realio-network/x/asset/types" + "github.com/ethereum/go-ethereum/common" ) type msgServer struct { @@ -48,9 +49,10 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "token with id %s already exists", tokenId) } - // TODO: create evm precompile here + // Create a evm addr from tokenId + evmAddr := common.BytesToAddress([]byte(tokenId)) - token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer) + token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer, evmAddr.Hex()) err := ms.Token.Set(ctx, tokenId, token) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenSet, err.Error()) diff --git a/x/asset/types/token.go b/x/asset/types/token.go index 88e7a608..ed9b4e4a 100644 --- a/x/asset/types/token.go +++ b/x/asset/types/token.go @@ -9,7 +9,7 @@ import ( ) // NewToken creates a new Token instance -func NewToken(id, name string, decimal uint32, description string, symbol string, issuer string) Token { +func NewToken(id, name string, decimal uint32, description string, symbol string, issuer string, evmAddress string) Token { return Token{ TokenId: id, Name: name, @@ -17,6 +17,7 @@ func NewToken(id, name string, decimal uint32, description string, symbol string Description: description, Symbol: symbol, Issuer: issuer, + EvmAddress: evmAddress, } } From eeee227f3d76976c5302cacc553301fa2d05dce3 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Tue, 21 Jan 2025 15:13:16 +0700 Subject: [PATCH 23/53] no more token distributor --- proto/realionetwork/asset/v1/token.proto | 14 +- x/asset/keeper/keeper.go | 36 +++- x/asset/keeper/msg_server.go | 36 +--- x/asset/types/token.go | 10 +- x/asset/types/token.pb.go | 238 ++++++++++++++--------- 5 files changed, 185 insertions(+), 149 deletions(-) diff --git a/proto/realionetwork/asset/v1/token.proto b/proto/realionetwork/asset/v1/token.proto index 45b2f5ec..0e789be8 100644 --- a/proto/realionetwork/asset/v1/token.proto +++ b/proto/realionetwork/asset/v1/token.proto @@ -21,15 +21,15 @@ message TokenManagement { repeated string managers = 1; bool allow_new_extensions = 2; repeated string extensions_list = 3; -} - -// TokenDistribution represents the asset manager's execute functions. -message TokenDistribution { - repeated string distributors = 1; - string max_supply = 2 [ + string max_supply = 4 [ (gogoproto.customtype) = "cosmossdk.io/math.Int", (gogoproto.nullable) = false - ]; + ]; +} + +message ShareAddress { + string evm_address = 1; + string sdk_address = 2; } enum Role { diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index b47633ba..472798e0 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "context" "fmt" @@ -29,7 +30,6 @@ type Keeper struct { Params collections.Item[types.Params] Token collections.Map[string, types.Token] TokenManagement collections.Map[string, types.TokenManagement] - TokenDistribution collections.Map[string, types.TokenDistribution] WhitelistAddresses collections.Map[string, bool] } @@ -53,7 +53,6 @@ func NewKeeper( Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), Token: collections.NewMap(sb, types.TokenKey, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), TokenManagement: collections.NewMap(sb, types.TokenManagementKey, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), - TokenDistribution: collections.NewMap(sb, types.TokenDistributionKey, "token_distribution", collections.StringKey, codec.CollValue[types.TokenDistribution](cdc)), WhitelistAddresses: collections.NewMap(sb, types.WhitelistAddressesKey, "whitelist_addresses", collections.StringKey, collections.BoolValue), } @@ -79,19 +78,48 @@ func (k Keeper) GetWhitelistAddress(ctx context.Context, address string) bool { return found } -func (k Keeper) EVMContractExist(ctx context.Context, address common.Address) (bool, error) { +func (k Keeper) EVMContractExist(ctx context.Context, address common.Address) (bool, string, error) { exist := false + tokenId := "" err := k.Token.Walk(ctx, nil, func(key string, token types.Token) (stop bool, err error) { if token.EvmAddress == address.String() { exist = true + tokenId = key return true, nil } return false, nil }) if err != nil { - return false, err + return false, "", err } + return exist, tokenId, nil +} + +func (k Keeper) GetParams(ctx context.Context) (types.Params, error) { + return k.Params.Get(ctx) +} + +func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr common.Address) (bool, error) { + exist := false + tm, err := k.TokenManagement.Get(ctx, tokenId) + if err != nil { + return false, nil + } + for _, manager := range tm.Managers { + if bytes.Equal(addr.Bytes(), sdk.MustAccAddressFromBech32(manager).Bytes()) { + exist = true + break + } + } return exist, nil } + +func (k Keeper) GetToken(ctx context.Context, tokenId string) (types.Token, error) { + return k.Token.Get(ctx, tokenId) +} + +func (k Keeper) GetTokenManager(ctx context.Context, tokenId string) (types.TokenManagement, error) { + return k.TokenManagement.Get(ctx, tokenId) +} diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index 8a68d510..b7227a3c 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -52,24 +52,18 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) // Create a evm addr from tokenId evmAddr := common.BytesToAddress([]byte(tokenId)) - token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer, evmAddr.Hex()) + token := types.NewToken(tokenId, msg.Name, msg.Decimal, msg.Description, msg.Symbol, msg.Issuer, evmAddr.String()) err := ms.Token.Set(ctx, tokenId, token) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenSet, err.Error()) } - tokenManagement := types.NewTokenManagement(msg.Managers, msg.AllowNewExtensions, msg.ExtensionsList) + tokenManagement := types.NewTokenManagement(msg.Managers, msg.AllowNewExtensions, msg.ExtensionsList, msg.MaxSupply) err = ms.TokenManagement.Set(ctx, tokenId, tokenManagement) if err != nil { return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) } - tokenDistribution := types.NewTokenDistribution(msg.Distributors, msg.MaxSupply) - err = ms.TokenDistribution.Set(ctx, tokenId, tokenDistribution) - if err != nil { - return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) - } - ms.bk.SetDenomMetaData(ctx, banktypes.Metadata{ Base: tokenId, Symbol: lowerCaseSymbol, Name: lowerCaseName, DenomUnits: []*banktypes.DenomUnit{{Denom: lowerCaseSymbol, Exponent: msg.Decimal}, {Denom: tokenId, Exponent: 0}}, @@ -117,19 +111,6 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) } - tokenDistribution, err := ms.TokenDistribution.Get(ctx, msg.TokenId) - if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenDistributionGet, err.Error()) - } - newDistributors := append(tokenDistribution.Distributors, msg.Distributors...) - slices.Sort(newDistributors) - tokenDistribution.Distributors = slices.Compact(newDistributors) - - err = ms.TokenDistribution.Set(ctx, msg.TokenId, tokenDistribution) - if err != nil { - return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) - } - sdkCtx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeTokenAuthorizeUpdated, @@ -169,19 +150,6 @@ func (ms msgServer) UnassignRoles(ctx context.Context, msg *types.MsgUnassignRol return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) } - tokenDistribution, err := ms.TokenDistribution.Get(ctx, msg.TokenId) - if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenDistributionGet, err.Error()) - } - - tokenDistribution.Distributors = slices.DeleteFunc(tokenDistribution.Distributors, func(distributor string) bool { - return slices.Contains(msg.Distributors, distributor) - }) - err = ms.TokenDistribution.Set(ctx, msg.TokenId, tokenDistribution) - if err != nil { - return nil, errorsmod.Wrap(types.ErrTokenDistributionSet, err.Error()) - } - sdkCtx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeTokenAuthorizeUpdated, diff --git a/x/asset/types/token.go b/x/asset/types/token.go index ed9b4e4a..660caf5f 100644 --- a/x/asset/types/token.go +++ b/x/asset/types/token.go @@ -21,18 +21,12 @@ func NewToken(id, name string, decimal uint32, description string, symbol string } } -func NewTokenManagement(managers []string, allowNewExtension bool, extensionList []string) TokenManagement { +func NewTokenManagement(managers []string, allowNewExtension bool, extensionList []string, maxSupply math.Int) TokenManagement { return TokenManagement{ Managers: managers, AllowNewExtensions: allowNewExtension, ExtensionsList: extensionList, - } -} - -func NewTokenDistribution(distributors []string, maxSupply math.Int) TokenDistribution { - return TokenDistribution{ - Distributors: distributors, - MaxSupply: maxSupply, + MaxSupply: maxSupply, } } diff --git a/x/asset/types/token.pb.go b/x/asset/types/token.pb.go index 56b0ddd8..4dd52904 100644 --- a/x/asset/types/token.pb.go +++ b/x/asset/types/token.pb.go @@ -150,9 +150,10 @@ func (m *Token) GetEvmAddress() string { // TokenManagement represents the asset manager's execute functions. type TokenManagement struct { - Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` - AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` - ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` + Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` + AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` + ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` + MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` } func (m *TokenManagement) Reset() { *m = TokenManagement{} } @@ -209,24 +210,23 @@ func (m *TokenManagement) GetExtensionsList() []string { return nil } -// TokenDistribution represents the asset manager's execute functions. -type TokenDistribution struct { - Distributors []string `protobuf:"bytes,1,rep,name=distributors,proto3" json:"distributors,omitempty"` - MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` +type ShareAddress struct { + EvmAddress string `protobuf:"bytes,1,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` + SdkAddress string `protobuf:"bytes,2,opt,name=sdk_address,json=sdkAddress,proto3" json:"sdk_address,omitempty"` } -func (m *TokenDistribution) Reset() { *m = TokenDistribution{} } -func (m *TokenDistribution) String() string { return proto.CompactTextString(m) } -func (*TokenDistribution) ProtoMessage() {} -func (*TokenDistribution) Descriptor() ([]byte, []int) { +func (m *ShareAddress) Reset() { *m = ShareAddress{} } +func (m *ShareAddress) String() string { return proto.CompactTextString(m) } +func (*ShareAddress) ProtoMessage() {} +func (*ShareAddress) Descriptor() ([]byte, []int) { return fileDescriptor_2f83138fc60a3176, []int{2} } -func (m *TokenDistribution) XXX_Unmarshal(b []byte) error { +func (m *ShareAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *TokenDistribution) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ShareAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_TokenDistribution.Marshal(b, m, deterministic) + return xxx_messageInfo_ShareAddress.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -236,30 +236,37 @@ func (m *TokenDistribution) XXX_Marshal(b []byte, deterministic bool) ([]byte, e return b[:n], nil } } -func (m *TokenDistribution) XXX_Merge(src proto.Message) { - xxx_messageInfo_TokenDistribution.Merge(m, src) +func (m *ShareAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShareAddress.Merge(m, src) } -func (m *TokenDistribution) XXX_Size() int { +func (m *ShareAddress) XXX_Size() int { return m.Size() } -func (m *TokenDistribution) XXX_DiscardUnknown() { - xxx_messageInfo_TokenDistribution.DiscardUnknown(m) +func (m *ShareAddress) XXX_DiscardUnknown() { + xxx_messageInfo_ShareAddress.DiscardUnknown(m) } -var xxx_messageInfo_TokenDistribution proto.InternalMessageInfo +var xxx_messageInfo_ShareAddress proto.InternalMessageInfo -func (m *TokenDistribution) GetDistributors() []string { +func (m *ShareAddress) GetEvmAddress() string { if m != nil { - return m.Distributors + return m.EvmAddress } - return nil + return "" +} + +func (m *ShareAddress) GetSdkAddress() string { + if m != nil { + return m.SdkAddress + } + return "" } func init() { proto.RegisterEnum("realionetwork.asset.v1.Role", Role_name, Role_value) proto.RegisterType((*Token)(nil), "realionetwork.asset.v1.Token") proto.RegisterType((*TokenManagement)(nil), "realionetwork.asset.v1.TokenManagement") - proto.RegisterType((*TokenDistribution)(nil), "realionetwork.asset.v1.TokenDistribution") + proto.RegisterType((*ShareAddress)(nil), "realionetwork.asset.v1.ShareAddress") } func init() { @@ -267,41 +274,41 @@ func init() { } var fileDescriptor_2f83138fc60a3176 = []byte{ - // 530 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x92, 0x3f, 0x6f, 0xd3, 0x40, - 0x18, 0xc6, 0xed, 0x36, 0x4d, 0x93, 0x4b, 0x4b, 0xc2, 0x51, 0x2a, 0x63, 0x09, 0xc7, 0x84, 0x81, - 0x80, 0x84, 0x4d, 0x61, 0x65, 0x49, 0x88, 0x41, 0x96, 0xd2, 0x14, 0x39, 0xe9, 0xc2, 0x62, 0x5d, - 0xe2, 0x53, 0x72, 0x8a, 0xcf, 0x67, 0xf9, 0x2e, 0xff, 0x26, 0xd6, 0x2a, 0x13, 0x5f, 0x20, 0x13, - 0x1f, 0x85, 0xa5, 0x63, 0x47, 0xc4, 0x50, 0xa1, 0xe4, 0x8b, 0xa0, 0x9c, 0xf3, 0x87, 0x6e, 0xef, - 0xf3, 0xbc, 0xbf, 0x7b, 0xf5, 0xbe, 0xa7, 0x07, 0x54, 0x12, 0x8c, 0x42, 0xc2, 0x22, 0x2c, 0x26, - 0x2c, 0x19, 0xda, 0x88, 0x73, 0x2c, 0xec, 0xf1, 0x85, 0x2d, 0xd8, 0x10, 0x47, 0x56, 0x9c, 0x30, - 0xc1, 0xe0, 0xf9, 0x03, 0xc6, 0x92, 0x8c, 0x35, 0xbe, 0xd0, 0xcf, 0xfa, 0xac, 0xcf, 0x24, 0x62, - 0xaf, 0xab, 0x94, 0xae, 0xfc, 0x52, 0xc1, 0x51, 0x67, 0xfd, 0x1a, 0x3e, 0x03, 0x39, 0x39, 0xc6, - 0x27, 0x81, 0xa6, 0x9a, 0x6a, 0x35, 0xef, 0x1d, 0x4b, 0xed, 0x06, 0xf0, 0x1c, 0x64, 0x09, 0xe7, - 0x23, 0x9c, 0x68, 0x07, 0xb2, 0xb1, 0x51, 0x10, 0x82, 0x4c, 0x84, 0x28, 0xd6, 0x0e, 0xa5, 0x2b, - 0xeb, 0x35, 0xcb, 0x67, 0xb4, 0xcb, 0x42, 0x2d, 0x93, 0xb2, 0xa9, 0x82, 0x1a, 0x38, 0x0e, 0x70, - 0x8f, 0x50, 0x14, 0x6a, 0x47, 0xa6, 0x5a, 0x3d, 0xf5, 0xb6, 0x12, 0x9a, 0xa0, 0x10, 0x60, 0xde, - 0x4b, 0x48, 0x2c, 0x08, 0x8b, 0xb4, 0xac, 0x7c, 0xf6, 0xbf, 0x05, 0xcb, 0xa0, 0x80, 0xc7, 0xd4, - 0x47, 0x41, 0x90, 0x60, 0xce, 0xb5, 0xbc, 0x24, 0x00, 0x1e, 0xd3, 0x5a, 0xea, 0x54, 0x6e, 0x54, - 0x50, 0x94, 0x57, 0x5c, 0xa2, 0x08, 0xf5, 0x31, 0xc5, 0x91, 0x80, 0x3a, 0xc8, 0x51, 0xa9, 0x12, - 0xae, 0xa9, 0xe6, 0x61, 0x35, 0xef, 0xed, 0x34, 0x7c, 0x07, 0xce, 0x50, 0x18, 0xb2, 0x89, 0x1f, - 0xe1, 0x89, 0x8f, 0xa7, 0x02, 0x47, 0x9c, 0xb0, 0x88, 0xcb, 0xf3, 0x72, 0x1e, 0x94, 0xbd, 0x16, - 0x9e, 0x38, 0xbb, 0x0e, 0x7c, 0x05, 0x8a, 0x7b, 0xce, 0x0f, 0x09, 0x17, 0xda, 0xa1, 0x1c, 0xfa, - 0x68, 0x6f, 0x37, 0x09, 0x17, 0x95, 0x11, 0x78, 0x2c, 0x37, 0x69, 0x10, 0x2e, 0x12, 0xd2, 0x1d, - 0xc9, 0x03, 0x2a, 0xe0, 0x24, 0xd8, 0x6a, 0xb6, 0xdb, 0xe7, 0x81, 0x07, 0x3f, 0x02, 0x40, 0xd1, - 0xd4, 0xe7, 0xa3, 0x38, 0x0e, 0x67, 0xe9, 0x47, 0xd7, 0x9f, 0xdf, 0xde, 0x97, 0x95, 0x3f, 0xf7, - 0xe5, 0xa7, 0x3d, 0xc6, 0x29, 0xe3, 0x3c, 0x18, 0x5a, 0x84, 0xd9, 0x14, 0x89, 0x81, 0xe5, 0x46, - 0xc2, 0xcb, 0x53, 0x34, 0x6d, 0x4b, 0xfe, 0xcd, 0x77, 0x90, 0xf1, 0x58, 0x88, 0xe1, 0x4b, 0x50, - 0xf2, 0xae, 0x9a, 0x8e, 0x7f, 0xdd, 0x6a, 0x7f, 0x75, 0x3e, 0xb9, 0x9f, 0x5d, 0xa7, 0x51, 0x52, - 0xf4, 0xd3, 0xf9, 0xc2, 0xcc, 0x3b, 0x34, 0x16, 0x33, 0x09, 0xbd, 0x00, 0x27, 0x12, 0xba, 0xac, - 0xb5, 0x6a, 0x5f, 0x1c, 0xaf, 0xa4, 0xea, 0xc5, 0xf9, 0xc2, 0x2c, 0xa4, 0x9f, 0x97, 0x48, 0xe4, - 0xf5, 0x66, 0x4e, 0xc3, 0x6d, 0x77, 0x3c, 0xb7, 0x7e, 0xdd, 0xb9, 0xf2, 0x4a, 0x07, 0xfa, 0x93, - 0xf9, 0xc2, 0x2c, 0x36, 0xf6, 0x5b, 0xaf, 0x51, 0x3d, 0x73, 0xf3, 0xd3, 0x50, 0xea, 0xcd, 0xdb, - 0xa5, 0xa1, 0xde, 0x2d, 0x0d, 0xf5, 0xef, 0xd2, 0x50, 0x7f, 0xac, 0x0c, 0xe5, 0x6e, 0x65, 0x28, - 0xbf, 0x57, 0x86, 0xf2, 0xed, 0x7d, 0x9f, 0x88, 0xc1, 0xa8, 0x6b, 0xf5, 0x18, 0xb5, 0xd3, 0x6c, - 0x0a, 0xdc, 0x1b, 0x6c, 0xca, 0xb7, 0xdb, 0x2c, 0x4f, 0x37, 0x69, 0x16, 0xb3, 0x18, 0xf3, 0x6e, - 0x56, 0xa6, 0xf3, 0xc3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x4c, 0x9a, 0x9f, 0xf1, 0x02, - 0x00, 0x00, + // 540 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xcf, 0x6e, 0xd3, 0x4c, + 0x14, 0xc5, 0xed, 0x36, 0x4d, 0x93, 0x49, 0xfb, 0x25, 0x9a, 0xaf, 0x54, 0xc6, 0x12, 0x8e, 0x09, + 0x0b, 0x02, 0x12, 0x36, 0x85, 0x2d, 0x9b, 0x84, 0x18, 0x64, 0x29, 0x4d, 0x2b, 0x27, 0xdd, 0xb0, + 0xb1, 0x26, 0xf1, 0x28, 0x19, 0xc5, 0xe3, 0xb1, 0x3c, 0x93, 0x7f, 0x2b, 0xb6, 0x28, 0x2b, 0x5e, + 0x20, 0x2b, 0x1e, 0x05, 0x09, 0x75, 0xd9, 0x25, 0x62, 0x51, 0xa1, 0xe4, 0x45, 0x50, 0xc6, 0x6e, + 0x0a, 0xdd, 0xdd, 0x73, 0xef, 0x6f, 0xae, 0x74, 0xee, 0x1c, 0x50, 0x4b, 0x30, 0x0a, 0x09, 0x8b, + 0xb0, 0x98, 0xb1, 0x64, 0x6c, 0x23, 0xce, 0xb1, 0xb0, 0xa7, 0x67, 0xb6, 0x60, 0x63, 0x1c, 0x59, + 0x71, 0xc2, 0x04, 0x83, 0xa7, 0xff, 0x30, 0x96, 0x64, 0xac, 0xe9, 0x99, 0x7e, 0x32, 0x64, 0x43, + 0x26, 0x11, 0x7b, 0x5b, 0xa5, 0x74, 0xed, 0xbb, 0x0a, 0x0e, 0x7a, 0xdb, 0xd7, 0xf0, 0x31, 0x28, + 0xc8, 0x35, 0x3e, 0x09, 0x34, 0xd5, 0x54, 0xeb, 0x45, 0xef, 0x50, 0x6a, 0x37, 0x80, 0xa7, 0x20, + 0x4f, 0x38, 0x9f, 0xe0, 0x44, 0xdb, 0x93, 0x83, 0x4c, 0x41, 0x08, 0x72, 0x11, 0xa2, 0x58, 0xdb, + 0x97, 0x5d, 0x59, 0x6f, 0x59, 0xbe, 0xa0, 0x7d, 0x16, 0x6a, 0xb9, 0x94, 0x4d, 0x15, 0xd4, 0xc0, + 0x61, 0x80, 0x07, 0x84, 0xa2, 0x50, 0x3b, 0x30, 0xd5, 0xfa, 0xb1, 0x77, 0x27, 0xa1, 0x09, 0x4a, + 0x01, 0xe6, 0x83, 0x84, 0xc4, 0x82, 0xb0, 0x48, 0xcb, 0xcb, 0x67, 0x7f, 0xb7, 0x60, 0x15, 0x94, + 0xf0, 0x94, 0xfa, 0x28, 0x08, 0x12, 0xcc, 0xb9, 0x56, 0x94, 0x04, 0xc0, 0x53, 0xda, 0x48, 0x3b, + 0xb5, 0x1f, 0x2a, 0x28, 0x4b, 0x17, 0xe7, 0x28, 0x42, 0x43, 0x4c, 0x71, 0x24, 0xa0, 0x0e, 0x0a, + 0x54, 0xaa, 0x84, 0x6b, 0xaa, 0xb9, 0x5f, 0x2f, 0x7a, 0x3b, 0x0d, 0x5f, 0x83, 0x13, 0x14, 0x86, + 0x6c, 0xe6, 0x47, 0x78, 0xe6, 0xe3, 0xb9, 0xc0, 0x11, 0x27, 0x2c, 0xe2, 0xd2, 0x5e, 0xc1, 0x83, + 0x72, 0xd6, 0xc1, 0x33, 0x67, 0x37, 0x81, 0xcf, 0x41, 0xf9, 0x9e, 0xf3, 0x43, 0xc2, 0x85, 0xb6, + 0x2f, 0x97, 0xfe, 0x77, 0xdf, 0x6e, 0x13, 0x2e, 0xe0, 0x3b, 0x00, 0x28, 0x9a, 0xfb, 0x7c, 0x12, + 0xc7, 0xe1, 0x22, 0xbd, 0x41, 0xf3, 0xc9, 0xf5, 0x6d, 0x55, 0xf9, 0x75, 0x5b, 0x7d, 0x34, 0x60, + 0x9c, 0x32, 0xce, 0x83, 0xb1, 0x45, 0x98, 0x4d, 0x91, 0x18, 0x59, 0x6e, 0x24, 0xbc, 0x22, 0x45, + 0xf3, 0xae, 0xe4, 0x6b, 0x97, 0xe0, 0xa8, 0x3b, 0x42, 0x09, 0xce, 0x8c, 0x3d, 0x74, 0xae, 0x3e, + 0x74, 0xbe, 0x05, 0x78, 0x30, 0xde, 0x01, 0xe9, 0xff, 0x00, 0x1e, 0x8c, 0x33, 0xe0, 0xe5, 0x67, + 0x90, 0xf3, 0x58, 0x88, 0xe1, 0x33, 0x50, 0xf1, 0x2e, 0xda, 0x8e, 0x7f, 0xd5, 0xe9, 0x5e, 0x3a, + 0xef, 0xdd, 0x0f, 0xae, 0xd3, 0xaa, 0x28, 0xfa, 0xf1, 0x72, 0x65, 0x16, 0x1d, 0x1a, 0x8b, 0x85, + 0x84, 0x9e, 0x82, 0x23, 0x09, 0x9d, 0x37, 0x3a, 0x8d, 0x8f, 0x8e, 0x57, 0x51, 0xf5, 0xf2, 0x72, + 0x65, 0x96, 0xd2, 0xab, 0x26, 0x12, 0x79, 0x91, 0xed, 0x69, 0xb9, 0xdd, 0x9e, 0xe7, 0x36, 0xaf, + 0x7a, 0x17, 0x5e, 0x65, 0x4f, 0xff, 0x7f, 0xb9, 0x32, 0xcb, 0x2d, 0xc2, 0x45, 0x42, 0xfa, 0x13, + 0xc1, 0x24, 0xaa, 0xe7, 0xbe, 0x7c, 0x33, 0x94, 0x66, 0xfb, 0x7a, 0x6d, 0xa8, 0x37, 0x6b, 0x43, + 0xfd, 0xbd, 0x36, 0xd4, 0xaf, 0x1b, 0x43, 0xb9, 0xd9, 0x18, 0xca, 0xcf, 0x8d, 0xa1, 0x7c, 0x7a, + 0x33, 0x24, 0x62, 0x34, 0xe9, 0x5b, 0x03, 0x46, 0xed, 0x34, 0xb4, 0x02, 0x0f, 0x46, 0x59, 0xf9, + 0xea, 0x2e, 0xe4, 0xf3, 0x2c, 0xe6, 0x62, 0x11, 0x63, 0xde, 0xcf, 0xcb, 0xd8, 0xbe, 0xfd, 0x13, + 0x00, 0x00, 0xff, 0xff, 0x22, 0xe2, 0x9c, 0xa3, 0x0a, 0x03, 0x00, 0x00, } func (m *Token) Marshal() (dAtA []byte, err error) { @@ -394,6 +401,16 @@ func (m *TokenManagement) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.MaxSupply.Size() + i -= size + if _, err := m.MaxSupply.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.ExtensionsList) > 0 { for iNdEx := len(m.ExtensionsList) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.ExtensionsList[iNdEx]) @@ -425,7 +442,7 @@ func (m *TokenManagement) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *TokenDistribution) Marshal() (dAtA []byte, err error) { +func (m *ShareAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -435,34 +452,29 @@ func (m *TokenDistribution) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *TokenDistribution) MarshalTo(dAtA []byte) (int, error) { +func (m *ShareAddress) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *TokenDistribution) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ShareAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - { - size := m.MaxSupply.Size() - i -= size - if _, err := m.MaxSupply.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintToken(dAtA, i, uint64(size)) + if len(m.SdkAddress) > 0 { + i -= len(m.SdkAddress) + copy(dAtA[i:], m.SdkAddress) + i = encodeVarintToken(dAtA, i, uint64(len(m.SdkAddress))) + i-- + dAtA[i] = 0x12 } - i-- - dAtA[i] = 0x12 - if len(m.Distributors) > 0 { - for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Distributors[iNdEx]) - copy(dAtA[i:], m.Distributors[iNdEx]) - i = encodeVarintToken(dAtA, i, uint64(len(m.Distributors[iNdEx]))) - i-- - dAtA[i] = 0xa - } + if len(m.EvmAddress) > 0 { + i -= len(m.EvmAddress) + copy(dAtA[i:], m.EvmAddress) + i = encodeVarintToken(dAtA, i, uint64(len(m.EvmAddress))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -535,23 +547,25 @@ func (m *TokenManagement) Size() (n int) { n += 1 + l + sovToken(uint64(l)) } } + l = m.MaxSupply.Size() + n += 1 + l + sovToken(uint64(l)) return n } -func (m *TokenDistribution) Size() (n int) { +func (m *ShareAddress) Size() (n int) { if m == nil { return 0 } var l int _ = l - if len(m.Distributors) > 0 { - for _, s := range m.Distributors { - l = len(s) - n += 1 + l + sovToken(uint64(l)) - } + l = len(m.EvmAddress) + if l > 0 { + n += 1 + l + sovToken(uint64(l)) + } + l = len(m.SdkAddress) + if l > 0 { + n += 1 + l + sovToken(uint64(l)) } - l = m.MaxSupply.Size() - n += 1 + l + sovToken(uint64(l)) return n } @@ -935,6 +949,40 @@ func (m *TokenManagement) Unmarshal(dAtA []byte) error { } m.ExtensionsList = append(m.ExtensionsList, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSupply", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipToken(dAtA[iNdEx:]) @@ -956,7 +1004,7 @@ func (m *TokenManagement) Unmarshal(dAtA []byte) error { } return nil } -func (m *TokenDistribution) Unmarshal(dAtA []byte) error { +func (m *ShareAddress) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -979,15 +1027,15 @@ func (m *TokenDistribution) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: TokenDistribution: wiretype end group for non-group") + return fmt.Errorf("proto: ShareAddress: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: TokenDistribution: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ShareAddress: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EvmAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1015,11 +1063,11 @@ func (m *TokenDistribution) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) + m.EvmAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxSupply", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SdkAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1047,9 +1095,7 @@ func (m *TokenDistribution) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MaxSupply.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.SdkAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex From b9b235c9f03f5ce21ad075652805aaf112782a34 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Tue, 21 Jan 2025 15:14:53 +0700 Subject: [PATCH 24/53] port denom into precompile, no more tokenPair --- app/mock_erc20.go | 4 ++-- precompiles/erc20/approve.go | 26 +++++++++++++------------- precompiles/erc20/query.go | 20 ++++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/mock_erc20.go b/app/mock_erc20.go index f07a773c..c47695d5 100644 --- a/app/mock_erc20.go +++ b/app/mock_erc20.go @@ -30,12 +30,12 @@ func NewEmptyMockErc20Keeper() MockErc20Keeper { func (k MockErc20Keeper) GetERC20PrecompileInstance(ctx sdk.Context, addr common.Address) (contract vm.PrecompiledContract, found bool, err error) { // Check if contract address in list - exist, err := k.assetKeeper.EVMContractExist(ctx, addr) + exist, denom, err := k.assetKeeper.EVMContractExist(ctx, addr) if err != nil || !exist { return nil, false, nil } - precompile, err := erc20.NewPrecompile(addr, k.bankKeeper, k.authzKeeper, *k.transferKeeper, k.assetKeeper) + precompile, err := erc20.NewPrecompile(denom, addr, k.bankKeeper, k.authzKeeper, *k.transferKeeper, k.assetKeeper) if err != nil { return nil, false, nil } diff --git a/precompiles/erc20/approve.go b/precompiles/erc20/approve.go index 029ecfcf..605ad4b4 100644 --- a/precompiles/erc20/approve.go +++ b/precompiles/erc20/approve.go @@ -178,7 +178,7 @@ func (p Precompile) DecreaseAllowance( } // TODO: owner should be the owner of the contract - authorization, expiration, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, grantee, granter, p.tokenPair.Denom) + authorization, expiration, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, grantee, granter, p.denom) // TODO: (@fedekunze) check if this is correct by comparing behavior with // regular ERC-20 @@ -189,7 +189,7 @@ func (p Precompile) DecreaseAllowance( err = ErrDecreaseNonPositiveValue case err != nil: // case 2. no authorization -> return error - err = sdkerrors.Wrap(err, fmt.Sprintf(ErrNoAllowanceForToken, p.tokenPair.Denom)) + err = sdkerrors.Wrap(err, fmt.Sprintf(ErrNoAllowanceForToken, p.denom)) case subtractedValue != nil && subtractedValue.Cmp(allowance) < 0: // case 3. subtractedValue positive and subtractedValue less than allowance -> update authorization amount, err = p.decreaseAllowance(ctx, grantee, granter, subtractedValue, authorization, expiration) @@ -199,10 +199,10 @@ func (p Precompile) DecreaseAllowance( amount = common.Big0 case subtractedValue != nil && allowance.Sign() == 0: // case 5. subtractedValue positive but no allowance for given denomination -> return error - err = fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + err = fmt.Errorf(ErrNoAllowanceForToken, p.denom) case subtractedValue != nil && subtractedValue.Cmp(allowance) > 0: // case 6. subtractedValue positive and subtractedValue higher than allowance -> return error - err = ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.tokenPair.Denom, subtractedValue, allowance)) + err = ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.denom, subtractedValue, allowance)) } if err != nil { @@ -222,7 +222,7 @@ func (p Precompile) createAuthorization(ctx sdk.Context, grantee, granter common return fmt.Errorf(ErrIntegerOverflow, amount) } - coins := sdk.Coins{{Denom: p.tokenPair.Denom, Amount: sdkmath.NewIntFromBigInt(amount)}} + coins := sdk.Coins{{Denom: p.denom, Amount: sdkmath.NewIntFromBigInt(amount)}} expiration := ctx.BlockTime().Add(p.ApprovalExpiration) // NOTE: we leave the allowed arg empty as all recipients are allowed (per ERC20 standard) @@ -235,7 +235,7 @@ func (p Precompile) createAuthorization(ctx sdk.Context, grantee, granter common } func (p Precompile) updateAuthorization(ctx sdk.Context, grantee, granter common.Address, amount *big.Int, authorization *banktypes.SendAuthorization, expiration *time.Time) error { - authorization.SpendLimit = updateOrAddCoin(authorization.SpendLimit, sdk.Coin{Denom: p.tokenPair.Denom, Amount: sdkmath.NewIntFromBigInt(amount)}) + authorization.SpendLimit = updateOrAddCoin(authorization.SpendLimit, sdk.Coin{Denom: p.denom, Amount: sdkmath.NewIntFromBigInt(amount)}) if err := authorization.ValidateBasic(); err != nil { return err } @@ -252,16 +252,16 @@ func (p Precompile) removeSpendLimitOrDeleteAuthorization(ctx sdk.Context, grant return authz.ErrUnknownAuthorizationType } - found, denomCoins := sendAuthz.SpendLimit.Find(p.tokenPair.Denom) + found, denomCoins := sendAuthz.SpendLimit.Find(p.denom) if !found { - return fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + return fmt.Errorf(ErrNoAllowanceForToken, p.denom) } newSpendLimit, hasNeg := sendAuthz.SpendLimit.SafeSub(denomCoins) // NOTE: safety check only, this should never happen since we only subtract what was found in the slice. if hasNeg { return ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, - p.tokenPair.Denom, denomCoins, sendAuthz.SpendLimit, + p.denom, denomCoins, sendAuthz.SpendLimit, )) } @@ -285,7 +285,7 @@ func (p Precompile) increaseAllowance( return nil, authz.ErrUnknownAuthorizationType } - allowance := sendAuthz.SpendLimit.AmountOfNoDenomValidation(p.tokenPair.Denom) + allowance := sendAuthz.SpendLimit.AmountOfNoDenomValidation(p.denom) sdkAddedValue := sdkmath.NewIntFromBigInt(addedValue) amount, overflow := cmn.SafeAdd(allowance, sdkAddedValue) if overflow { @@ -311,15 +311,15 @@ func (p Precompile) decreaseAllowance( return nil, authz.ErrUnknownAuthorizationType } - found, allowance := sendAuthz.SpendLimit.Find(p.tokenPair.Denom) + found, allowance := sendAuthz.SpendLimit.Find(p.denom) if !found { - return nil, fmt.Errorf(ErrNoAllowanceForToken, p.tokenPair.Denom) + return nil, fmt.Errorf(ErrNoAllowanceForToken, p.denom) } amount = new(big.Int).Sub(allowance.Amount.BigInt(), subtractedValue) // NOTE: Safety check only since this is checked in the DecreaseAllowance method already. if amount.Sign() < 0 { - return nil, ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.tokenPair.Denom, subtractedValue, allowance.Amount)) + return nil, ConvertErrToERC20Error(fmt.Errorf(ErrSubtractMoreThanAllowance, p.denom, subtractedValue, allowance.Amount)) } if err := p.updateAuthorization(ctx, grantee, granter, amount, sendAuthz, expiration); err != nil { diff --git a/precompiles/erc20/query.go b/precompiles/erc20/query.go index f9c269c7..06e599fa 100644 --- a/precompiles/erc20/query.go +++ b/precompiles/erc20/query.go @@ -51,12 +51,12 @@ func (p Precompile) Name( method *abi.Method, _ []interface{}, ) ([]byte, error) { - metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.denom) if found { return method.Outputs.Pack(metadata.Name) } - baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.tokenPair.Denom) + baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.denom) if err != nil { return nil, ConvertErrToERC20Error(err) } @@ -75,12 +75,12 @@ func (p Precompile) Symbol( method *abi.Method, _ []interface{}, ) ([]byte, error) { - metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.denom) if found { return method.Outputs.Pack(metadata.Symbol) } - baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.tokenPair.Denom) + baseDenom, err := p.getBaseDenomFromIBCVoucher(ctx, p.denom) if err != nil { return nil, ConvertErrToERC20Error(err) } @@ -99,9 +99,9 @@ func (p Precompile) Decimals( method *abi.Method, _ []interface{}, ) ([]byte, error) { - metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) + metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.denom) if !found { - denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, p.tokenPair.Denom) + denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, p.denom) if err != nil { return nil, ConvertErrToERC20Error(err) } @@ -129,7 +129,7 @@ func (p Precompile) Decimals( if !displayFound { return nil, ConvertErrToERC20Error(fmt.Errorf( "display denomination not found for denom: %q", - p.tokenPair.Denom, + p.denom, )) } @@ -152,7 +152,7 @@ func (p Precompile) TotalSupply( method *abi.Method, _ []interface{}, ) ([]byte, error) { - supply := p.BankKeeper.GetSupply(ctx, p.tokenPair.Denom) + supply := p.BankKeeper.GetSupply(ctx, p.denom) return method.Outputs.Pack(supply.Amount.BigInt()) } @@ -171,7 +171,7 @@ func (p Precompile) BalanceOf( return nil, err } - balance := p.BankKeeper.GetBalance(ctx, account.Bytes(), p.tokenPair.Denom) + balance := p.BankKeeper.GetBalance(ctx, account.Bytes(), p.denom) return method.Outputs.Pack(balance.Amount.BigInt()) } @@ -196,7 +196,7 @@ func (p Precompile) Allowance( return method.Outputs.Pack(abi.MaxUint256) } - _, _, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spender, owner, p.tokenPair.Denom) + _, _, allowance, err := GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spender, owner, p.denom) if err != nil { // NOTE: We are not returning the error here, because we want to align the behavior with // standard ERC20 smart contracts, which return zero if an allowance is not found. From c77a57c73f701a6e61f75862651ef61726d56204 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Tue, 21 Jan 2025 15:18:09 +0700 Subject: [PATCH 25/53] basic mint/burn --- precompiles/erc20/erc20.go | 28 ++++++- precompiles/erc20/events.go | 62 ++++++++++++++ precompiles/erc20/tx.go | 159 +++++++++++++++++++++++++++++++++++- precompiles/erc20/types.go | 55 +++++++++++++ 4 files changed, 298 insertions(+), 6 deletions(-) diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 9e463210..ab67457b 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -6,6 +6,7 @@ package erc20 import ( "embed" "fmt" + "slices" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -15,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/common" auth "github.com/evmos/os/precompiles/authorization" cmn "github.com/evmos/os/precompiles/common" - erc20types "github.com/evmos/os/x/erc20/types" "github.com/evmos/os/x/evm/core/vm" transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" assetkeeper "github.com/realiotech/realio-network/x/asset/keeper" @@ -47,7 +47,7 @@ var _ vm.PrecompiledContract = &Precompile{} // Precompile defines the precompiled contract for ERC-20. type Precompile struct { cmn.Precompile - tokenPair erc20types.TokenPair + denom string transferKeeper transferkeeper.Keeper // BankKeeper is a public field so that the werc20 precompile can use it. BankKeeper bankkeeper.Keeper @@ -57,6 +57,7 @@ type Precompile struct { // NewPrecompile creates a new ERC-20 Precompile instance as a // PrecompiledContract interface. func NewPrecompile( + denom string, address common.Address, bankKeeper bankkeeper.Keeper, authzKeeper authzkeeper.Keeper, @@ -78,7 +79,8 @@ func NewPrecompile( }, BankKeeper: bankKeeper, transferKeeper: transferKeeper, - assetKeep: assetKeeper, + assetKeep: assetKeeper, + denom: denom, } // Address defines the address of the ERC-20 precompile contract. p.SetAddress(address) @@ -188,12 +190,32 @@ func (p *Precompile) HandleMethod( method *abi.Method, args []interface{}, ) (bz []byte, err error) { + params, err := p.assetKeep.GetParams(ctx) + allowedMethods := params.AllowExtensions + if err != nil { + return nil, err + } switch method.Name { // ERC-20 transactions case TransferMethod: bz, err = p.Transfer(ctx, contract, stateDB, method, args) case TransferFromMethod: bz, err = p.TransferFrom(ctx, contract, stateDB, method, args) + case MintMethod: + if !slices.Contains(allowedMethods, MintMethod) { + return nil, fmt.Errorf("method %s is not supported", MintMethod) + } + bz, err = p.Mint(ctx, contract, stateDB, method, args) + case BurnMethod: + if !slices.Contains(allowedMethods, BurnMethod) { + return nil, fmt.Errorf("method %s is not supported", BurnMethod) + } + bz, err = p.Burn(ctx, contract, stateDB, method, args) + case BurnFromMethod: + if !slices.Contains(allowedMethods, BurnFromMethod) { + return nil, fmt.Errorf("method %s is not supported", BurnFromMethod) + } + bz, err = p.BurnFrom(ctx, contract, stateDB, method, args) case auth.ApproveMethod: bz, err = p.Approve(ctx, contract, stateDB, method, args) case auth.IncreaseAllowanceMethod: diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index 7b886bd5..459f956c 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -20,6 +20,8 @@ import ( const ( // EventTypeTransfer defines the event type for the ERC-20 Transfer and TransferFrom transactions. EventTypeTransfer = "Transfer" + EventTypeMint = "Mint" + EventTypeBurn = "Burn" ) // EmitTransferEvent creates a new Transfer event emitted on transfer and transferFrom transactions. @@ -58,6 +60,66 @@ func (p Precompile) EmitTransferEvent(ctx sdk.Context, stateDB vm.StateDB, from, return nil } +func (p Precompile) EmitMintEvent(ctx sdk.Context, stateDB vm.StateDB, to common.Address, value *big.Int) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeMint] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(to) + if err != nil { + return err + } + + arguments := abi.Arguments{event.Inputs[1]} + packed, err := arguments.Pack(value) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + +func (p Precompile) EmitBurnEvent(ctx sdk.Context, stateDB vm.StateDB, from common.Address, value *big.Int) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeBurn] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(from) + if err != nil { + return err + } + + arguments := abi.Arguments{event.Inputs[1]} + packed, err := arguments.Pack(value) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + // EmitApprovalEvent creates a new approval event emitted on Approve, IncreaseAllowance // and DecreaseAllowance transactions. func (p Precompile) EmitApprovalEvent(ctx sdk.Context, stateDB vm.StateDB, owner, spender common.Address, value *big.Int) error { diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index c94f25d3..de68b4a3 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -4,6 +4,7 @@ package erc20 import ( + "fmt" "math/big" errorsmod "cosmossdk.io/errors" @@ -17,6 +18,7 @@ import ( cmn "github.com/evmos/os/precompiles/common" "github.com/evmos/os/x/evm/core/vm" evmtypes "github.com/evmos/os/x/evm/types" + assettypes "github.com/realiotech/realio-network/x/asset/types" ) const ( @@ -26,6 +28,12 @@ const ( // TransferFromMethod defines the ABI method name for the ERC-20 transferFrom // transaction. TransferFromMethod = "transferFrom" + + BurnMethod = "burn" + + BurnFromMethod = "burnFrom" + + MintMethod = "mint" ) // SendMsgURL defines the authorization type for MsgSend @@ -77,7 +85,7 @@ func (p *Precompile) transfer( from, to common.Address, amount *big.Int, ) (data []byte, err error) { - coins := sdk.Coins{{Denom: p.tokenPair.Denom, Amount: math.NewIntFromBigInt(amount)}} + coins := sdk.Coins{{Denom: p.denom, Amount: math.NewIntFromBigInt(amount)}} msg := banktypes.NewMsgSend(from.Bytes(), to.Bytes(), coins) @@ -96,7 +104,7 @@ func (p *Precompile) transfer( msgSrv := bankkeeper.NewMsgServerImpl(p.BankKeeper) _, err = msgSrv.Send(ctx, msg) } else { - _, _, prevAllowance, err = GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spenderAddr, from, p.tokenPair.Denom) + _, _, prevAllowance, err = GetAuthzExpirationAndAllowance(p.AuthzKeeper, ctx, spenderAddr, from, p.denom) if err != nil { return nil, ConvertErrToERC20Error(errorsmod.Wrap(err, authz.ErrNoAuthorizationFound.Error())) } @@ -111,7 +119,7 @@ func (p *Precompile) transfer( } evmDenom := evmtypes.GetEVMCoinDenom() - if p.tokenPair.Denom == evmDenom { + if p.denom == evmDenom { convertedAmount := evmtypes.ConvertAmountTo18DecimalsBigInt(amount) p.SetBalanceChangeEntries(cmn.NewBalanceChangeEntry(from, convertedAmount, cmn.Sub), cmn.NewBalanceChangeEntry(to, convertedAmount, cmn.Add)) @@ -142,3 +150,148 @@ func (p *Precompile) transfer( return method.Outputs.Pack(true) } + +func (p *Precompile) Mint( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + to, amount, err := ParseMintArgs(args) + if err != nil { + return nil, err + } + + return p.mint(ctx, contract, stateDB, method, to, amount) +} + +func (p *Precompile) mint( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + to common.Address, + amount *big.Int, +) (data []byte, err error) { + + minter := contract.CallerAddress + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) + if err != nil || !havePerm { + return nil, err + } + + mintToAddr := sdk.AccAddress(to.Bytes()) + + coins := sdk.Coins{{Denom: p.denom, Amount: math.NewIntFromBigInt(amount)}} + + // Check if new supply exceed max supply + + tm, err := p.assetKeep.GetTokenManager(ctx, p.denom) + if err != nil { + return nil, err + } + maxSupply := tm.MaxSupply + currentSupply := p.BankKeeper.GetSupply(ctx, p.denom).Amount + newSupply := currentSupply.Add(math.NewIntFromBigInt(amount)) + if newSupply.GT(maxSupply) { + return nil, ConvertErrToERC20Error(fmt.Errorf("Exceed max supply, expected: %d, got: %d", maxSupply, newSupply)) + } + + // Mint coins to asset module then transfer to minter addr + err = p.BankKeeper.MintCoins(ctx, assettypes.ModuleName, coins) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + err = p.BankKeeper.SendCoinsFromModuleToAccount(ctx, assettypes.ModuleName, mintToAddr, coins) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + evmDenom := evmtypes.GetEVMCoinDenom() + if p.denom == evmDenom { + convertedAmount := evmtypes.ConvertAmountTo18DecimalsBigInt(amount) + p.SetBalanceChangeEntries(cmn.NewBalanceChangeEntry(to, convertedAmount, cmn.Add)) + } + + if err = p.EmitMintEvent(ctx, stateDB, to, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +func (p *Precompile) Burn( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + from := contract.CallerAddress + amount, err := ParseBurnArgs(args) + if err != nil { + return nil, err + } + + return p.burn(ctx, contract, stateDB, method, from, amount) +} + +func (p *Precompile) BurnFrom( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + from, amount, err := ParseBurnFromArgs(args) + if err != nil { + return nil, err + } + + return p.burn(ctx, contract, stateDB, method, from, amount) +} + +func (p *Precompile) burn( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + from common.Address, + amount *big.Int, +) (data []byte, err error) { + + minter := contract.CallerAddress + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) + if err != nil || !havePerm { + return nil, err + } + + burnFromAddr := sdk.AccAddress(from.Bytes()) + + coins := sdk.Coins{{Denom: p.denom, Amount: math.NewIntFromBigInt(amount)}} + + // Transfer to asset module then burn + err = p.BankKeeper.SendCoinsFromAccountToModule(ctx, burnFromAddr, assettypes.ModuleName, coins) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + err = p.BankKeeper.BurnCoins(ctx, assettypes.ModuleName, coins) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + evmDenom := evmtypes.GetEVMCoinDenom() + if p.denom == evmDenom { + convertedAmount := evmtypes.ConvertAmountTo18DecimalsBigInt(amount) + p.SetBalanceChangeEntries(cmn.NewBalanceChangeEntry(from, convertedAmount, cmn.Add)) + } + + if err = p.EmitBurnEvent(ctx, stateDB, from, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index 399a7e31..565e4b45 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -150,3 +150,58 @@ func updateOrAddCoin(coins sdk.Coins, coin sdk.Coin) sdk.Coins { // add it here. return coins.Add(coin) } + +func ParseMintArgs(args []interface{}) ( + to common.Address, amount *big.Int, err error, +) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + to, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid to address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return to, amount, nil +} + +func ParseBurnArgs(args []interface{}) ( + amount *big.Int, err error, +) { + if len(args) != 1 { + return nil, fmt.Errorf("invalid number of arguments; expected 1; got: %d", len(args)) + } + + amount, ok := args[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return amount, nil +} + +func ParseBurnFromArgs(args []interface{}) ( + from common.Address, amount *big.Int, err error, +) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + from, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid to address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return from, amount, nil +} From 8173a0b026f3c023abdb6724f6bbb4d8e0bba282 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 19:23:50 +0700 Subject: [PATCH 26/53] basic test --- go.mod | 50 +- go.sum | 112 +- precompiles/erc20/integration_test.go | 2868 +++++++++++++++++++++++++ precompiles/erc20/setup_test.go | 63 + precompiles/erc20/tx_test.go | 262 +++ precompiles/erc20/utils_test.go | 598 ++++++ 6 files changed, 3877 insertions(+), 76 deletions(-) create mode 100644 precompiles/erc20/integration_test.go create mode 100644 precompiles/erc20/setup_test.go create mode 100644 precompiles/erc20/tx_test.go create mode 100644 precompiles/erc20/utils_test.go diff --git a/go.mod b/go.mod index 693a2d38..82cde197 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.22.8 require ( cosmossdk.io/api v0.7.6 - cosmossdk.io/client/v2 v2.0.0-beta.5 + cosmossdk.io/client/v2 v2.0.0-beta.7 cosmossdk.io/collections v0.4.0 cosmossdk.io/core v0.11.1 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.5.0 - cosmossdk.io/math v1.4.0 + cosmossdk.io/math v1.5.0 cosmossdk.io/simapp v0.0.0-20240805084742-3fc80745eef2 cosmossdk.io/store v1.1.1 cosmossdk.io/tools/confix v0.1.2 @@ -18,7 +18,7 @@ require ( cosmossdk.io/x/tx v0.13.7 cosmossdk.io/x/upgrade v0.1.4 github.com/cometbft/cometbft v0.38.15 - github.com/cosmos/cosmos-db v1.1.0 + github.com/cosmos/cosmos-db v1.1.1 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.11 github.com/cosmos/gogoproto v1.7.0 @@ -30,16 +30,18 @@ require ( github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/onsi/ginkgo/v2 v2.22.2 + github.com/onsi/gomega v1.36.2 github.com/realio-tech/multi-staking-module v0.0.0-00010101000000-000000000000 - github.com/spf13/cast v1.7.0 + github.com/spf13/cast v1.7.1 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 - golang.org/x/sync v0.9.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 - google.golang.org/grpc v1.68.0 - google.golang.org/protobuf v1.35.2 + golang.org/x/sync v0.10.0 + google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 + google.golang.org/grpc v1.69.2 + google.golang.org/protobuf v1.36.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -47,7 +49,7 @@ require ( cloud.google.com/go v0.115.0 // indirect cloud.google.com/go/auth v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.1.9 // indirect cloud.google.com/go/storage v1.41.0 // indirect cosmossdk.io/depinject v1.1.0 // indirect @@ -80,6 +82,7 @@ require ( github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -123,6 +126,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect @@ -134,6 +138,7 @@ require ( github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect @@ -157,7 +162,7 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.3.1 // indirect + github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect @@ -169,7 +174,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/linxGnu/grocksdb v1.9.2 // indirect + github.com/linxGnu/grocksdb v1.9.8 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -224,22 +229,23 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.29.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.28.0 // indirect google.golang.org/api v0.186.0 // indirect google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -255,10 +261,10 @@ replace ( // use Evmos geth fork github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc4 - github.com/evmos/os => github.com/evmos/os v0.0.0-20250108125741-e95afb000453 + github.com/evmos/os => github.com/evmos/os v0.0.0-20250130185216-d2cab8abc34d // use Realio sdk v0.46.11-realio-4 // github.com/cosmos/cosmos-sdk => github.com/realiotech/cosmos-sdk v0.46.11-realio-4 - github.com/evmos/os/example_chain => github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee + github.com/evmos/os/example_chain => github.com/evmos/os/example_chain v0.0.0-20250130185216-d2cab8abc34d // github.com/realio-tech/multi-staking-module => ../multi-staking // github.com/evmos/os => ../evmos-os diff --git a/go.sum b/go.sum index 1cb84b49..2bea430f 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -188,8 +188,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.6 h1:PC20PcXy1xYKH2KU4RMurVoFjjKkCgYRbVAD4PdqUuY= cosmossdk.io/api v0.7.6/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= -cosmossdk.io/client/v2 v2.0.0-beta.5 h1:0LVv3nEByn//hFDIrYLs2WvsEU3HodOelh4SDHnA/1I= -cosmossdk.io/client/v2 v2.0.0-beta.5/go.mod h1:4p0P6o0ro+FizakJUYS9SeM94RNbv0thLmkHRw5o5as= +cosmossdk.io/client/v2 v2.0.0-beta.7 h1:O0PfZL5kC3Sp54wZASLNihQ612Gd6duMp11aM9wawNg= +cosmossdk.io/client/v2 v2.0.0-beta.7/go.mod h1:TzwwrzeK+AfSVSESVEIOYO/9xuCh1fPv0HgeocmfVnM= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= cosmossdk.io/core v0.11.1 h1:h9WfBey7NAiFfIcUhDVNS503I2P2HdZLebJlUIs8LPA= @@ -200,8 +200,8 @@ cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= cosmossdk.io/log v1.5.0 h1:dVdzPJW9kMrnAYyMf1duqacoidB9uZIl+7c6z0mnq0g= cosmossdk.io/log v1.5.0/go.mod h1:Tr46PUJjiUthlwQ+hxYtUtPn4D/oCZXAkYevBeh5+FI= -cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= -cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= +cosmossdk.io/math v1.5.0 h1:sbOASxee9Zxdjd6OkzogvBZ25/hP929vdcYcBJQbkLc= +cosmossdk.io/math v1.5.0/go.mod h1:AAwwBmUhqtk2nlku174JwSll+/DepUXW3rWIXN5q+Nw= cosmossdk.io/simapp v0.0.0-20240805084742-3fc80745eef2 h1:f2zS+kpAqxGEbY1xHUK7ytfKeCVkmu89FMYGAK+FbYA= cosmossdk.io/simapp v0.0.0-20240805084742-3fc80745eef2/go.mod h1:prWoljZuPhMPxw7Xtc7FhceNtg6hSbla9S5GreyfM58= cosmossdk.io/tools/confix v0.1.2 h1:2hoM1oFCNisd0ltSAAZw2i4ponARPmlhuNu3yy0VwI4= @@ -364,6 +364,8 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= @@ -394,8 +396,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= -github.com/cosmos/cosmos-db v1.1.0 h1:KLHNVQ73h7vawXTpj9UJ7ZR2IXv51tsEHkQJJ9EBDzI= -github.com/cosmos/cosmos-db v1.1.0/go.mod h1:t7c4A6cfGdpUwwVxrQ0gQLeRQqGUBJu0yvE4F/26REg= +github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNCM= +github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.50.11 h1:LxR1aAc8kixdrs3itO+3a44sFoc+vjxVAOyPFx22yjk= @@ -501,10 +503,10 @@ github.com/evmos/cosmos-sdk/store v0.0.0-20240718141609-414cbd051fbe h1:CKvjP3Cc github.com/evmos/cosmos-sdk/store v0.0.0-20240718141609-414cbd051fbe/go.mod h1:Bm6h8ZkYgVTytHK5vhHOMKw9OHyiumm3b1UbkYIJ/Ug= github.com/evmos/go-ethereum v1.10.26-evmos-rc4 h1:vwDVMScuB2KSu8ze5oWUuxm6v3bMUp6dL3PWvJNJY+I= github.com/evmos/go-ethereum v1.10.26-evmos-rc4/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= -github.com/evmos/os v0.0.0-20250108125741-e95afb000453 h1:ZwRIMj0RPxk37fXeHh6wRJr3S7tj5fxWG5Jf3ZyMCus= -github.com/evmos/os v0.0.0-20250108125741-e95afb000453/go.mod h1:BFkZxXO384jHZ++ETF7Vmh82MGNQ2wzzQV7LOA9cJJs= -github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee h1:BZpePPAM2zYn8P9EkU14K0p4TTgwEQJLaQG4FjNh99Q= -github.com/evmos/os/example_chain v0.0.0-20241002122822-02a9121016ee/go.mod h1:+SPMqw9wtbWO3jG02uLbLtVVjMHBldmXTN51kxbWqJ8= +github.com/evmos/os v0.0.0-20250130185216-d2cab8abc34d h1:EAHT7l/YzzrbEPl2C8iQz5W7zDwQ8cYKmHsXzI3Uefw= +github.com/evmos/os v0.0.0-20250130185216-d2cab8abc34d/go.mod h1:zgs0dJ8M4AQtRDtGNCa6h2XqQDh4a5ar4Za+B80YJwc= +github.com/evmos/os/example_chain v0.0.0-20250130185216-d2cab8abc34d h1:4K8xoiN5ikYkcbZIxrxmzFtG1y6ZkT2OJqKdvHqU0MM= +github.com/evmos/os/example_chain v0.0.0-20250130185216-d2cab8abc34d/go.mod h1:NyqEZcwpY6sa+Re11S/Q1Q1cnfyy7I9YmSS0Pi72WtU= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= @@ -674,8 +676,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -781,8 +783,8 @@ github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= -github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -858,8 +860,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linxGnu/grocksdb v1.9.2 h1:O3mzvO0wuzQ9mtlHbDrShixyVjVbmuqTjFrzlf43wZ8= -github.com/linxGnu/grocksdb v1.9.2/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= +github.com/linxGnu/grocksdb v1.9.8 h1:vOIKv9/+HKiqJAElJIEYv3ZLcihRxyP7Suu/Mu8Dxjs= +github.com/linxGnu/grocksdb v1.9.8/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -941,14 +943,14 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -1078,8 +1080,8 @@ github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIK github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= @@ -1182,14 +1184,16 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1220,8 +1224,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1321,8 +1325,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1364,8 +1368,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1465,13 +1469,13 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1482,8 +1486,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1550,8 +1554,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1730,10 +1734,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1775,8 +1779,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= -google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1793,8 +1797,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/precompiles/erc20/integration_test.go b/precompiles/erc20/integration_test.go new file mode 100644 index 00000000..27a6efaa --- /dev/null +++ b/precompiles/erc20/integration_test.go @@ -0,0 +1,2868 @@ +package erc20 + +import ( + "fmt" + "math/big" + "slices" + "strings" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/contracts" + auth "github.com/evmos/os/precompiles/authorization" + "github.com/evmos/os/precompiles/erc20" + "github.com/evmos/os/precompiles/erc20/testdata" + "github.com/evmos/os/precompiles/testutil" + testconstants "github.com/evmos/os/testutil/constants" + "github.com/evmos/os/testutil/integration/os/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/evmos/os/testutil/integration/os/keyring" + "github.com/evmos/os/testutil/integration/os/network" + integrationutils "github.com/evmos/os/testutil/integration/os/utils" + utiltx "github.com/evmos/os/testutil/tx" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/evmos/os/x/evm/core/vm" + evmtypes "github.com/evmos/os/x/evm/types" + + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/ginkgo/v2" + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/gomega" +) + +var is *IntegrationTestSuite + +type IntegrationTestSuite struct { + // NOTE: we have to use the Unit testing network because we access a keeper in a setup function. + // Might adjust this on a follow-up PR. + network *network.UnitTestNetwork + handler grpc.Handler + keyring keyring.Keyring + factory factory.TxFactory + + bondDenom string + tokenDenom string // erc20 precompile denom with supply + tokenDenomTwo string // erc20 precompile denom with zero supply + + precompile *erc20.Precompile // erc20 precompile with supply + precompileTwo *erc20.Precompile // erc20 precompile with zero supply +} + +func (is *IntegrationTestSuite) SetupTest() { + is.tokenDenom = "xmpl" + is.tokenDenomTwo = "xmpl2" + + keys := keyring.New(2) + genesis := integrationutils.CreateGenesisWithTokenPairs(keys, is.tokenDenom, is.tokenDenomTwo) + + nw := network.NewUnitTestNetwork( + network.WithPreFundedAccounts(keys.GetAllAccAddrs()...), + network.WithOtherDenoms([]string{is.tokenDenom}), // add balance (supply) to is.tokenDenom + network.WithCustomGenesis(genesis), + ) + gh := grpc.NewIntegrationHandler(nw) + tf := factory.New(nw, gh) + + is.network = nw + is.factory = tf + is.handler = gh + is.keyring = keys + + is.bondDenom = nw.GetBaseDenom() + + erc20Gen := genesis[erc20types.ModuleName].(*erc20types.GenesisState) + is.precompile = is.setupERC20Precompile(is.tokenDenom, erc20Gen.TokenPairs) + is.precompileTwo = is.setupERC20Precompile(is.tokenDenomTwo, erc20Gen.TokenPairs) +} + +func TestIntegrationSuite(t *testing.T) { + is = new(IntegrationTestSuite) + + // Run Ginkgo integration tests + RegisterFailHandler(Fail) + RunSpecs(t, "ERC20 Extension Suite") +} + +var ( + revertContractAddr common.Address + gasLimit = uint64(5000000) + gasPrice = big.NewInt(800_000_000) +) + +var _ = Describe("ERC20 Extension -", func() { + var ( + // contractsData holds the addresses and ABIs for the different + // contract instances that are subject to testing here. + contractsData ContractsData + + allowanceCallerContract evmtypes.CompiledContract + revertCallerContract evmtypes.CompiledContract + erc20MinterV5Contract evmtypes.CompiledContract + + execRevertedCheck testutil.LogCheckArgs + failCheck testutil.LogCheckArgs + passCheck testutil.LogCheckArgs + ) + + BeforeEach(func() { + is.SetupTest() + + var err error + allowanceCallerContract, err = testdata.LoadERC20AllowanceCaller() + Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 allowance caller contract") + + erc20MinterV5Contract, err = testdata.LoadERC20MinterV5Contract() + Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 minter contract") + + revertCallerContract, err = testdata.LoadERC20TestCaller() + Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 allowance caller contract") + + sender := is.keyring.GetKey(0) + contractAddr, err := is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: allowanceCallerContract, + // NOTE: we're passing the precompile address to the constructor because that initiates the contract + // to make calls to the correct ERC20 precompile. + ConstructorArgs: []interface{}{is.precompile.Address()}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // commit the changes to update state (account nonce mostly) + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + + contractAddrTokenTwo, err := is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: allowanceCallerContract, + // NOTE: we're passing the precompile address to the constructor because that initiates the contract + // to make calls to the correct ERC20 precompile. + ConstructorArgs: []interface{}{is.precompileTwo.Address()}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // commit the changes to update state (account nonce mostly) + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + + erc20MinterBurnerAddr, err := is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: contracts.ERC20MinterBurnerDecimalsContract, + ConstructorArgs: []interface{}{ + "Xmpl", "Xmpl", uint8(6), + }, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter burner contract") + + // commit the changes to update state (account nonce mostly) + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + + ERC20MinterV5Addr, err := is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: erc20MinterV5Contract, + ConstructorArgs: []interface{}{ + "Xmpl", "Xmpl", + }, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter contract") + + // commit the changes to update state (account nonce mostly) + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + + erc20MinterV5CallerAddr, err := is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: allowanceCallerContract, + ConstructorArgs: []interface{}{ + ERC20MinterV5Addr, + }, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter caller contract") + + // commit the changes to update state (account nonce mostly) + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + + // Store the data of the deployed contracts + contractsData = ContractsData{ + ownerPriv: sender.Priv, + contractData: map[CallType]ContractData{ + directCall: { + Address: is.precompile.Address(), + ABI: is.precompile.ABI, + }, + directCallToken2: { + Address: is.precompileTwo.Address(), + ABI: is.precompileTwo.ABI, + }, + contractCall: { + Address: contractAddr, + ABI: allowanceCallerContract.ABI, + }, + contractCallToken2: { + Address: contractAddrTokenTwo, + ABI: allowanceCallerContract.ABI, + }, + erc20Call: { + Address: erc20MinterBurnerAddr, + ABI: contracts.ERC20MinterBurnerDecimalsContract.ABI, + }, + erc20V5Call: { + Address: ERC20MinterV5Addr, + ABI: erc20MinterV5Contract.ABI, + }, + erc20V5CallerCall: { + Address: erc20MinterV5CallerAddr, + ABI: allowanceCallerContract.ABI, + }, + }, + } + + failCheck = testutil.LogCheckArgs{ABIEvents: is.precompile.Events} + execRevertedCheck = failCheck.WithErrContains("execution reverted") + passCheck = failCheck.WithExpPass(true) + + erc20Params := is.network.App.Erc20Keeper.GetParams(is.network.GetContext()) + Expect(len(erc20Params.NativePrecompiles)).To(Equal(1)) + Expect(common.HexToAddress(erc20Params.NativePrecompiles[0])).To(Equal(common.HexToAddress(testconstants.WEVMOSContractMainnet))) + + revertContractAddr, err = is.factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: revertCallerContract, + // NOTE: we're passing the precompile address to the constructor because that initiates the contract + // to make calls to the correct ERC20 precompile. + ConstructorArgs: []interface{}{common.HexToAddress(erc20Params.NativePrecompiles[0])}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy reverter contract") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to advance block") + }) + + Context("basic functionality -", func() { + When("sending tokens to contract", func() { + It("it should return error", func() { + sender := is.keyring.GetKey(0) + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + + // Fund account with some tokens + is.fundWithTokens(directCall, contractsData, sender.Addr, fundCoins) + + // Taking custom args from the table entry + txArgs := evmtypes.EvmTxArgs{} + txArgs.Amount = big.NewInt(int64(1000)) + precompileAddress := is.precompile.Address() + txArgs.To = &precompileAddress + + _, err := is.factory.ExecuteEthTx(sender.Priv, txArgs) + // Currently, this check pass because the erc20 precompile does + // not expose a fallback handler. Adding a fallback handler, the + // test should pass again because of the check on the message + // value in the precompile before the setup. + Expect(err.Error()).To(ContainSubstring(vm.ErrExecutionReverted.Error()), "precompile should not accept transfers") + }, + ) + }) + When("transferring tokens", func() { + DescribeTable("it should transfer tokens to a non-existing address", func(callType CallType, expGasUsedLowerBound int64, expGasUsedUpperBound int64) { + sender := is.keyring.GetKey(0) + receiver := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) + senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoins[0].Amount.BigInt()) + + transferCheck := passCheck.WithExpEvents(erc20.EventTypeTransfer) + + res, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: sender.AccAddr, expCoins: senderInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + + Expect(res.GasUsed > expGasUsedLowerBound).To(BeTrue(), "expected different gas used") + Expect(res.GasUsed < expGasUsedUpperBound).To(BeTrue(), "expected different gas used") + }, + // FIXME: The gas used on the precompile is much higher than on the EVM + Entry(" - direct call", directCall, int64(3_021_000), int64(3_022_000)), + Entry(" - through erc20 contract", erc20Call, int64(54_000), int64(54_500)), + Entry(" - through erc20 v5 contract", erc20V5Call, int64(52_000), int64(52_200)), + ) + + DescribeTable("it should transfer tokens to an existing address", func(callType CallType) { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetKey(1) + fundCoinsSender := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + fundCoinsReceiver := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 500)} + transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) + + // Fund accounts with some tokens + receiverInitialAmt := is.fundWithTokens(callType, contractsData, receiver.Addr, fundCoinsReceiver) + receiverInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, receiverInitialAmt)} + + senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoinsSender) + senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver.Addr, transferCoin.Amount.BigInt()) + + transferCheck := passCheck.WithExpEvents(erc20.EventTypeTransfer) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: sender.AccAddr, expCoins: senderInitialBalance.Sub(transferCoin)}, + {address: receiver.AccAddr, expCoins: receiverInitialBalance.Add(transferCoin)}, + }, + ) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because transferring using a caller contract + // is only supported through transferFrom method. + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should return an error trying to call from a smart contract", func(callType CallType) { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) + + // Fund account with some tokens + is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoin.Amount.BigInt()) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + // NOTE: we are not passing the direct call here because this test is specific to the contract calls + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should return an error if the sender does not have enough tokens", func(callType CallType) { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + + // Fund account with some tokens + senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) + senderInitialBalance := sdk.NewCoin(is.tokenDenom, senderInitialAmt) + + transferCoin := senderInitialBalance.Add(sdk.NewInt64Coin(is.tokenDenom, 100)) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoin.Amount.BigInt()) + + insufficientBalanceCheck := failCheck.WithErrContains( + erc20.ErrTransferAmountExceedsBalance.Error(), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientBalanceCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because this test is for direct calls only + + Entry(" - through erc20 contract", erc20Call), + // // TODO: The ERC20 V5 contract is raising the ERC-6093 standardized error which we are not as of yet + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + When("calling reverter contract", func() { + Context("in a direct call to the WEVMOS contract", func() { + var ( + args factory.CallArgs + txArgs evmtypes.EvmTxArgs + ) + BeforeEach(func() { + args = factory.CallArgs{ + ContractABI: revertCallerContract.ABI, + } + + txArgs = evmtypes.EvmTxArgs{ + To: &revertContractAddr, + GasLimit: gasLimit, + GasPrice: gasPrice, + } + }) + It("should transfer tokens", func() { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetKey(1) + amountToSend := big.NewInt(100) + + balRes, err := is.handler.GetBalanceFromBank(receiver.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + denomInitialBalance := balRes.Balance + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderInitialBalance := balRes.Balance + + args.MethodName = "transferWithRevert" + args.Args = []interface{}{ + receiver.Addr, + amountToSend, + false, + false, + } + txArgs.Amount = amountToSend + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + ) + res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) + Expect(err).To(BeNil()) + Expect(is.network.NextBlock()).To(BeNil()) + fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) + + Expect(is.network.NextBlock()).ToNot(HaveOccurred(), "failed to advance block") + + balRes, err = is.handler.GetBalanceFromBank(receiver.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + denomFinalBalance := balRes.Balance + Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(amountToSend.Int64())))) + + balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + contractBalance := balRes.Balance + Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) + + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderFinalBalance := balRes.Balance + denomSpent := fees.Add(math.NewIntFromBigInt(amountToSend)) + Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) + }, + ) + DescribeTable("it should revert token transfer from the WEVMOS contract", func(before bool, after bool) { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + amountToSend := big.NewInt(100) + balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomInitialBalance := balRes.Balance + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderInitialBalance := balRes.Balance + + args.MethodName = "transferWithRevert" + args.Args = []interface{}{ + receiver, + amountToSend, + before, + after, + } + txArgs.Amount = amountToSend + + res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, execRevertedCheck) + Expect(err).To(BeNil()) + Expect(is.network.NextBlock()).To(BeNil()) + + fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) + + // contract balance should remain unchanged + balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomFinalBalance := balRes.Balance + Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount)) + + balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + contractBalance := balRes.Balance + Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) + + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderFinalBalance := balRes.Balance + Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(fees))) + }, + Entry("revert before", true, false), + Entry("revert after", false, true), + ) + It("it should send token transfer and send from WEVMOS contract", func() { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + totalToSend := int64(350) + balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomInitialBalance := balRes.Balance + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderInitialBalance := balRes.Balance + + args.MethodName = "testTransferAndSend" + args.Args = []interface{}{ + receiver, + big.NewInt(100), + big.NewInt(100), + big.NewInt(150), + false, + false, + } + txArgs.Amount = big.NewInt(totalToSend) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + ) + res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) + Expect(err).To(BeNil()) + Expect(is.network.NextBlock()).To(BeNil()) + fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) + + // contract balance should remain unchanged + balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomFinalBalance := balRes.Balance + Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(totalToSend)))) + + balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + contractBalance := balRes.Balance + Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) + + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderFinalBalance := balRes.Balance + denomSpent := fees.AddRaw(totalToSend) + Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) + }, + ) + DescribeTable("it should revert token transfer and send from WEVMOS contract", func(before bool, after bool) { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomInitialBalance := balRes.Balance + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderInitialBalance := balRes.Balance + + args.MethodName = "testTransferAndSend" + args.Args = []interface{}{ + receiver, + big.NewInt(100), + big.NewInt(100), + big.NewInt(100), + before, + after, + } + txArgs.Amount = big.NewInt(300) + + res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, execRevertedCheck) + Expect(err).To(BeNil()) + Expect(is.network.NextBlock()).To(BeNil()) + fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) + + // contract balance should remain unchanged + balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomFinalBalance := balRes.Balance + Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount)) + + balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + contractBalance := balRes.Balance + Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) + + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderFinalBalance := balRes.Balance + Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(fees))) + }, + Entry("revert before", true, false), + Entry("revert after", false, true), + ) + It("revert when transfer with try", func() { + sender := is.keyring.GetKey(0) + receiver := is.keyring.GetAddr(1) + amountToSend := big.NewInt(100) + balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomInitialBalance := balRes.Balance + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderInitialBalance := balRes.Balance + + args.MethodName = "transfersWithTry" + args.Args = []interface{}{ + receiver, + amountToSend, + amountToSend, + } + txArgs.Amount = big.NewInt(200) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + ) + res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) + Expect(err).To(BeNil()) + Expect(is.network.NextBlock()).To(BeNil()) + fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) + + balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + denomFinalBalance := balRes.Balance + Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(amountToSend.Int64())))) + + balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) + Expect(err).To(BeNil()) + contractBalance := balRes.Balance + Expect(contractBalance.Amount.Int64()).To(Equal(amountToSend.Int64())) + + balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) + Expect(err).To(BeNil()) + senderFinalBalance := balRes.Balance + denomSpent := fees.AddRaw(amountToSend.Int64() + amountToSend.Int64()) + Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) + }) + }) + }) + + When("transferring tokens from another account", func() { + Context("in a direct call to the token contract", func() { + DescribeTable("it should transfer tokens from another account with a sufficient approval set", func(callType CallType) { + owner := is.keyring.GetKey(0) + spender := is.keyring.GetKey(1) + receiver := utiltx.GenerateAddress() + + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) + ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} + + // Set allowance + is.setupSendAuthzForContract(callType, contractsData, spender.Addr, owner.Priv, transferCoins) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoins[0].Amount.BigInt(), + ) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + auth.EventTypeApproval, + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to the chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + + // Check that the allowance was removed since we authorized only the transferred amount + is.ExpectNoSendAuthzForContract( + callType, contractsData, + spender.Addr, owner.Addr, + ) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because this test is for direct calls only + + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + When("the spender is the same as the sender", func() { + It("should transfer funds without the need for an approval when calling the EVM extension", func() { + owner := is.keyring.GetKey(0) + spender := owner + receiver := utiltx.GenerateAddress() + + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(directCall, contractsData, owner.Addr, fundCoins) + ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + directCall, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoins[0].Amount.BigInt(), + ) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, auth.EventTypeApproval, + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) + is.ExpectBalancesForContract( + directCall, contractsData, + []ExpectedBalance{ + {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + }) + + DescribeTable("it should transfer funds from the own account in case sufficient approval is set", func(callType CallType) { + owner := is.keyring.GetKey(0) + receiver := utiltx.GenerateAddress() + + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) + ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} + + // NOTE: Here we set up the allowance using the contract calls instead of the helper utils, + // because the `MsgGrant` used there doesn't allow the sender to be the same as the spender, + // but the ERC20 contracts do. + txArgs, approveArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.ApproveMethod, + owner.Addr, transferCoins[0].Amount.BigInt(), + ) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, _, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // create new block to commit the changes in the state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectSendAuthzForContract( + callType, contractsData, + owner.Addr, owner.Addr, transferCoins, + ) + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoins[0].Amount.BigInt(), + ) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + auth.EventTypeApproval, + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + + // Check that the allowance was removed since we authorized only the transferred amount + // FIXME: This is not working for the case where we transfer from the own account + // because the allowance is not removed on the SDK side. + is.ExpectNoSendAuthzForContract( + callType, contractsData, + owner.Addr, owner.Addr, + ) + }, + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + DescribeTable("it should return an error when the spender does not have enough allowance", func(callType CallType) { + owner := is.keyring.GetKey(0) + spender := is.keyring.GetKey(1) + receiver := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + transferCoin := sdk.NewInt64Coin(is.tokenDenom, 200) + + // Fund account with some tokens + is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) + // Set allowance + is.setupSendAuthzForContract( + callType, contractsData, + spender.Addr, owner.Priv, authzCoins, + ) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoin.Amount.BigInt(), + ) + + insufficientAllowanceCheck := failCheck.WithErrContains(erc20.ErrInsufficientAllowance.Error()) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, insufficientAllowanceCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because this test case only covers direct calls + + Entry(" - through erc20 contract", erc20Call), + + // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should return an error if there is no allowance set", func(callType CallType) { + sender := is.keyring.GetKey(0) + from := is.keyring.GetKey(1) + receiver := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) + + // Fund account with some tokens + is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + from.Addr, receiver, transferCoin.Amount.BigInt(), + ) + + insufficientAllowanceCheck := failCheck.WithErrContains( + erc20.ErrInsufficientAllowance.Error(), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientAllowanceCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because this test case only covers direct calls + + Entry(" - through erc20 contract", erc20Call), + + // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should return an error if the sender does not have enough tokens", func(callType CallType) { + sender := is.keyring.GetKey(0) + from := is.keyring.GetKey(1) + receiver := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + + // Fund account with some tokens + senderInitialAmt := is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) + senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} + transferCoins := senderInitialBalance.Add(sdk.NewInt64Coin(is.tokenDenom, 100)) + + // Set allowance + is.setupSendAuthzForContract( + callType, contractsData, + sender.Addr, from.Priv, transferCoins, + ) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferFromMethod, from.Addr, receiver, transferCoins[0].Amount.BigInt()) + + insufficientBalanceCheck := failCheck.WithErrContains( + erc20.ErrTransferAmountExceedsBalance.Error(), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientBalanceCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the contract call here because this test case only covers direct calls + + Entry(" - through erc20 contract", erc20Call), + + // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + Context("in a call from another smart contract to the token contract", func() { + DescribeTable("it should transfer tokens with a sufficient approval set", func(callType CallType) { + owner := is.keyring.GetKey(0) + receiver := utiltx.GenerateAddress() + fundCoin := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // NOTE: the spender will be the contract address + spender := contractsData.GetContractData(callType).Address + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoin) + ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} + + // Set allowance + is.setupSendAuthzForContract( + callType, contractsData, + spender, owner.Priv, transferCoins, + ) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoins[0].Amount.BigInt(), + ) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + auth.EventTypeApproval, + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + + // Check that the allowance was removed since we authorized only the transferred amount + is.ExpectNoSendAuthzForContract( + callType, contractsData, + spender, owner.Addr, + ) + }, + // Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + // NOTE: we are not passing the erc20 contract call here because this is supposed to + // test external contract calls + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should transfer funds with a sufficient allowance and triggered from another account", func(callType CallType) { + msgSender := is.keyring.GetKey(0) + owner := is.keyring.GetKey(1) + receiver := utiltx.GenerateAddress() + + // NOTE: the spender will be the contract address + spender := contractsData.GetContractData(callType).Address + + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) + ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} + + // Set allowance + is.setupSendAuthzForContract( + callType, contractsData, + spender, owner.Priv, transferCoins, + ) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + owner.Addr, receiver, transferCoins[0].Amount.BigInt(), + ) + + transferCheck := passCheck.WithExpEvents( + erc20.EventTypeTransfer, + auth.EventTypeApproval, + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(msgSender.Priv, txArgs, transferArgs, transferCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) + is.ExpectBalancesForContract( + callType, contractsData, + []ExpectedBalance{ + {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, + {address: receiver.Bytes(), expCoins: transferCoins}, + }, + ) + + // Check that the allowance was removed since we authorized only the transferred amount + is.ExpectNoSendAuthzForContract( + callType, contractsData, + spender, owner.Addr, + ) + }, + // NOTE: we are not passing the direct call here because this test is specific to the contract calls + + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should return an error when the spender does not have enough allowance", func(callType CallType) { + from := is.keyring.GetKey(0) + receiver := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 400)} + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + transferCoin := sdk.NewInt64Coin(is.tokenDenom, 300) + + // NOTE: the spender will be the contract address + spender := contractsData.GetContractData(callType).Address + + // Fund account with some tokens + is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) + + // Set allowance + is.setupSendAuthzForContract(callType, contractsData, spender, from.Priv, authzCoins) + + // Transfer tokens + txArgs, transferArgs := is.getTxAndCallArgs( + callType, contractsData, + erc20.TransferFromMethod, + from.Addr, receiver, transferCoin.Amount.BigInt(), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(from.Priv, txArgs, transferArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + // NOTE: we are not passing the direct call here because this test is for contract calls only + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + }) + }) + + When("querying balance", func() { + DescribeTable("it should return an existing balance", func(callType CallType) { + sender := is.keyring.GetKey(0) + addedAmt := big.NewInt(100) + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, addedAmt.Int64())} + + // Fund account with some tokens + ownerInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) + + // Query the balance + txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, sender.Addr) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var balance *big.Int + err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(math.NewIntFromBigInt(balance)).To(Equal(ownerInitialAmt), "expected different balance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should return zero if balance only exists for other tokens", func(callType CallType) { + sender := is.keyring.GetKey(0) + address := utiltx.GenerateAddress() + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 100)} + + // Fund account with some tokens + err := is.factory.FundAccount(is.keyring.GetKey(0), sender.AccAddr, fundCoins) + Expect(err).ToNot(HaveOccurred(), "failed to fund account") + Expect(is.network.NextBlock()).To(BeNil()) + + // Query the balance + txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, address) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var balance *big.Int + err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(balance.Int64()).To(BeZero(), "expected zero balance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contracts + // only support the actual token denomination and don't know of other balances. + ) + + DescribeTable("it should return zero if the account does not exist", func(callType CallType) { + sender := is.keyring.GetKey(0) + address := utiltx.GenerateAddress() + + // Query the balance + txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, address) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var balance *big.Int + err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(balance.Int64()).To(BeZero(), "expected zero balance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + }) + + When("querying allowance", func() { + DescribeTable("it should return an existing allowance", func(callType CallType) { + grantee := utiltx.GenerateAddress() + granter := is.keyring.GetKey(0) + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + is.setupSendAuthzForContract(callType, contractsData, grantee, granter.Priv, authzCoins) + + txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance).To(Equal(authzCoins[0].Amount.BigInt()), "expected different allowance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + When("querying the allowance for the own address", func() { + // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, + // querying allowance and reducing allowance on a transferFrom transaction is not possible without + // changes to the Cosmos SDK. + // + // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 + It("should return the maxUint256 value when calling the EVM extension", func() { + grantee := is.keyring.GetAddr(0) + granter := is.keyring.GetKey(0) + + txArgs, allowanceArgs := is.getTxAndCallArgs(directCall, contractsData, auth.AllowanceMethod, grantee, grantee) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance).To(Equal(abi.MaxUint256), "expected different allowance") + }) + + // NOTE: Since it's possible to set an allowance for the own address with the Solidity ERC20 contracts, + // we describe this case here for completion purposes, to describe the difference in behavior. + DescribeTable("should return the actual allowance value when calling the ERC20 contract", func(callType CallType) { + granter := is.keyring.GetKey(0) + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + is.setupSendAuthzForContract(callType, contractsData, granter.Addr, granter.Priv, authzCoins) + + txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, granter.Addr) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance).To(Equal(authzCoins.AmountOf(is.tokenDenom).BigInt()), "expected different allowance") + }, + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + DescribeTable("it should return zero if no allowance exists", func(callType CallType) { + grantee := is.keyring.GetAddr(1) + granter := is.keyring.GetKey(0) + + txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should return zero if an allowance exists for other tokens", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 100)} + + is.setupSendAuthz(grantee.AccAddr, granter.Priv, authzCoins) + + txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee.Addr) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("it should return zero if the account does not exist", func(callType CallType) { + grantee := utiltx.GenerateAddress() + granter := is.keyring.GetKey(0) + + txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var allowance *big.Int + err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + }) + + When("querying total supply", func() { + DescribeTable("it should return the total supply", func(callType CallType) { + sender := is.keyring.GetKey(0) + expSupply := big.NewInt(100) + fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, expSupply.Int64())} + + // Fund account with some tokens + is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) + + // if is native coin, get expSupply from the bank mod + if slices.Contains(nativeCallTypes, callType) { + qc := is.network.GetBankClient() + qRes, err := qc.SupplyOf(is.network.GetContext(), &banktypes.QuerySupplyOfRequest{Denom: is.tokenDenom}) + Expect(err).To(BeNil()) + Expect(qRes).NotTo(BeNil()) + expSupply = qRes.Amount.Amount.BigInt() + } + + // Query the balance + txArgs, supplyArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TotalSupplyMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, supplyArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var supply *big.Int + err = is.precompile.UnpackIntoInterface(&supply, erc20.TotalSupplyMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(supply).To(Equal(expSupply), "expected different supply") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should return zero if no tokens exist", func(callType CallType) { + sender := is.keyring.GetKey(0) + txArgs, supplyArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TotalSupplyMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, supplyArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var supply *big.Int + err = is.precompile.UnpackIntoInterface(&supply, erc20.TotalSupplyMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(supply.Int64()).To(BeZero(), "expected zero supply") + }, + Entry(" - direct call", directCallToken2), + Entry(" - through contract", contractCallToken2), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + }) + + When("approving an allowance", func() { + Context("in a call to the token contract", func() { + DescribeTable("it should approve an allowance", func(callType CallType) { + grantee := is.keyring.GetKey(0) + granter := is.keyring.GetKey(1) + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, transferCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter.Addr, transferCoins, + ) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should add a new spend limit to an existing allowance with a different token", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} + tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // set up a previous authorization + is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check allowance contains both spend limits + is.expectSendAuthz(grantee.AccAddr, granter.AccAddr, bondCoins.Add(tokenCoins...)) + }, + Entry(" - direct call", directCall), + + // NOTE 2: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("it should set the new spend limit for an existing allowance with the same token", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} + tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + doubleTokenCoin := sdk.NewInt64Coin(is.tokenDenom, 200) + + // set up a previous authorization + is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins.Add(doubleTokenCoin)) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check allowance contains both spend limits + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, bondCoins.Add(tokenCoins...)) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should remove the token from the spend limit of an existing authorization when approving zero", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} + tokenCoin := sdk.NewInt64Coin(is.tokenDenom, 100) + + // set up a previous authorization + is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins.Add(tokenCoin)) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + // Check allowance contains only the spend limit in network denomination + is.expectSendAuthz(grantee.AccAddr, granter.AccAddr, bondCoins) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("it should delete the authorization when approving zero with no other spend limits", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // set up a previous authorization + is.setupSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Priv, tokenCoins) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check allowance was deleted + is.expectNoSendAuthz(grantee.AccAddr, granter.AccAddr) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("it should no-op if approving 0 and no allowance exists", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + + // We are expecting an approval to be made, but no authorization stored since it's 0 + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check still no authorization exists + is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + When("the grantee is the same as the granter", func() { + // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, + // querying allowance and reducing allowance on a transferFrom transaction is not possible without + // changes to the Cosmos SDK. + // + // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 + It("should return an error when calling the EVM extension", func() { + grantee := is.keyring.GetKey(0) + granter := is.keyring.GetKey(0) + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs( + directCall, contractsData, + auth.ApproveMethod, + grantee.Addr, authzCoins[0].Amount.BigInt(), + ) + + spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, spenderIsOwnerCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectNoSendAuthzForContract( + directCall, contractsData, + grantee.Addr, granter.Addr, + ) + }) + + DescribeTable("it should create an allowance", func(callType CallType) { + grantee := is.keyring.GetKey(0) + granter := is.keyring.GetKey(0) + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.ApproveMethod, + grantee.Addr, authzCoins[0].Amount.BigInt(), + ) + + approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approvalCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter.Addr, authzCoins, + ) + }, + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + DescribeTable("it should return an error if approving 0 and allowance only exists for other tokens", func(callType CallType) { + grantee := is.keyring.GetKey(1) + granter := is.keyring.GetKey(0) + bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} + + // set up a previous authorization + is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + + notFoundCheck := failCheck.WithErrContains( + fmt.Sprintf(erc20.ErrNoAllowanceForToken, is.tokenDenom), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, notFoundCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + }) + + // NOTE: We have to split the tests for contract calls into a separate context because + // when approving through a smart contract, the approval is created between the contract address and the + // grantee, instead of the sender address and the grantee. + Context("in a contract call", func() { + DescribeTable("it should approve an allowance", func(callType CallType) { + sender := is.keyring.GetKey(0) + grantee := is.keyring.GetKey(1) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, transferCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check allowance + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter, transferCoins, + ) + }, + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should set the new spend limit for an existing allowance with the same token", func(callType CallType) { + sender := is.keyring.GetKey(0) + grantee := is.keyring.GetKey(1) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + initialAmount := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + newAmount := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + + // Set up a first approval + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, initialAmount[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + + // Set up a second approval which should overwrite the initial one + txArgs, approveArgs = is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, newAmount[0].Amount.BigInt()) + approveCheck = passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err = is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // Check allowance has been updated + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter, newAmount, + ) + }, + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should delete the authorization when approving zero with no other spend limits", func(callType CallType) { + sender := is.keyring.GetKey(0) + grantee := is.keyring.GetKey(1) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // set up a previous authorization + // + // TODO: refactor using helper + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + + // Approve allowance + txArgs, approveArgs = is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + _, ethRes, err = is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + + // Check allowance was deleted from the keeper / is returning 0 for smart contracts + is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter) + }, + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + DescribeTable("it should no-op if approving 0 and no allowance exists", func(callType CallType) { + sender := is.keyring.GetKey(0) + grantee := is.keyring.GetKey(1) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) + + // We are expecting an approval event to be emitted, but no authorization to be stored + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + // Check still no authorization exists + is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter) + }, + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + + When("the grantee is the same as the granter", func() { + // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, + // querying allowance and reducing allowance on a transferFrom transaction is not possible without + // changes to the Cosmos SDK. + // + // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 + It("should return an error when calling the EVM extension", func() { + callType := contractCall + sender := is.keyring.GetKey(0) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + grantee := granter + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.ApproveMethod, + grantee, authzCoins[0].Amount.BigInt(), + ) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectNoSendAuthzForContract( + callType, contractsData, + grantee, granter, + ) + }) + + DescribeTable("it should create an allowance when calling an ERC20 Solidity contract", func(callType CallType) { + sender := is.keyring.GetKey(0) + granter := contractsData.GetContractData(callType).Address // the granter will be the contract address + grantee := granter + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // Approve allowance + txArgs, approveArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.ApproveMethod, + grantee, authzCoins[0].Amount.BigInt(), + ) + + approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approvalCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee, granter, authzCoins, + ) + }, + Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), + ) + }) + }) + }) + }) + + Context("metadata query -", func() { + Context("for a token without registered metadata", func() { + BeforeEach(func() { + // Deploy ERC20NoMetadata contract for this test + erc20NoMetadataContract, err := testdata.LoadERC20NoMetadataContract() + Expect(err).ToNot(HaveOccurred(), "failed to load contract") + + erc20NoMetadataAddr, err := is.factory.DeployContract( + is.keyring.GetPrivKey(0), + evmtypes.EvmTxArgs{}, + factory.ContractDeploymentData{ + Contract: erc20NoMetadataContract, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // NOTE: update the address but leave the ABI as it is, so that the ABI includes + // the metadata methods but the contract doesn't have them. + contractsData.contractData[erc20Call] = ContractData{ + Address: erc20NoMetadataAddr, + ABI: contracts.ERC20MinterBurnerDecimalsContract.ABI, + } + }) + + DescribeTable("querying the name should return an error", func(callType CallType) { + txArgs, nameArgs := is.getTxAndCallArgs(callType, contractsData, erc20.NameMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, nameArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors + ) + + DescribeTable("querying the symbol should return an error", func(callType CallType) { + txArgs, symbolArgs := is.getTxAndCallArgs(callType, contractsData, erc20.SymbolMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, symbolArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors + ) + + DescribeTable("querying the decimals should return an error", func(callType CallType) { + txArgs, decimalsArgs := is.getTxAndCallArgs(callType, contractsData, erc20.DecimalsMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, decimalsArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors + ) + }) + + Context("for a token with available metadata", func() { + const ( + expSymbol = "Xmpl" + expDecimals = uint8(18) + ) + + var ( + erc20Addr common.Address + expName string + ) + + BeforeEach(func() { + erc20Addr = contractsData.GetContractData(erc20V5Call).Address + expName = erc20types.CreateDenom(erc20Addr.String()) + + // Register ERC20 token pair for this test + tokenPairs, err := integrationutils.RegisterERC20(is.factory, is.network, integrationutils.ERC20RegistrationData{ + Addresses: []string{erc20Addr.Hex()}, + ProposerPriv: is.keyring.GetPrivKey(0), + }) + Expect(err).ToNot(HaveOccurred(), "failed to register ERC20 token") + Expect(tokenPairs).To(HaveLen(1)) + + // overwrite the other precompile with this one, so that the test utils like is.getTxAndCallArgs still work. + is.precompile, err = setupNewERC20PrecompileForTokenPair(is.keyring.GetPrivKey(0), is.network, is.factory, tokenPairs[0]) + Expect(err).ToNot(HaveOccurred(), "failed to set up erc20 precompile") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // update this in the global contractsData + contractsData.contractData[directCall] = ContractData{ + Address: is.precompile.Address(), + ABI: is.precompile.ABI, + } + + // Deploy contract calling the ERC20 precompile + callerAddr, err := is.factory.DeployContract( + is.keyring.GetPrivKey(0), + evmtypes.EvmTxArgs{}, + factory.ContractDeploymentData{ + Contract: allowanceCallerContract, + ConstructorArgs: []interface{}{ + is.precompile.Address(), + }, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + contractsData.contractData[contractCall] = ContractData{ + Address: callerAddr, + ABI: allowanceCallerContract.ABI, + } + }) + + DescribeTable("querying the name should return the name", func(callType CallType) { + txArgs, nameArgs := is.getTxAndCallArgs(callType, contractsData, erc20.NameMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, nameArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var name string + err = is.precompile.UnpackIntoInterface(&name, erc20.NameMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(name).To(Equal(expName), "expected different name") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("querying the symbol should return the symbol", func(callType CallType) { + txArgs, symbolArgs := is.getTxAndCallArgs(callType, contractsData, erc20.SymbolMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, symbolArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var symbol string + err = is.precompile.UnpackIntoInterface(&symbol, erc20.SymbolMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(symbol).To(Equal(expSymbol), "expected different symbol") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("querying the decimals should return the decimals", func(callType CallType) { + txArgs, decimalsArgs := is.getTxAndCallArgs(callType, contractsData, erc20.DecimalsMethod) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, decimalsArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + var decimals uint8 + err = is.precompile.UnpackIntoInterface(&decimals, erc20.DecimalsMethod, ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "failed to unpack result") + Expect(decimals).To(Equal(expDecimals), "expected different decimals") + }, + Entry(" - direct call", directCall), + Entry(" - through contract", contractCall), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + }) + + Context("allowance adjustments -", func() { + var ( + grantee keyring.Key + granter keyring.Key + ) + + BeforeEach(func() { + // Deploying the contract which has the increase / decrease allowance methods + contractAddr, err := is.factory.DeployContract( + is.keyring.GetPrivKey(0), + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: allowanceCallerContract, + ConstructorArgs: []interface{}{is.precompile.Address()}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + contractsData.contractData[erc20CallerCall] = ContractData{ + Address: contractAddr, + ABI: allowanceCallerContract.ABI, + } + + grantee = is.keyring.GetKey(0) + granter = is.keyring.GetKey(1) + }) + + When("the grantee is the same as the granter", func() { + // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, + // querying allowance and reducing allowance on a transferFrom transaction is not possible without + // changes to the Cosmos SDK. + // + // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 + Context("increasing allowance", func() { + It("should return an error when calling the EVM extension", func() { + granter := is.keyring.GetKey(0) + grantee := granter + + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs( + directCall, contractsData, + auth.IncreaseAllowanceMethod, + grantee.Addr, authzCoins[0].Amount.BigInt(), + ) + + spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, spenderIsOwnerCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectNoSendAuthzForContract( + directCall, contractsData, + grantee.Addr, granter.Addr, + ) + }) + + DescribeTable("it should create an allowance if none existed before", func(callType CallType) { + granter := is.keyring.GetKey(0) + grantee := granter + + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.IncreaseAllowanceMethod, + grantee.Addr, authzCoins[0].Amount.BigInt(), + ) + + approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approvalCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter.Addr, authzCoins, + ) + }, + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + Context("decreasing allowance", func() { + It("should return an error when calling the EVM extension", func() { + granter := is.keyring.GetKey(0) + grantee := granter + + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, decreaseArgs := is.getTxAndCallArgs( + directCall, contractsData, + auth.DecreaseAllowanceMethod, + grantee.Addr, authzCoins[0].Amount.BigInt(), + ) + + spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, spenderIsOwnerCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + is.ExpectNoSendAuthzForContract( + directCall, contractsData, + grantee.Addr, granter.Addr, + ) + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + }) + + DescribeTable("it should decrease an existing allowance", func(callType CallType) { + granter := is.keyring.GetKey(0) + grantee := granter + + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} + decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + is.setupSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter.Priv, authzCoins, + ) + + txArgs, decreaseArgs := is.getTxAndCallArgs( + callType, contractsData, + auth.DecreaseAllowanceMethod, + grantee.Addr, decreaseCoins[0].Amount.BigInt(), + ) + + approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approvalCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract( + callType, contractsData, + grantee.Addr, granter.Addr, decreaseCoins, + ) + }, + Entry(" - through erc20 contract", erc20Call), + Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + }) + + When("no allowance exists", func() { + DescribeTable("decreasing the allowance should return an error", func(callType CallType) { + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) + + notFoundCheck := execRevertedCheck + if callType == directCall { + notFoundCheck = failCheck.WithErrContains( + fmt.Sprintf(auth.ErrAuthzDoesNotExistOrExpired, erc20.SendMsgURL, grantee.Addr.String()), + ) + } + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, notFoundCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + + // NOTE: We have to split between direct and contract calls here because the ERC20 behavior + // for approvals is different, so we expect different authorizations here + Context("in direct calls", func() { + DescribeTable("increasing the allowance should create a new authorization", func(callType CallType) { + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + Context("in contract calls", func() { + DescribeTable("increasing the allowance should create a new authorization", func(callType CallType) { + contractAddr := contractsData.GetContractData(callType).Address + authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, contractAddr, authzCoins) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + }) + }) + + When("an allowance exists for other tokens", func() { + var bondCoins sdk.Coins + + BeforeEach(func() { + bondCoins = sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} + is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) + }) + + DescribeTable("increasing the allowance should add the token to the spend limit", func(callType CallType) { + increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, bondCoins.Add(increaseCoins...)) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("decreasing the allowance should return an error", func(callType CallType) { + decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + + notFoundCheck := execRevertedCheck + if callType == directCall { + notFoundCheck = failCheck.WithErrContains( + fmt.Sprintf(erc20.ErrNoAllowanceForToken, is.tokenDenom), + ) + } + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, notFoundCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + }) + + When("an allowance exists for the same token", func() { + var authzCoins sdk.Coins + + BeforeEach(func() { + authzCoins = sdk.NewCoins( + sdk.NewInt64Coin(is.network.GetBaseDenom(), 100), + sdk.NewInt64Coin(is.tokenDenom, 200), + ) + + is.setupSendAuthz(grantee.AccAddr, granter.Priv, authzCoins) + }) + + DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { + increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Add(increaseCoins...)) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { + decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Sub(decreaseCoins...)) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { + maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("decreasing the allowance to zero should remove the token from the spend limit", func(callType CallType) { + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) + + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // Check that only the spend limit in the network denomination remains + bondDenom := is.network.GetBaseDenom() + expCoins := sdk.Coins{sdk.NewCoin(bondDenom, authzCoins.AmountOf(bondDenom))} + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, expCoins) + }, + Entry(" - direct call", directCall), + // NOTE: we are not passing the erc20 contract call here because the ERC20 contract + // only supports the actual token denomination and doesn't know of other allowances. + ) + + DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { + decreaseCoins := sdk.Coins{sdk.NewCoin(is.tokenDenom, authzCoins.AmountOf(is.tokenDenom).AddRaw(100))} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + belowZeroCheck := failCheck.WithErrContains(erc20.ErrDecreasedAllowanceBelowZero.Error()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, belowZeroCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + // Check that the allowance was not changed + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) + }, + Entry(" - direct call", directCall), + ) + }) + + When("an allowance exists for only the same token", func() { + // NOTE: we have to split between direct and contract calls here because the ERC20 contract + // handles the allowance differently by creating an approval between the contract and the grantee, instead + // of the message sender and the grantee, so we expect different authorizations. + Context("in direct calls", func() { + var authzCoins sdk.Coins + + BeforeEach(func() { + authzCoins = sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + // NOTE: We set up the standard authorization here for the authz keeper and then also + // set up the authorization for the ERC20 contract, so that we can test both. + is.setupSendAuthzForContract(directCall, contractsData, grantee.Addr, granter.Priv, authzCoins) + is.setupSendAuthzForContract(erc20Call, contractsData, grantee.Addr, granter.Priv, authzCoins) + }) + + DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { + increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Add(increaseCoins...)) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { + decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 50)} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Sub(decreaseCoins...)) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("decreasing the allowance to zero should delete the authorization", func(callType CallType) { + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { + decreaseAmount := authzCoins.AmountOf(is.tokenDenom).AddRaw(100) + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseAmount.BigInt()) + + belowZeroCheck := failCheck.WithErrContains(erc20.ErrDecreasedAllowanceBelowZero.Error()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, belowZeroCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + // Check that the allowance was not changed + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + + DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { + maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + // Check that the allowance was not changed + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) + }, + Entry(" - direct call", directCall), + Entry(" - through erc20 contract", erc20Call), + // NOTE: The ERC20 V5 contract does not contain these methods + // Entry(" - through erc20 v5 contract", erc20V5Call), + ) + }) + + Context("in contract calls", func() { + var ( + authzCoins sdk.Coins + grantee keyring.Key + ) + + BeforeEach(func() { + authzCoins = sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + grantee = is.keyring.GetKey(1) + callerContractAddr := contractsData.GetContractData(contractCall).Address + erc20CallerContractAddr := contractsData.GetContractData(erc20CallerCall).Address + + // NOTE: Here we create an authorization between the contract and the grantee for both contracts. + // This is different from the direct calls, where the authorization is created between the + // message sender and the grantee. + txArgs, approveArgs := is.getTxAndCallArgs(contractCall, contractsData, auth.ApproveMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, _, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectSendAuthzForContract(contractCall, contractsData, grantee.Addr, callerContractAddr, authzCoins) + + // Create the authorization for the ERC20 caller contract + txArgs, approveArgs = is.getTxAndCallArgs(erc20CallerCall, contractsData, auth.ApproveMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) + _, _, err = is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectSendAuthzForContract(erc20CallerCall, contractsData, grantee.Addr, erc20CallerContractAddr, authzCoins) + }) + + DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { //nolint:dupl + senderPriv := is.keyring.GetPrivKey(0) + granterAddr := contractsData.GetContractData(callType).Address + increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, increaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins.Add(increaseCoins...)) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + + DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { + senderPriv := is.keyring.GetPrivKey(0) + granterAddr := contractsData.GetContractData(callType).Address + maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} + + txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, increaseArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + // Check that the allowance was not changed + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + + DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { //nolint:dupl + senderPriv := is.keyring.GetPrivKey(0) + granterAddr := contractsData.GetContractData(callType).Address + decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 50)} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins.Sub(decreaseCoins...)) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + + DescribeTable("decreasing the allowance to zero should delete the authorization", func(callType CallType) { + senderPriv := is.keyring.GetPrivKey(0) + granterAddr := contractsData.GetContractData(callType).Address + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) + approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) + _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + + // commit the changes to state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) + is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + + DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { + senderPriv := is.keyring.GetPrivKey(0) + granterAddr := contractsData.GetContractData(callType).Address + decreaseCoins := sdk.Coins{sdk.NewCoin(is.tokenDenom, authzCoins.AmountOf(is.tokenDenom).AddRaw(100))} + + txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) + _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, execRevertedCheck) + Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") + Expect(ethRes).To(BeNil(), "expected empty result") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") + + // Check that the allowance was not changed + is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins) + }, + Entry(" - contract call", contractCall), + Entry(" - through erc20 caller contract", erc20CallerCall), + ) + }) + }) + }) +}) + +var _ = Describe("ERC20 Extension migration Flows -", func() { + When("migrating an existing ERC20 token", func() { + var ( + contractData ContractsData + erc20MinterV5Contract evmtypes.CompiledContract + + tokenDenom = "xmpl" + tokenName = "Xmpl" + tokenSymbol = strings.ToUpper(tokenDenom) + + supply = sdk.NewInt64Coin(tokenDenom, 1000000000000000000) + ) + + BeforeEach(func() { + is.SetupTest() + + var err error + erc20MinterV5Contract, err = testdata.LoadERC20MinterV5Contract() + Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 minter contract") + + contractOwner := is.keyring.GetKey(0) + + // Deploy an ERC20 contract + erc20Addr, err := is.factory.DeployContract( + contractOwner.Priv, + evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values + factory.ContractDeploymentData{ + Contract: erc20MinterV5Contract, + ConstructorArgs: []interface{}{ + tokenName, tokenSymbol, + }, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") + + // NOTE: We need to overwrite the information in the contractData here for this specific + // deployed contract. + contractData = ContractsData{ + ownerPriv: contractOwner.Priv, + contractData: map[CallType]ContractData{ + erc20V5Call: { + Address: erc20Addr, + ABI: erc20MinterV5Contract.ABI, + }, + }, + } + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to commit block") + + // Register the deployed erc20 contract as a token pair + _, err = integrationutils.RegisterERC20(is.factory, is.network, integrationutils.ERC20RegistrationData{ + Addresses: []string{erc20Addr.Hex()}, + ProposerPriv: contractOwner.Priv, + }) + Expect(err).ToNot(HaveOccurred(), "failed to register ERC20 token") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "failed to commit block") + + // Mint the supply of tokens + err = is.MintERC20(erc20V5Call, contractData, contractOwner.Addr, supply.Amount.BigInt()) + Expect(err).ToNot(HaveOccurred(), "failed to mint tokens") + + // Check that the supply was minted + is.ExpectBalancesForERC20(erc20V5Call, contractData, []ExpectedBalance{{ + address: contractOwner.AccAddr, + expCoins: sdk.Coins{supply}, + }}) + }) + + It("should migrate the full token balance to the bank module", func() { + // TODO: implement test on follow-up PR + Skip("will be addressed on follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + }) + + When("migrating an extended ERC20 token (e.g. ERC20Votes)", func() { + It("should migrate the full token balance to the bank module", func() { + // TODO: make sure that extended tokens are compatible with the ERC20 extensions + Skip("not included in first tranche") + + Expect(true).To(BeFalse(), "not implemented") + }) + }) + + When("running the migration logic for a set of existing ERC20 tokens", func() { + BeforeEach(func() { + // TODO: Add some ERC20 tokens and then run migration logic + // TODO: check here that the balance cannot be queried from the bank keeper before migrating the token + }) + + It("should add and enable the corresponding EVM extensions", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + + It("should be possible to query the balances through the bank module", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + + It("should return all tokens when querying all balances for an account", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + }) + + When("registering a native IBC coin", func() { + BeforeEach(func() { + // TODO: Add some IBC coins, register the token pair and then run migration logic + }) + + It("should add the corresponding EVM extensions", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + + It("should be possible to query the balances using an EVM transaction", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + }) + + When("using Evmos (not wEvmos) in smart contracts", func() { + It("should be using straight Evmos for sending funds in smart contracts", func() { + Skip("will be addressed in follow-up PR") + + Expect(true).To(BeFalse(), "not implemented") + }) + }) +}) diff --git a/precompiles/erc20/setup_test.go b/precompiles/erc20/setup_test.go new file mode 100644 index 00000000..c6db9cc4 --- /dev/null +++ b/precompiles/erc20/setup_test.go @@ -0,0 +1,63 @@ +package erc20 + +import ( + "testing" + + erc20precompile "github.com/evmos/os/precompiles/erc20" + "github.com/evmos/os/testutil/integration/os/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + "github.com/evmos/os/testutil/integration/os/network" + "github.com/stretchr/testify/suite" +) + +var s *PrecompileTestSuite + +// PrecompileTestSuite is the implementation of the TestSuite interface for ERC20 precompile +// unit tests. +type PrecompileTestSuite struct { + suite.Suite + + bondDenom string + // tokenDenom is the specific token denomination used in testing the ERC20 precompile. + // This denomination is used to instantiate the precompile. + tokenDenom string + network *network.UnitTestNetwork + factory factory.TxFactory + grpcHandler grpc.Handler + keyring testkeyring.Keyring + + precompile *erc20precompile.Precompile +} + +func TestPrecompileTestSuite(t *testing.T) { + s = new(PrecompileTestSuite) + suite.Run(t, s) +} + +func (s *PrecompileTestSuite) SetupTest() { + keyring := testkeyring.New(2) + integrationNetwork := network.NewUnitTestNetwork( + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + ) + grpcHandler := grpc.NewIntegrationHandler(integrationNetwork) + txFactory := factory.New(integrationNetwork, grpcHandler) + + ctx := integrationNetwork.GetContext() + sk := integrationNetwork.App.StakingKeeper + bondDenom, err := sk.BondDenom(ctx) + s.Require().NoError(err) + s.Require().NotEmpty(bondDenom, "bond denom cannot be empty") + + s.bondDenom = bondDenom + s.factory = txFactory + s.grpcHandler = grpcHandler + s.keyring = keyring + s.network = integrationNetwork + + // Instantiate the precompile with an exemplary token denomination. + // + // NOTE: This has to be done AFTER assigning the suite fields. + s.tokenDenom = "xmpl" + s.precompile = s.setupERC20Precompile(s.tokenDenom) +} diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go new file mode 100644 index 00000000..3ac8ec89 --- /dev/null +++ b/precompiles/erc20/tx_test.go @@ -0,0 +1,262 @@ +package erc20 + +import ( + "math/big" + "time" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/evmos/os/precompiles/testutil" + utiltx "github.com/evmos/os/testutil/tx" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/evmos/os/x/evm/core/vm" + "github.com/evmos/os/x/evm/statedb" +) + +var ( + tokenDenom = "xmpl" + // XMPLCoin is a dummy coin used for testing purposes. + XMPLCoin = sdk.NewCoins(sdk.NewInt64Coin(tokenDenom, 1e18)) + // toAddr is a dummy address used for testing purposes. + toAddr = utiltx.GenerateAddress() +) + +func (s *PrecompileTestSuite) TestTransfer() { + method := s.precompile.Methods[TransferMethod] + // fromAddr is the address of the keyring account used for testing. + fromAddr := s.keyring.GetKey(0).Addr + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + }{ + { + "fail - negative amount", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(-1)} + }, + func() {}, + true, + "coin -1xmpl amount is not positive", + }, + { + "fail - invalid to address", + func() []interface{} { + return []interface{}{"", big.NewInt(100)} + }, + func() {}, + true, + "invalid to address", + }, + { + "fail - invalid amount", + func() []interface{} { + return []interface{}{toAddr, ""} + }, + func() {}, + true, + "invalid amount", + }, + { + "fail - not enough balance", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(2e18)} + }, + func() {}, + true, + ErrTransferAmountExceedsBalance.Error(), + }, + { + "pass", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(100)} + }, + func() { + toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), fromAddr, s.precompile, 0) + + // Mint some coins to the module account and then send to the from address + err := s.network.App.BankKeeper.MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, fromAddr.Bytes(), XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = s.precompile.Transfer(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected transfer transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestTransferFrom() { + var ( + ctx sdk.Context + stDB *statedb.StateDB + ) + method := s.precompile.Methods[TransferFromMethod] + // owner of the tokens + owner := s.keyring.GetKey(0) + // spender of the tokens + spender := s.keyring.GetKey(1) + + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + }{ + { + "fail - negative amount", + func() []interface{} { + return []interface{}{owner.Addr, toAddr, big.NewInt(-1)} + }, + func() {}, + true, + "coin -1xmpl amount is not positive", + }, + { + "fail - invalid from address", + func() []interface{} { + return []interface{}{"", toAddr, big.NewInt(100)} + }, + func() {}, + true, + "invalid from address", + }, + { + "fail - invalid to address", + func() []interface{} { + return []interface{}{owner.Addr, "", big.NewInt(100)} + }, + func() {}, + true, + "invalid to address", + }, + { + "fail - invalid amount", + func() []interface{} { + return []interface{}{owner.Addr, toAddr, ""} + }, + func() {}, + true, + "invalid amount", + }, + { + "fail - not enough allowance", + func() []interface{} { + return []interface{}{owner.Addr, toAddr, big.NewInt(100)} + }, + func() {}, + true, + ErrInsufficientAllowance.Error(), + }, + { + "fail - not enough balance", + func() []interface{} { + expiration := time.Now().Add(time.Hour) + err := s.network.App.AuthzKeeper.SaveGrant( + ctx, + spender.AccAddr, + owner.AccAddr, + &banktypes.SendAuthorization{SpendLimit: sdk.Coins{sdk.Coin{Denom: s.tokenDenom, Amount: math.NewInt(5e18)}}}, + &expiration, + ) + s.Require().NoError(err, "failed to save grant") + + return []interface{}{owner.Addr, toAddr, big.NewInt(2e18)} + }, + func() {}, + true, + ErrTransferAmountExceedsBalance.Error(), + }, + { + "pass - spend on behalf of other account", + func() []interface{} { + expiration := time.Now().Add(time.Hour) + err := s.network.App.AuthzKeeper.SaveGrant( + ctx, + spender.AccAddr, + owner.AccAddr, + &banktypes.SendAuthorization{SpendLimit: sdk.Coins{sdk.Coin{Denom: tokenDenom, Amount: math.NewInt(300)}}}, + &expiration, + ) + s.Require().NoError(err, "failed to save grant") + + return []interface{}{owner.Addr, toAddr, big.NewInt(100)} + }, + func() { + toAddrBalance := s.network.App.BankKeeper.GetBalance(ctx, toAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + }, + { + "pass - spend on behalf of own account", + func() []interface{} { + // Mint some coins to the module account and then send to the spender address + err := s.network.App.BankKeeper.MintCoins(ctx, erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(ctx, erc20types.ModuleName, spender.AccAddr, XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + // NOTE: no authorization is necessary to spend on behalf of the same account + return []interface{}{spender.Addr, toAddr, big.NewInt(100)} + }, + func() { + toAddrBalance := s.network.App.BankKeeper.GetBalance(ctx, toAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + ctx = s.network.GetContext() + stDB = s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx = testutil.NewPrecompileContract(s.T(), ctx, spender.Addr, s.precompile, 0) + + // Mint some coins to the module account and then send to the from address + err := s.network.App.BankKeeper.MintCoins(ctx, erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(ctx, erc20types.ModuleName, owner.AccAddr, XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = s.precompile.TransferFrom(ctx, contract, stDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected transfer transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/precompiles/erc20/utils_test.go b/precompiles/erc20/utils_test.go new file mode 100644 index 00000000..3d7da72f --- /dev/null +++ b/precompiles/erc20/utils_test.go @@ -0,0 +1,598 @@ +package erc20 + +import ( + "fmt" + "math/big" + "slices" + "time" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + auth "github.com/evmos/os/precompiles/authorization" + "github.com/evmos/os/precompiles/erc20" + "github.com/evmos/os/precompiles/testutil" + commonfactory "github.com/evmos/os/testutil/integration/common/factory" + commonnetwork "github.com/evmos/os/testutil/integration/common/network" + "github.com/evmos/os/testutil/integration/os/factory" + network "github.com/evmos/os/testutil/integration/os/network" + testutils "github.com/evmos/os/testutil/integration/os/utils" + utiltx "github.com/evmos/os/testutil/tx" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + + //nolint:revive // dot imports are fine for Gomega + . "github.com/onsi/gomega" +) + +// setupSendAuthz is a helper function to set up a SendAuthorization for +// a given grantee and granter combination for a given amount. +// +// NOTE: A default expiration of 1 hour after the current block time is used. +func (s *PrecompileTestSuite) setupSendAuthz( + grantee sdk.AccAddress, granterPriv cryptotypes.PrivKey, amount sdk.Coins, +) { + err := setupSendAuthz( + s.network, + s.factory, + grantee, + granterPriv, + amount, + ) + s.Require().NoError(err, "failed to set up send authorization") +} + +func (is *IntegrationTestSuite) setupSendAuthz( + grantee sdk.AccAddress, granterPriv cryptotypes.PrivKey, amount sdk.Coins, +) { + err := setupSendAuthz( + is.network, + is.factory, + grantee, + granterPriv, + amount, + ) + Expect(err).ToNot(HaveOccurred(), "failed to set up send authorization") + + // commit changes to chain state + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") +} + +func setupSendAuthz( + network commonnetwork.Network, + factory commonfactory.BaseTxFactory, + grantee sdk.AccAddress, + granterPriv cryptotypes.PrivKey, + amount sdk.Coins, +) error { + granter := sdk.AccAddress(granterPriv.PubKey().Address()) + expiration := network.GetContext().BlockHeader().Time.Add(time.Hour) + sendAuthz := banktypes.NewSendAuthorization( + amount, + []sdk.AccAddress{}, + ) + + msgGrant, err := authz.NewMsgGrant( + granter, + grantee, + sendAuthz, + &expiration, + ) + if err != nil { + return errorsmod.Wrap(err, "failed to create MsgGrant") + } + + // Create an authorization + txArgs := commonfactory.CosmosTxArgs{Msgs: []sdk.Msg{msgGrant}} + _, err = factory.ExecuteCosmosTx(granterPriv, txArgs) + if err != nil { + return errorsmod.Wrap(err, "failed to execute MsgGrant") + } + + return nil +} + +// setupSendAuthzForContract is a helper function which executes an approval +// for the given contract data. +// +// If: +// - the classic ERC20 contract is used, it calls the `approve` method on the contract. +// - in other cases, it sends a `MsgGrant` to set up the authorization. +func (is *IntegrationTestSuite) setupSendAuthzForContract( + callType CallType, contractData ContractsData, grantee common.Address, granterPriv cryptotypes.PrivKey, amount sdk.Coins, +) { + Expect(amount).To(HaveLen(1), "expected only one coin") + Expect(amount[0].Denom).To(Equal(is.tokenDenom), + "this test utility only works with the token denom in the context of these integration tests", + ) + + switch { + case slices.Contains(nativeCallTypes, callType): + is.setupSendAuthz(grantee.Bytes(), granterPriv, amount) + case slices.Contains(erc20CallTypes, callType): + is.setupSendAuthzForERC20(callType, contractData, grantee, granterPriv, amount) + default: + panic("unknown contract call type") + } + + // commit changes to the chain state + err := is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") +} + +// setupSendAuthzForERC20 is a helper function to set up a SendAuthorization for +// a given grantee and granter combination for a given amount. +func (is *IntegrationTestSuite) setupSendAuthzForERC20( + callType CallType, contractData ContractsData, grantee common.Address, granterPriv cryptotypes.PrivKey, amount sdk.Coins, +) { + if callType == erc20V5CallerCall { + // NOTE: When using the ERC20 caller contract, we must still approve from the actual ERC20 v5 contract. + callType = erc20V5Call + } + + abiEvents := contractData.GetContractData(callType).ABI.Events + + txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, auth.ApproveMethod, grantee, amount.AmountOf(is.tokenDenom).BigInt()) + + approveCheck := testutil.LogCheckArgs{ + ABIEvents: abiEvents, + ExpEvents: []string{auth.EventTypeApproval}, + ExpPass: true, + } + + _, _, err := is.factory.CallContractAndCheckLogs(granterPriv, txArgs, callArgs, approveCheck) + Expect(err).ToNot(HaveOccurred(), "failed to execute approve") +} + +// requireOut is a helper utility to reduce the amount of boilerplate code in the query tests. +// +// It requires the output bytes and error to match the expected values. Additionally, the method outputs +// are unpacked and the first value is compared to the expected value. +// +// NOTE: It's sufficient to only check the first value because all methods in the ERC20 precompile only +// return a single value. +func (s *PrecompileTestSuite) requireOut( + bz []byte, + err error, + method abi.Method, + expPass bool, + errContains string, + expValue interface{}, +) { + if expPass { + s.Require().NoError(err, "expected no error") + s.Require().NotEmpty(bz, "expected bytes not to be empty") + + // Unpack the name into a string + out, err := method.Outputs.Unpack(bz) + s.Require().NoError(err, "expected no error unpacking") + + // Check if expValue is a big.Int. Because of a difference in uninitialized/empty values for big.Ints, + // this comparison is often not working as expected, so we convert to Int64 here and compare those values. + bigExp, ok := expValue.(*big.Int) + if ok { + bigOut, ok := out[0].(*big.Int) + s.Require().True(ok, "expected output to be a big.Int") + s.Require().Equal(bigExp.Int64(), bigOut.Int64(), "expected different value") + } else { + s.Require().Equal(expValue, out[0], "expected different value") + } + } else { + s.Require().Error(err, "expected error") + s.Require().Contains(err.Error(), errContains, "expected different error") + } +} + +// requireSendAuthz is a helper function to check that a SendAuthorization +// exists for a given grantee and granter combination for a given amount. +// +// NOTE: This helper expects only one authorization to exist. +func (s *PrecompileTestSuite) requireSendAuthz(grantee, granter sdk.AccAddress, amount sdk.Coins, allowList []string) { + grants, err := s.grpcHandler.GetGrantsByGrantee(grantee.String()) + s.Require().NoError(err, "expected no error querying the grants") + s.Require().Len(grants, 1, "expected one grant") + s.Require().Equal(grantee.String(), grants[0].Grantee, "expected different grantee") + s.Require().Equal(granter.String(), grants[0].Granter, "expected different granter") + + authzs, err := s.grpcHandler.GetAuthorizationsByGrantee(grantee.String()) + s.Require().NoError(err, "expected no error unpacking the authorization") + s.Require().Len(authzs, 1, "expected one authorization") + + sendAuthz, ok := authzs[0].(*banktypes.SendAuthorization) + s.Require().True(ok, "expected send authorization") + + s.Require().Equal(amount, sendAuthz.SpendLimit, "expected different spend limit amount") + if len(allowList) == 0 { + s.Require().Empty(sendAuthz.AllowList, "expected empty allow list") + } else { + s.Require().Equal(allowList, sendAuthz.AllowList, "expected different allow list") + } +} + +// setupERC20Precompile is a helper function to set up an instance of the ERC20 precompile for +// a given token denomination, set the token pair in the ERC20 keeper and adds the precompile +// to the available and active precompiles. +func (s *PrecompileTestSuite) setupERC20Precompile(denom string) *erc20.Precompile { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), denom, erc20types.OWNER_MODULE) + s.network.App.Erc20Keeper.SetTokenPair(s.network.GetContext(), tokenPair) + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + return precompile +} + +// setupERC20Precompile is a helper function to set up an instance of the ERC20 precompile for +// a given token denomination, set the token pair in the ERC20 keeper and adds the precompile +// to the available and active precompiles. +func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs []erc20types.TokenPair) *erc20.Precompile { + var tokenPair erc20types.TokenPair + for _, tp := range tokenPairs { + if tp.Denom != denom { + continue + } + tokenPair = tp + } + + precompile, err := erc20.NewPrecompile( + tokenPair, + is.network.App.BankKeeper, + is.network.App.AuthzKeeper, + is.network.App.TransferKeeper, + ) + Expect(err).ToNot(HaveOccurred(), "failed to set up %q erc20 precompile", tokenPair.Denom) + + return precompile +} + +// setupERC20PrecompileForTokenPair is a helper function to set up an instance of the ERC20 precompile for +// a given token pair and adds the precompile to the available and active precompiles. +// Do not use this function for integration tests. +func setupERC20PrecompileForTokenPair( + unitNetwork network.UnitTestNetwork, tokenPair erc20types.TokenPair, +) (*erc20.Precompile, error) { + precompile, err := erc20.NewPrecompile( + tokenPair, + unitNetwork.App.BankKeeper, + unitNetwork.App.AuthzKeeper, + unitNetwork.App.TransferKeeper, + ) + if err != nil { + return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) + } + + err = unitNetwork.App.Erc20Keeper.EnableDynamicPrecompiles( + unitNetwork.GetContext(), + precompile.Address(), + ) + if err != nil { + return nil, errorsmod.Wrapf(err, "failed to add %q erc20 precompile to EVM extensions", tokenPair.Denom) + } + + return precompile, nil +} + +// setupNewERC20PrecompileForTokenPair is a helper function to set up an instance of the ERC20 precompile for +// a given token pair and adds the precompile to the available and active precompiles. +// This function should be used for integration tests +func setupNewERC20PrecompileForTokenPair( + privKey cryptotypes.PrivKey, + unitNetwork *network.UnitTestNetwork, + tf factory.TxFactory, tokenPair erc20types.TokenPair, +) (*erc20.Precompile, error) { + precompile, err := erc20.NewPrecompile( + tokenPair, + unitNetwork.App.BankKeeper, + unitNetwork.App.AuthzKeeper, + unitNetwork.App.TransferKeeper, + ) + if err != nil { + return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) + } + + // Update the params via gov proposal + params := unitNetwork.App.Erc20Keeper.GetParams(unitNetwork.GetContext()) + params.DynamicPrecompiles = append(params.DynamicPrecompiles, precompile.Address().Hex()) + slices.Sort(params.DynamicPrecompiles) + + if err := params.Validate(); err != nil { + return nil, err + } + + if err := testutils.UpdateERC20Params(testutils.UpdateParamsInput{ + Pk: privKey, + Tf: tf, + Network: unitNetwork, + Params: params, + }); err != nil { + return nil, errorsmod.Wrapf(err, "failed to add %q erc20 precompile to EVM extensions", tokenPair.Denom) + } + + return precompile, nil +} + +// CallType indicates which type of contract call is made during the integration tests. +type CallType int + +// callType constants to differentiate between direct calls and calls through a contract. +const ( + directCall CallType = iota + 1 + directCallToken2 + contractCall + contractCallToken2 + erc20Call + erc20CallerCall + erc20V5Call + erc20V5CallerCall +) + +var ( + nativeCallTypes = []CallType{directCall, directCallToken2, contractCall, contractCallToken2} + erc20CallTypes = []CallType{erc20Call, erc20CallerCall, erc20V5Call, erc20V5CallerCall} +) + +// getTxAndCallArgs is a helper function to return the correct call arguments for a given call type. +// +// In case of a direct call to the precompile, the precompile's ABI is used. Otherwise, the +// ERC20CallerContract's ABI is used and the given contract address. +func (is *IntegrationTestSuite) getTxAndCallArgs( + callType CallType, + contractData ContractsData, + methodName string, + args ...interface{}, +) (evmtypes.EvmTxArgs, factory.CallArgs) { + cd := contractData.GetContractData(callType) + + txArgs := evmtypes.EvmTxArgs{ + To: &cd.Address, + GasPrice: gasPrice, + } + + callArgs := factory.CallArgs{ + ContractABI: cd.ABI, + MethodName: methodName, + Args: args, + } + + return txArgs, callArgs +} + +// ExpectedBalance is a helper struct to check the balances of accounts. +type ExpectedBalance struct { + address sdk.AccAddress + expCoins sdk.Coins +} + +// ExpectBalances is a helper function to check if the balances of the given accounts are as expected. +func (is *IntegrationTestSuite) ExpectBalances(expBalances []ExpectedBalance) { + for _, expBalance := range expBalances { + for _, expCoin := range expBalance.expCoins { + coinBalance, err := is.handler.GetBalanceFromBank(expBalance.address, expCoin.Denom) + Expect(err).ToNot(HaveOccurred(), "expected no error getting balance") + Expect(coinBalance.Balance.Amount).To(Equal(expCoin.Amount), "expected different balance") + } + } +} + +// ExpectBalancesForContract is a helper function to check expected balances for given accounts depending +// on the call type. +func (is *IntegrationTestSuite) ExpectBalancesForContract(callType CallType, contractData ContractsData, expBalances []ExpectedBalance) { + switch { + case slices.Contains(nativeCallTypes, callType): + is.ExpectBalances(expBalances) + case slices.Contains(erc20CallTypes, callType): + is.ExpectBalancesForERC20(callType, contractData, expBalances) + default: + panic("unknown contract call type") + } +} + +// ExpectBalancesForERC20 is a helper function to check expected balances for given accounts +// when using the ERC20 contract. +func (is *IntegrationTestSuite) ExpectBalancesForERC20(callType CallType, contractData ContractsData, expBalances []ExpectedBalance) { + contractABI := contractData.GetContractData(callType).ABI + + for _, expBalance := range expBalances { + addr := common.BytesToAddress(expBalance.address.Bytes()) + txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, "balanceOf", addr) + + passCheck := testutil.LogCheckArgs{ExpPass: true} + + _, ethRes, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "expected no error getting balance") + + err = is.network.NextBlock() + Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") + + var balance *big.Int + err = contractABI.UnpackIntoInterface(&balance, "balanceOf", ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "expected no error unpacking balance") + Expect(math.NewIntFromBigInt(balance)).To(Equal(expBalance.expCoins.AmountOf(is.tokenDenom)), "expected different balance") + } +} + +// expectSendAuthz is a helper function to check that a SendAuthorization +// exists for a given grantee and granter combination for a given amount and optionally an access list. +// +// NOTE: This helper expects only one authorization to exist. +// +// NOTE 2: This mirrors the requireSendAuthz method but adapted to Ginkgo. +func (is *IntegrationTestSuite) expectSendAuthz(grantee, granter sdk.AccAddress, expAmount sdk.Coins) { + authzs, err := is.handler.GetAuthorizations(grantee.String(), granter.String()) + Expect(err).ToNot(HaveOccurred(), "expected no error unpacking the authorization") + Expect(authzs).To(HaveLen(1), "expected one authorization") + + sendAuthz, ok := authzs[0].(*banktypes.SendAuthorization) + Expect(ok).To(BeTrue(), "expected send authorization") + + Expect(sendAuthz.SpendLimit).To(Equal(expAmount), "expected different spend limit amount") +} + +// expectSendAuthzForERC20 is a helper function to check that a SendAuthorization +// exists for a given grantee and granter combination for a given amount. +func (is *IntegrationTestSuite) expectSendAuthzForERC20(callType CallType, contractData ContractsData, grantee, granter common.Address, expAmount sdk.Coins) { + contractABI := contractData.GetContractData(callType).ABI + + txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, auth.AllowanceMethod, granter, grantee) + + passCheck := testutil.LogCheckArgs{ExpPass: true} + + _, ethRes, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, passCheck) + Expect(err).ToNot(HaveOccurred(), "expected no error getting allowance") + // Increase block to update nonce + Expect(is.network.NextBlock()).To(BeNil()) + + var allowance *big.Int + err = contractABI.UnpackIntoInterface(&allowance, "allowance", ethRes.Ret) + Expect(err).ToNot(HaveOccurred(), "expected no error unpacking allowance") + Expect(math.NewIntFromBigInt(allowance)).To(Equal(expAmount.AmountOf(is.tokenDenom)), "expected different allowance") +} + +// ExpectSendAuthzForContract is a helper function to check that a SendAuthorization +// exists for a given grantee and granter combination for a given amount and optionally an access list. +// +// NOTE: This helper expects only one authorization to exist. +func (is *IntegrationTestSuite) ExpectSendAuthzForContract( + callType CallType, contractData ContractsData, grantee, granter common.Address, expAmount sdk.Coins, +) { + switch { + case slices.Contains(nativeCallTypes, callType): + is.expectSendAuthz(grantee.Bytes(), granter.Bytes(), expAmount) + case slices.Contains(erc20CallTypes, callType): + is.expectSendAuthzForERC20(callType, contractData, grantee, granter, expAmount) + default: + panic("unknown contract call type") + } +} + +// expectNoSendAuthz is a helper function to check that no SendAuthorization +// exists for a given grantee and granter combination. +func (is *IntegrationTestSuite) expectNoSendAuthz(grantee, granter sdk.AccAddress) { + authzs, err := is.handler.GetAuthorizations(grantee.String(), granter.String()) + Expect(err).ToNot(HaveOccurred(), "expected no error unpacking the authorizations") + Expect(authzs).To(HaveLen(0), "expected no authorizations") +} + +// expectNoSendAuthzForERC20 is a helper function to check that no SendAuthorization +// exists for a given grantee and granter combination. +func (is *IntegrationTestSuite) expectNoSendAuthzForERC20(callType CallType, contractData ContractsData, grantee, granter common.Address) { + is.expectSendAuthzForERC20(callType, contractData, grantee, granter, sdk.Coins{}) +} + +// ExpectNoSendAuthzForContract is a helper function to check that no SendAuthorization +// exists for a given grantee and granter combination. +func (is *IntegrationTestSuite) ExpectNoSendAuthzForContract( + callType CallType, contractData ContractsData, grantee, granter common.Address, +) { + switch { + case slices.Contains(nativeCallTypes, callType): + is.expectNoSendAuthz(grantee.Bytes(), granter.Bytes()) + case slices.Contains(erc20CallTypes, callType): + is.expectNoSendAuthzForERC20(callType, contractData, grantee, granter) + default: + panic("unknown contract call type") + } +} + +// ExpectTrueToBeReturned is a helper function to check that the precompile returns true +// in the ethereum transaction response. +func (is *IntegrationTestSuite) ExpectTrueToBeReturned(res *evmtypes.MsgEthereumTxResponse, methodName string) { + var ret bool + err := is.precompile.UnpackIntoInterface(&ret, methodName, res.Ret) + Expect(err).ToNot(HaveOccurred(), "expected no error unpacking") + Expect(ret).To(BeTrue(), "expected true to be returned") +} + +// ContractsData is a helper struct to hold the addresses and ABIs for the +// different contract instances that are subject to testing here. +type ContractsData struct { + contractData map[CallType]ContractData + ownerPriv cryptotypes.PrivKey +} + +// ContractData is a helper struct to hold the address and ABI for a given contract. +type ContractData struct { + Address common.Address + ABI abi.ABI +} + +// GetContractData is a helper function to return the contract data for a given call type. +func (cd ContractsData) GetContractData(callType CallType) ContractData { + data, found := cd.contractData[callType] + if !found { + panic(fmt.Sprintf("no contract data found for call type: %d", callType)) + } + return data +} + +// fundWithTokens is a helper function for the scope of the ERC20 integration tests. +// Depending on the passed call type, it funds the given address with tokens either +// using the Bank module or by minting straight on the ERC20 contract. +// Returns the updated balance amount of the receiver address +func (is *IntegrationTestSuite) fundWithTokens( + callType CallType, + contractData ContractsData, + receiver common.Address, + fundCoins sdk.Coins, +) math.Int { + Expect(fundCoins).To(HaveLen(1), "expected only one coin") + Expect(fundCoins[0].Denom).To(Equal(is.tokenDenom), + "this helper function only supports funding with the token denom in the context of these integration tests", + ) + + var err error + receiverBalance := fundCoins.AmountOf(is.tokenDenom) + balanceInBankMod := slices.Contains(nativeCallTypes, callType) + + switch { + case balanceInBankMod: + err = is.factory.FundAccount(is.keyring.GetKey(0), receiver.Bytes(), fundCoins) + case slices.Contains(erc20CallTypes, callType): + err = is.MintERC20(callType, contractData, receiver, fundCoins.AmountOf(is.tokenDenom).BigInt()) + default: + panic("unknown contract call type") + } + + Expect(err).ToNot(HaveOccurred(), "failed to fund account") + Expect(is.network.NextBlock()).To(BeNil()) + + if balanceInBankMod { + balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), fundCoins.Denoms()[0]) + Expect(err).To(BeNil()) + receiverBalance = balRes.Balance.Amount + } + + return receiverBalance +} + +// MintERC20 is a helper function to mint tokens on the ERC20 contract. +// +// NOTE: we are checking that there was a Transfer event emitted (which happens on minting). +func (is *IntegrationTestSuite) MintERC20(callType CallType, contractData ContractsData, receiver common.Address, amount *big.Int) error { + if callType == erc20V5CallerCall { + // NOTE: When using the ERC20 caller contract, we must still mint from the actual ERC20 v5 contract. + callType = erc20V5Call + } + abiEvents := contractData.GetContractData(callType).ABI.Events + + txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, "mint", receiver, amount) + + mintCheck := testutil.LogCheckArgs{ + ABIEvents: abiEvents, + ExpEvents: []string{erc20.EventTypeTransfer}, // NOTE: this event occurs when calling "mint" on ERC20s + ExpPass: true, + } + + if _, _, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, mintCheck); err != nil { + return err + } + + // commit changes to chain state + return is.network.NextBlock() +} From 566e81141276d8398ef7a140e2d2b1b7cd101e58 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 21:44:21 +0700 Subject: [PATCH 27/53] update state.md --- x/asset/spec/02_state.md | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index bf9d03d1..96400226 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -23,13 +23,13 @@ Allows creation of tokens with optional user authorization. ```go type Token struct { - TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` - Decimals uint32 `protobuf:"varint,5,opt,name=decimals,proto3" json:"decimals,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - EVMAddress common.Address `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` + TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` + Decimal uint32 `protobuf:"varint,5,opt,name=decimal,proto3" json:"decimal,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + EvmAddress string `protobuf:"bytes,9,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` } ``` @@ -42,25 +42,16 @@ When create the token, `asset` module auto generate for it a evm address. This a ### TokenManagement ```go -type TokenManagement struct{ - Managers []string `protobuf:"bytes,7,rep,name=managers,proto3" json:"managers,omitempty"` - AllowNewExtensions bool `protobuf:"varint,10,opt,name=allow_new_Extensions,json=allowNewExtensions,proto3" json:"allow_new_Extensions,omitempty"` - ExtensionsList []string `protobuf:"bytes,11,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` - EvmEnable bool `protobuf:"varint,9,opt,name=evm_enable,json=evmEnable,proto3" json:"evm_enable,omitempty"` - } +type TokenManagement struct { + Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` + AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` + ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` + MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` +} ``` By setting `allow_new_extensions`, `issuer` can specify whether they accept new extensions or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `extensions_list`and the `manager` can then modify the `extensions_list` as he sees fit. Otherwise, the `manager` can not chaing the `extensions_list`. -### TokenDistribution - -```go -type TokenDistribution struct{ - Distributors []string - MaxSupply math.Int -} -``` - `MaxSupply` defines the maximum number of tokens can be minted. ### WhitelistAddresses From 797ce54c7e6631d1e4c1b2d93bc5f17f9a14709a Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 21:46:46 +0700 Subject: [PATCH 28/53] remove distribution --- x/asset/spec/02_state.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 96400226..3ad377f2 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -13,9 +13,7 @@ The `x/asset` module keeps the following objects in state: | `Params` | Params of asset module | `[]byte{1}` | `[]byte(params)` | KV | | `Token` | Token information | `[]byte{2} + []byte(token_id)` | `[]byte{token}` | KV | | `TokenManagement` | TokenManagement info of a denom | `[]byte{3} + []byte(token_id)` | `[]byte{token_manager}` | KV | -| `TokenDistribution` | TokenDistribution info of a denom | `[]byte{4} + []byte(token_id)` | `[]byte{token_distributor}` | KV | -| `WhitelistAddresses` | Whitelist Addresses | `[]byte{5} + []byte(address)` | `[]byte{bool}` | KV | -| `ExtenstionStore` | State store for each extensions | `[]byte{6} + []byte(token_id) + []byte(extension_name)` | Depend on extension implementation | KV | +| `WhitelistAddresses` | Whitelist Addresses | `[]byte{4} + []byte(address)` | `[]byte{bool}` | KV | ### Token @@ -58,8 +56,3 @@ By setting `allow_new_extensions`, `issuer` can specify whether they accept new `WhitelistAddresses` is a list of the address that's allow to create new asset. -### ExtenstionStore - -Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed. - -Each extension store has its own namespace, which is defined by token identifiers and extension name, which means that a combination of token and extension will create a new substore derived from the Asset module store. From 67d9b0038d200f732fab5f30585d6ecbe8d6967d Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 21:57:15 +0700 Subject: [PATCH 29/53] update --- x/asset/spec/02_state.md | 3 +- x/asset/spec/04_msgs.md | 66 ++++++++++++---------------------------- 2 files changed, 20 insertions(+), 49 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 3ad377f2..c1aff8f3 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -42,13 +42,12 @@ When create the token, `asset` module auto generate for it a evm address. This a ```go type TokenManagement struct { Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` - AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` } ``` -By setting `allow_new_extensions`, `issuer` can specify whether they accept new extensions or not when creating a new token. If he permits it, when upgrading the chain, the new features will be automatically added to the `extensions_list`and the `manager` can then modify the `extensions_list` as he sees fit. Otherwise, the `manager` can not chaing the `extensions_list`. +`extensions_list` is the list of actions that user can execute. The `manager` can then modify the `extensions_list` as he sees fit. `MaxSupply` defines the maximum number of tokens can be minted. diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 65e0db41..c6e12871 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -12,7 +12,6 @@ order: 4 type MsgIssueToken struct { Issuer address Managers [ ]address - Distributors [ ]address Name string Symbol string Decimal uint32 @@ -38,7 +37,6 @@ Example token.json: ```json { "Manager": ["realioabc..."], - "Distributor": ["realioabc2..."], "Symbol": "riel", "Decimal": 18, "Description": "", @@ -61,27 +59,27 @@ Flow: 4. Save the token basic information (name, symbol, decimal and description) in the x/bank metadata store 5. Save the token management info and distribution info in the x/asset store. -## 2. AssignRoles +## 2. AssignManagers -`MsgAssignRoles` allow issue to set role likes manager or distributor for the token. +`MsgAssignManagers` allow issue to set managers for the token. ```go - type MsgAssignRoles struct { + type MsgAssignManagers struct { TokenId string Issuer address - Addresses mapping[Role]([]addresses) + Addresses []addresses } ``` ```go - type MsgAssignRolesResponse struct { + type MsgAssignManagersResponse struct { } ``` CLI: ```bash - realio-networkd tx assign-roles [privilege.json] [flags] + realio-networkd tx assign-managers [privilege.json] [flags] ``` Example privilege.json: @@ -91,14 +89,8 @@ Example privilege.json: "TokenId": "asset/realio1.../tokena", "Issuer": "realio1...", "Assign": [ - { - "role": 1 (manager), - "addresses": ["realio2..."], - }, - { - "role": 2 (distributor), - "addresses": ["realio3..."], - } + "realio2...", + "realio3..." ] } ``` @@ -109,12 +101,11 @@ Validation: - Check if caller is issuer of the token - Check if addresses is valid - Check if manager doesn't exist in the current managers list of token -- Check if distributor doesn't exist in the current distributor list of token Flow: -- Get `TokenManager` and `TokenDistributor` from store by token_id -- Loop through addresses and append manager addresses to `TokenManager.Managers`, distributor addresses to `TokenDistributor.Distributors` +- Get `TokenManager` from store by token_id +- Loop through addresses and append manager addresses to `TokenManager.Managers` ## 3. UnassignRoles @@ -136,12 +127,12 @@ Validation: - Check if token exists - Check if caller is issuer of the token - Check if addresses is valid -- Check if addresses is in `TokenManager.Managers` or `TokenDistributor.Distributors` +- Check if addresses is in `TokenManager.Managers` Flow: -- Get `TokenManager` and `TokenDistributor` from store by token_id -- Loop through addresses and remove manager addresses from `TokenManager.Managers`, distributor addresses to `TokenDistributor.Distributors` +- Get `TokenManager` from store by token_id +- Loop through addresses and remove manager addresses from `TokenManager.Managers` ## 4. ExecuteExtension @@ -185,35 +176,16 @@ Validation: - Checks if the token specified in the msg exists. - Checks if the extension is supported. - Check if addresses is valid -- Checks if the distributor address is in `TokenDistributor.Distributors` -- Checks if mint amount exceed `MaxSupply` or `MaxRatelimit`. +- Checks if the address is in `TokenManager.Managers` +- Checks if mint amount exceed `MaxSupply`. Flow: -- Get `TokenDistributor` from store by token_id +- Get `TokenManager` from store by token_id - Mint the asset for corresponding receiver -- Increase the Maxsupply in TokenDistribution store. +- Increase the supply. -### 6. UpdateDistributionSetting - -Distributor can change the max supply of the token. - -```go - type MsgUpdateDistributionSetting struct { - Distributor address - TokenId string - NewSettings DistributionSettings - } -``` - -Validation: - -- Checks if the token specified in the msg exists. -- Checks if the extension is supported. -- Checks if the distributor address is in `TokenDistributor.Distributors` -- Checks if current supply exceed new settings `MaxSupply` - -### 7. UpdateExtensionsList +### 6. UpdateExtensionsList Manager can update the `ExtensionsList` of the token. This only can be executed when the token's `AllowNewExtensions` is enable. @@ -231,4 +203,4 @@ Validation: - Checks if manager addresses is in `TokenManager.Managers` - Checks if the new extension is supported. -### 8. UpdateParams +### 7. UpdateParams From 492d5b0f3216892a319f16d68540e9a4506eae0b Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 21:58:10 +0700 Subject: [PATCH 30/53] remove allow new extension --- x/asset/spec/04_msgs.md | 1 - 1 file changed, 1 deletion(-) diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index c6e12871..0c635a2e 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -16,7 +16,6 @@ order: 4 Symbol string Decimal uint32 Description string - AllowNewExtensions bool ExtensionsList [ ]string } ``` From 8cd94d50f827c2800c52881cf5c7690a3f8b77fa Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:08:49 +0700 Subject: [PATCH 31/53] init supply --- x/asset/spec/04_msgs.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 0c635a2e..727d9cf7 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -17,6 +17,8 @@ order: 4 Decimal uint32 Description string ExtensionsList [ ]string + Distributor [ ]string + InitialSupply [ ]math.Int } ``` From f2d7ba3e44904c037fd64d1d6a580e937d538d63 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:12:34 +0700 Subject: [PATCH 32/53] new image --- x/asset/spec/imgs/asset_module.png | Bin 399432 -> 279157 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/x/asset/spec/imgs/asset_module.png b/x/asset/spec/imgs/asset_module.png index 193309a356b078d7cf98260bd70694b5b8500c2b..1cefb9ec5493c70e043bbd0e756d7580ccd16442 100644 GIT binary patch literal 279157 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

      oLj^>l81ru47Iu%6ZT}D?h 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%0AX4YboE@DcMj&jj%&PZ%-)A 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

    1. Y!i(cG*66dOzMm-DPeBMM{PAL8CL&xN#6FB03X_ zNj^^OM!oXvM#W*v(>-}<%d>sl%`=qx>H6RBH*CwFrPV$6JtpGy>K(O+cgHVz+{k|G zM>IJK=Vo_b_}!|XTKoR9T^b!{d(UH)+6?LB{ahFP-s(O5?Iz7O;rPk@%tZi5I*e8i zOqabhK3!>$;)_dvJhkg`K=wh&0|lMbBY%3oJd3JeGMVXS(*t3(WVN#Xdkd}7k_D$q z4D<&H*1_t=tCcy`-vcqBRKWn5>@acl@SX1ERgChq5^ZQsm$4VvMVd$+U)uHi?anlWkR5Z z25r8SIcpyEs8O3na@EA{5`UhvQdGsi}~qri9*J3Zdn1(PX_q^D9v zLS}XiwrNGoT@+ERw(-UA78gOaB_4PzkATfF^8GsWTPI4pMN9TQ1Q`{S4IyXx?#tR~ z$F*;i;?vKb2mP+|uX~igOUl!1CFHM(fLim3wh8Hb)$BXYtMwSEZ>BwlD~||$JN6Im zx9`N??mRq;n{GZM-(%UaXEl*pm^zzUU}bF`{W{`xU+`;pEJ}~41=HT zZDz+~&FyC$#!vB#SvTCGP8q$a8*$eK8}DcmtpG+^+rXW|Ba{L_jmM|JXctrmD#AR3 zDM?H=K;;-59**sH4VZ{5fVXlnb$q4y_B!LT4EH^LM_kdXtM)!%V&D1Q4221s4xwL9DB8$k;zd|km~7ZX)X?=e6?dRHju>h6 zq@$VSY}3fEo^eYAo1MU)$$ipThz{QogG zF>!(F#_h@G#JQ(i=4G@NJMat>G}p`OjEFUOWv2yFPYRudXRo4}e{0K+!@qX1+MfG1 zv3-wbgD~O2+ZbVtv-i2a@MHeLHF7QTpF-xPz_v%I{dcVucEMC#%7_nfM|J}Jeq@+5 z4}yXe)GWyzI%Hl}Mi{Wo^l*ct`@R(0-^Y? z9nSsZ!99oHU>wHFaMfn9qy1uUZUyJAF>m*>bY9=aR(q*pq;xJl zN2r_Wb-e^~bncI1#*lw2kC6zSW3wp;$7Y*4)V&19m)`iGu4mQr_2&}wY3qcmbGJNLM^p%a#ca!Ea1(KG*kJjcX=|3 ztTJpxK`6T&2HmT*0UGx{dKAr~ejLB?Nr&#I>XB{Q_D6E5mdOc%01 zCY2K~!&}kt@on^TieYd(|MH|`qGgESV)ck?>Jsm_n_9_U<*q)$mwBk3GxstDT|1jH zc|@i===m3-CB=bn@*8jd`TnXr$7O3s<}GKdVy(36!G;N{YquD>EZD>+4ru4z;xhha z;29Vhw1~VSs=)`|IBHlWL7!%SFDcb8V}exTKj-*mLSWYO8R(^dD7&->JjNr?(sQ;4 zIyR5NjBDbW586hT>`(TT@<&?-i|5uhT1T8QU(<=rQ!^tKY=8O1XOC$r{KMz#av%FY z3+Zf)H@c)Et7FfrN>R8p6t^hhXJCywUZ5WCV0$aEBr zWv6zowut0AuH&oSbA5YWef{WOwyN*+w$GV?@=}rU!G%$h!4+{Cx;g2`?Gjj1RNlU8 zZ5JY0ri#U~pP3V2Z@M|=b;WELy%_(++4Ii{nfLD`#zrK}36Z0Li9t1gf@yht#Z0z5@f4>9i(@*dWih|oaJ5L}^Qd|LDnCHN_uKD%oM8hRsHE~gjE;qjD_QL7pjO|C@W57>Sha%(UhazGLt#h^fOlN?=2MolflcG6hQ>_ZnIeT-{s=zP=X9PT=0|MisBTuCnd2xD-a zdRd%>Jlh}z4~*RyZ#1yY6xh2~XPKL@<_d|K01)5@m-XJ+OaBZl+ZZD~$LEm$FiwL2 zr`Toz17tC z`_D8O37I9YVokq4vsC<4MC2;wP+{#xM6+)ycS#yG^;{AgkIv+dQ}arQ1jW!8gM8Px zi-CH{ZK7!Hpyo`VYa^%awTmsbcey@!Dl5Z*kwrDQx&#H0^p>WOePxICN*CFD7%KJR zLCA91k7ARb7$mljDx^OE1Hv?@xOo%!5?`S)q~aHr3v-j^a1IY1m)2j#EzA0u$Pzf9_3S8Ru?Mi2$6b68>swZkeVad&F{>hav9$GyR;OpmFHGPm$@hd z^N2KWcyre+KAZ`X4G_KDNJa9YwxH(29@&en1VRpu_DfO=S!cR@WY-?q_G|XZebcOR ztbgk$dp04S68}CsYOnKH?wao@gMe=Tm-ntP(Aukp9(eYXgy6cbU-^Z$$`r^MpSWx? zRDolZ66XEhsK6H#?dBI2e$EEoNMj)5G&ur&eu>?0pBq7!Sw$`wOo62_Gkw|YK_RjJ zxDO?S4dnqd-Le(c8^4?sP$mB2A;InoH*nI2gZ%J_w;$VHNHHs`tD~^*PgY!s62$th z_uZzhSyM;nICO1bojFruhhk8Pr5+a)6np}Gqe!Rr!>q`lRL6y(Z!V;_Y6Idhm?QsD z$sMl~GcBt97B(hMy6;AG-yMH0MgA(fty57i>l{~-0*?BF`kWW1kDkcfB-oWO-Yp{K zl&Mch3+v3aZM~6iExP1*G{t4h@Y(6yE=%V;g5$I-v1cQ%ZW14#+mjI+OLldOl`l@9*=ujiQa-(;Am%>99lj$17v?#rmG4zjLaup7W^l0&4(B^;P zoRb{&d1#1E5bYRsFz*kF>u~rpx$S$m*8+<8=UB8)8uS;RZ>&pFyknXN!Ei58k|K9| zbSE-EEr~rAS1$1*I36Wz931?u_9VG8pyx&(C|+0WNOZiWaPCE(&w`zswt7FSl4r`P z_+TOtvu3}kH1)~`+Mg?gJAr&Qr{&5B8f_l8jfB^Ks_ZXwzI1_A_sAvwn}o!Hz+A^V zXI&sgz4YyF?lW~R;!7kX$AKjK5&+_l-%E&HwHhMH0Bo*&H2`gEi{ph4qemS3Ulp`@ zilRt3>^Zr)lPu%8DAjW?J?qL&d=^Xdm`dZ%r)-^gFpDchF-b?b!$?e=-FHp((G1_{ zpkle>YlrtU@tE91X`?^NneEzJEssWN*sphGDJN1> zL?_Ni>v3J5p$u1Z7L)#Lh6GBpH5bCJS-hUseB3BPacfQHmY!K8i*zK>sBPi{OkXke zfr0U#1WQjZQ;pkATUSJl?U7v$_wq!X0;(Yd2{M-Y67*^Jy#yr;JVl{U^B^+&6{KGt z>*VF+jLrt%X#b#iC+UI3RPuv~FVc@JjAy>(e?9C%v$nQB~|$mKD1&Axx$Z<4aof zrwSb4ef=+qUykEMbO3(!PBebnJ za99*&4fz38KZEh!={yPkPhkY6wcb}%zxhZT<3#dhSANlpSAA%1%Ypc?z_>(Y52rNlLWIQ`hH`> zgvW>vtFc41rp5eJU!%7cqAAZ(|GLR!k(DHk6VV$K`H{(8wd7^bheAmvE;_g4(r@g7 z*vSz^;1IDGsLc=mXR}i`|m2G0rWJ4lRstdGzQ}IcS{i?Ct%&e4$~) z`t6C%=vyO`onvqxi)yF8YW<|-*dp9-V?~*;_Xam$#U}DtJPsS>+e1(%%15DV?xA!v zx0WH|Y2p%uIzEFF$9ez$y)V#&fq-IbdGN_Vsrwo{*e>`3HB>l_Hd8(31Vuhtgat6k z__(t--h%8XScRiD;vvM}h)0|Ld8&{)x{tO|E&uH`#i1Y*?44z$bW-Jgg?EgjpqC=W7Jy!2G&4N1Ns|2_U(0 zvR!hsJK||-x=8*I#oB+ij_L|2HkW=wTk`={dk8Tc{bL%LI{J?tdZy>w_Gk>-brK9k z>X)Gr1+i^){Vo9+!q38zNV?{n7kMv-Y04N!*CIew&yXFoo^DT3$&*^R9&$b=Xp4m~ z|E^V!7`<}6JZSFn#YDfZp~7`b{!a&!{whlEOb|5{q9JSA`k0p+kL|@nM(eY7;AAV_ zKK}FeSja%VHqaAq@=x_I3{U8{xoKvD_ufVofuK==1z3|pQ6gV-b?^MQeeQ3_0M=Y( zCT?S-7n9MAReS^NQT6-qBf7)^M}G;J1#1|-Em51ehv7G7ij{t2X8p0q&iSrg(B&gZ zw16&td0!ktEDz&(@wS{cE@TC#H zOAr`IuiKZ6%{-}8ShAk0V+E2vm_So^;695Brg{lz{XGPhff0=sK*E?_2abwTj{|=F zdJhf_!IxIF8;#}Gw{@a84c~&u@3Iz|rBCANp*va`{KQPcX!0{qA|u`I6!-Ju2@&6Y z+TNUJ4^~ONWP8%8_>(E-2^~9q_xzbf+L9sy%4>q!Ilseb)7uv`b*$Ycb4J4sL0tE5 zC3_A?Jv1gp)n+7gNx2|i6}has8N(Psby9o>A|L6lAQj;@Selz<{DP)a9s-AgwbpM(Es4_o$GlWODdc88)X!i+uedO(}tn23=uR_~>YQ-XqG8$uzK8{{YkPJQ6 zDQhvMqH-J7dIe}^_iy2?ZY58+xNW{}e&?)|r~DIzPoTBUZTJ@2zjqhrsc)(N4Iuf2 zrO+clfg(2bn)z=ZS2W0G2$tI}3RW-}0d`@Z*g|F|IgF6BlL}~R4aM${Cm`kW_-#deZ4bHlAQGs}1UmW> zvE;H3_>%2R$TsvQ>Q5g5f`gN(C$)vwN!&>T$ zvBa#T#2wC7)7@sT&FZ({UN3=)OW1M}G zLQqlurGu2IJBxUO!o#zxuFX{4NrFr9lgMiVm~R$i?BIL-d=Bud_X*FNZr%d^4!L3aC*t z6l{eNytIw1<-_~@wg{FVSAFR*?P}3;rs!1-q ze80%tj%#^E6;{TWk&Hyg7>{4VMUK9Ct?&`u(FXG!N&c%p&D%P3>~{5d?D6lB+wU`i z><2ozc0hUiJZ5YKIBxaBDS(0hJ|bexCVePv%=^vy&JHRdU@ft_kqLP-q_+(XVL(9( z@t>02$SzaXERvk-0hdBw>YbUtNY)@xkE$Vi{dbA!!717CNJW2qY z*Qi%!TPSSoV>(apy>mK3muyWXN#waF&w@)chLKTxc|NrxY_oo+zC6nW7irfISk2^@ zD(m*IUiY4%o{c`$*i<>tAd;Ma%K2y}dspkjjk{lgD6#dPu zOspF70Q=ony1K7)6eXic80sA>IQO4F$TB!t7du3!2haA9y+B>R(J})fGKg}%%2Ksz zT6=p8Eu8sHRJ&O>quu;ICe}10=~?O+WlFap*{(H%Omc-f6#KB^BdNQT-j5!=<-ySZ z{IuHOV#SMDP7p)sm>G601)sz9{_ur<3S(8g?@jo8V`l467%^@yCoSB7cR|u_jnwl? z2!kV+mq)64ro`(ar*%-zA~2B#0n#V>5$l2eP~Z!@9f)X_q;uzxD>44!^apD#Oa;)~ zJMf#f^P)eIkM_YjPqyupJMT(t-1=}17b%q1e zxd@}8WNPyIWj|7r_b(z~!UtKwPQmq1E$21Ns8 zaS?b1txfX(9o`UoEdcVtk!uquN&^5rAEv>PS?P;hawiI>`^fl5BpRfqIs){*21^Fb z&?zREk|bgs$*oT?p*r;L7ERdfgc?|dE)3R(266VuX}@doeZ-zOe3^DtnR_vyKkA%{BDAS#RK{LvzA|1EQ#t1&55o$NPpXhVT8Yi?R`vAUqbh!ECr7dvZ*9O= zb&Wq~EK*o%BuAKl#?QS{mKc4fZSQeNCG|Ae_=Z0CvV90@;@ocT;O z^oKPjbxkLv@G{(eVtT5J*u(Fw)gY(4&d-XsJzx%BJeThFUdS^%U8}wK#I||jo;!ok zJpa=Ozm^ccD|n5yw7LgVb)scd(y^u~_1D|(#F}gD&?c{Ganv>TSl2?8Cj{%9Uw+WS<67Gi~&EODjg^aMrdJw!uZ_!|6x2 zasK9G-c&6|ZTyYCrMdP#RBv1qLDZ z)YPn!G8eAsP7KVRuSe&ikc#Z&E;DQ9$vILv@`zT9yB+p+_cF|1@rs=cHQRFYvaPf7 z%(h(j#601DBq!{ApeVLw1@KRM}BKc+yl4YMBuSW1OROq>BQ* zdVV>7>uuNX3>FDqSwA-AZRHT0WygaI?M1{8wcRsjU2%>RdP~mgA*Iai+4_C=k+2O< zI60JUG_jk88NX7#`LVKLI$Wx9E68A0tBEh9K^QE;<knFUT|-)taL#rY(}qbb3wnw4N(W1nsmZqKkPT+4eM?Cp({{=;0s70w z$qQy-!+3!axNY<{kP05vPIvQsiynpH=z8+0I6EBS;amp|gVt)FUle#*8nX)JO)i+G z2YsAnG(KP7+$b(wBi&9JrCi=fU8?JQslKHDU4N@VtMQV9^pVhib}PAja6nsq$tH!B z>9dB#bU8&P5{LV#S&fOEvvYjCr?^zBc4K%H*=OE@Y_{Vz;%NcSPGK#bxyVR^(kq3R zQ%!PJn&$hXL!PEtNn@z6)nCL^*J(PpB`ALd{zllbTY z=GS_*8D>wgA3sJ0ROmp!A3k!fh5)BqmcZcP&=aV*(=d=qfwmBOd+;`-t}uMw==jVX zmoUWRdAc9{Y)9b!ty#h>KJU<(QGDe0S#oN%U(2~}p=-XRea*%jBdWp_ zmJJEwN-^hRJ4^XO$`3bq5%MM~Z|@2SmfM40q0Z+EO)c33ulc5B>!fIyZtJJ+^(8Sp7d^2?Q z+zP5j9csLe^X<+l?A?wUFr9=j46;zSNxE^&LJkA1jfUeqy-Q%%n!>g%I2%Z{jcsrC z1B-=pJa&Axsntp5__qn?`0|eW15_IBe5U-e8TMaLhaWXYTUTQ;e3Ig%fp1y0=$j;G z%_nH0?Pt+i;g zl)ibU9MtvkBc64L!NSCr>Z8p({vkn>Nu7Z%WjI@P+Q5RBjZ#^G=`?o*Q_d%tN44Sq^5 zI>AW=7HZIn5n`#JrEs2SkRP>9#S`Z_we)J@(z0S7DWK^1zv}X%G;Un1A4E*3D!-E>> zGn6ew0nV^r+D#~;eXPlgUIqc_{rvaZ**Dh4;Ra~*Y-#H1^f(I_;=87iY*}&44PRTl z)b?X)uQrqA^5wBAZYmHq_j%-FMRk<uCZD*Vb?-}7eA-Sz(#7Qb)q<$UAYl30 ztRCuNE8K>KqhW{m@Zm`gNAcp!)aBhTkLg-lGN5A;<)GR~8a@(6X$fXo6UqARfyhnT zX0P-KH^7Xaq^#YPka0gl$Y-#RhA4`JM`5$nDLg7Fq29h*nshTe2^;G*GyJ2Wrv8-( zi{f#w=i|XKPN;baeK|XFn69o@2*t#?_9Ll9cAT3v4F%Z=`v${88_O&4dH<|XE9#WD~+dw*| z(;j@S!OZ8_=5FkI#6 zF9fXI^nt3M9gxj>wP7Y zCuG>zaA3-jpzgAQ{M}%zc-l!Ol4%48{-Rk<7LRNP*gF7`g9a^$>Ed8UXJz7Q2nQYfD5{^YJ%t_PQj06kd^|gt zXKWMGbjrk5Xu#2sXJbB>4uJD)n|vRkw#n)AW~#Z8uu#E|U?X+CUaYzpXT?-`5wN=& zm&sFp?!;GwKP$gQ_c&;`*E+4f?!)AJ1A~=GkfoR49O&t#Tlytye?BJ|8FkvmrW>k| z_I~(0BSEI^q{IIjTuIFyw0nQOdTGbVkcJs_8}pW>hr2?O zUNMWzJ4AQlz*mlad-EGZV`IOyS-I`IgQ8RTKS#$xC?oJ>)#UwtUlXi$D*esGzGCEk z6XrD?7owima_?1UM>wJg!4LVzH(azrqF^50wu01u`lAj0{uNl|kYbp$UeNr;k-Yc4 zf+kS!Zb!s_PRJ|r$MD0=^crX_9toEZb7&Q_5STTN^IxH;fuxb7!weGh?touAbY zc6;J~@Fd)ZYrS#Hz<|jQ$kRQr$%jl&aTB1liL~>Ehm|nDLC~o_7c0`0d_~@jsWxtp z@k&6Z+OyM=h-h=D_|`E@cx$aeXk$mN;i(OGC5l7eUNHeO3b|#Hhn}(3SPOB=_hOtp z%Ji(u%%S~PZT9%0c-rNX^Cc*#FDV{r?`Kn)QO|~p)NI>}9sD}nRe5GRMn$S)O#ImY zPVgZO`Nfanx6~H&t6#x77R$nsuEd?mIPaJ*ag?J*VQH_v5*bWgwRs}c7667L$)wU|#JKH8#NJj0y zfA10RZu>yRrIxzYXizM><~ituD)JQnKzXa-M>JLCJ5tS0uJEJMQ+l#tccmjwkYn=Q~E1u;(v)e{PbKbx#FjNRnCD9IF6VA~zw(e;N5)V0C-{ zhHa{R`r&H$*EB8JnJ4SD`lWsuJ;%HpA7v-66qmKF;NY2CADODm7i9F4J99yE+E0Z>H^|3+!|OANBW zp|6`9GQMVRe2!XuU7rqEhJN^UxAt{Cnj=B{3-&|rUU=yih={dWv8$ycBl=lVkYh%6au~>f{t;&`kJZ5%f@-kCm%1}aAd;M4c%F!WM9H}yW{F^Tv{+p@v-)) znp+v_TZNJ&QJu&6vT*b6RL1vNr;>?nYc%)0Q~lX~m3x8LHG4ir4EfNdO2NLF#c;=f zlFGz@Xy1`lT4)m-bd}o!O=Mbsq7fH{K;RRhjF|M8jbGH2YGeCEwhU_ZYmGQ|7p^P8 z&9_YTnZ#kL49^NMBb=^_(^#3VsLxMC?Uo~c&6a0ac1;g)Np6Ke*qPV0{oSGgI4JzLy!S=Q#q@(fgl(REA^eYa{bMolg&a?lBS{L>eE#sptsS^D1P*s))=|T>jqy$R5a_=2W;Ne&28SN zg3Q1T5kCc3*gpjJU8u}MX?z4wy`!&>dtKe#+krC-WMN@JPSpmMp>tPE>Hx4%EF*xF z8%0JLfG{3{PSdhR5do`Q32rBZ%+aQW-6v6)y2dI6 zr1{#0{>$Bh15T2R5r0N6mMsAWB=edf*z?${YPfhir|~^qUG5Zb7%3;Tl<2#-@*o~Y zgT~$mfmg|QN)N#L6EBp!W~ocki;`Z0Jfu9a>Nz1_0Y~LK8DlM7+~ymr!)2zgT{u3y zuWu%|yVOoc21Ix`3yiDL1lU$9RrrlkWv_WYqQschNA4FLX|Qy)N-x22EZ~U7?|S;K zv_j9E{C_~TNCSV&M*xdv2`XRs){LK!(Sw&cU zqgk62?HY3C#4eDNzU%~%&L1G89`C{30A3Z8Bw#O3$meoyTAI#N1jkI@hd8n(a3vn{)jeS!*m2h-^zMjo~4$KJ!GBjuIft+Mz1W{XCo9})z zEf%aLIe-92WBn{%zBY^4hM&YRY`?pDrN78j%lMNa^#Nr^ju@)ynf!;Et3-*&^Rb-( z2JhX^u#!^Kcbdt4bA<~?C?Nu?gNLq(q#armKHs%8K8vuP!{g|Ps08;G2ag23}w-A@@Z@r=sbi?1i1NM53BX_al`CF`MfbIL}ioI^Wo5N{XBR z&}eUlxs)w_dj5)Fa}z~7IkcV!E;PIz#dyOrUCZZtaiZulY1Qjkl;q2KYsgpp?2Au) z&q+HbZDn77hO1WVI&kz~W9Q69UE{o;3{V%G?QE$}trRU&mhP-%ds?$QS?O=mexE(q zpLUZ&DEPK0Z9-@IT}V$B-nw$Po=WIg-N)PoOjVk$Is6TV#0bs8mO282+Qh#77xcEh z4662n*8xehyMuW_TUYW#y7=^`AErkK9)9~g#^Cf(+ZpZwLbaXloH@o%S{sZSFsugf zio&OIn*yDJIkvh~8qug}L}(>Q6MXTAYa2r)rt162TAK-}hS0+9pPm5j_V}yE3hmKJ zRQ!^w5_O&$Lrp`^34>Xq<~ajx&kmhbkc+n07ciCUKh=jjn0@8P#a9)0(BsYZ|K64Q zK1O=>?3tZq3xLVNtvls`Xx0u0(J)cn`CdL5rj4T<{&B3Ul^cC<94$1c6Ekt+KLpmr zNSZt`2Xqcw{Ju%pF5!8M5MQw%>Qp7TU1mSaiz%(Mq2*|0Jz4U)x>)q7X#nI89J$P) zbZr+a{*sqU`s{ww(`t+fQ-gzpOB)+KV(Q^ZMfeAV^UNWEfp#zN28bh4q^e{0epEdd z5^Au;pUVYPlIXB+{=UQjk~A_hGG{<&c$A!+o9zf%hI%uGv{j%ZI-D;}ToDSdgN0yR z>$wK z9Nl#31Xq`=S!(Oa$;c(BGnS21@ufJ7`8TDetieC*RZjM_Zt-Rw?puB5yehaS)#@=| zkWz2FpvRcttrMQ!dTyn-?8Ms5I;fmqfx~{k_i5td^Y?>vcN9%=Dx0Nty0zdI0{xNl z-7tu3voxQQenp}{i1H}WGpC#IsUQRLcZyP@L)0kaqUYE4swEa)5hb5AKCUEUJD~`l z=*~N8l#uCmwihyt1}b9-hDlC!ajUM{7WrEiVJA)`9jbdft|7RLX(xV|w4klOQ06s# zm+>N1YO$))rx&5FTz)lOOV`sbd^X}j_jT{kw>`rsy&l=mpc8#wlSr_hpL2$DS+>RL zI@AuUrx2!V^Go%$>hH{5{uZE;HP*edl>f9H(4mMpw(IpN?b{5&w6NfYU?AvC>U^+J zQlzeO&wh#rHa5a4pUZqzcx(g`%V%3+TWqLnvp9NZzq!75zeH>wz zb&o=grNpM_XJ}A>T_&Hlu?4_i=)G0d)YLS_iBo(J)6iZDB+F%XoN*_Q+yKJoXpKRm z8w!uh%`Pp+t@f5+)xop}#@hXi8$r$twbrvLG}JrqZL&rL*r}^`#b2tvc9jMyn?c~u z5uI`4Fu;pJ6p)J_dnVQ|Pav6jC3%dIJaUe2(9%dihL5!gktU>b7JE5eASw7|{xb=; zGTZJCI7Ua82*H6K`uTi=wO}j>^4sEWD(=ZFO!ZB_(%`31N*Hh@H)m zA;$9oO7nLs)VxBRGIn84PMLA$xGdo>;tehR!X)%36zNM|DDzcF;!51uSWz#~XOWd! zg59(TRs+*9T!_Lu)IBM_{kE3Y!B8(WW4ZS))8l@nDL3jYxM9FOe>Q0PZTlK;7V>_w zm4=%#7`>sfxI(z85bmWh?|mCoaon|-Va-c7>6R_P? z+cvF-H*vK!Oi95OddPEZx+c`Y;8Ih~2CXNBuPKD#Y_IDR9REj~u!IBaD>&R#V9-!z zJQ8Lw3C0`|D^*)5h5+a~uBS_UZqQ!h@tAtIfu+`@Tk|1ts+z<@PkaB0DJHAo-G-@= zI8}O=A3HlKG1mX`FBHF8PDM7(;{}S9JW~2-03U1b_=$~GV-u)l<3Wu~9tn9}voCqY z<^zbAUr0zuwIuyLAo&Rs4AS5x(B-vYtxW0q1OZs)dqexN;HW4J;Bf_bVE$_?&XA$$ z;VjXv7Ql;%ml39=%S2UmT$B8MjZAY;l0`4lCxNyWUG(}9jmDTCvR@FSqWUYJQS%AQ zo>l3hObaraHjht5?#JRrrRYx_gzCc^f=>E3Fs{E&OBRv}U1-tK5tYZc111MgG%U3m z3O_(J0-oV1Ty*Xwean?XYpvu9?;(t9P>g@uq0KsFw76*DOq(;+aO$N6hqKQF8Tf@! zPruq8cVch3nLR<0I|kd(s556=_DyVYMlLgLwNVNepz6HnmP~Wk)VT01M75tST(7>V zbNGox;K!O?o6NCS#V2p)+D*03BP{LO!MZ6@Z*zYv7l=F=jNMQ&2;pD;#*pTOhRt9$ zLezYrLB={*61k69#AymVx+dH=*@{x$*N}+dHo#w{G z@lNWu`CuQB&df9Pc+hZDy=~wLLDJ`J$(F$tafGd_JU86Hjhlm?aHTCf7^okX(m&`d zLf$yb|R&Uufhwq3yeltxcWmjbLPp3o_eI>Uaj zuk^V+lE_LKe5!Fk%I}J~ySL|bo`p!MXATdx`!HBsIv@ICx><4QX$|Axhn;qKO|lsA zf~%N)x1(kElA(kS*^ zzR$3KQKpJmWS?@I7<0b@-7e*aICqVaF60rvgbH-rT)=VC@US0`y_B9ACtox2VRaa7LKMfk{i#N*l>oG>KY}-mSA2&;(CVRp% z*(fX)hh!H44GVHzc+Hl(Sk=Tbxh%`_O9G4llukCNnIU z7O}Q^luew&>o==P(Er}^t1*F2m+@j@xc6Talb;c$>;0VoyY&n%3nxwJ+wR=qUl@8D zwrz-w=h{PamX&E+<{wvdS_8z=E?`K}^TxwZE^n_Kz5tcm$r$k{QgnbwoGkntI!=KJ zcBC}NqHKbRG%eXRd<`bzAK6{@=WcbE+k@H$2GEBY9V!gE9GM;+H~<-ldf%c+ zWNqQ1dJp{T?aIrD403X{HDNJE zS9*G)^-QBfY%cuginUF3KWC1e37tM}=p&hC2*XYyIAPTSSzA3r%Qf!9afQXe+%dQAcP;*P zTlE70&dPn=+2vrwJUX=f5W z7=!H5CT}t}RyikJpZjhALI1#)Xx_ndUlF`x6fs_GKP3v^6+#VfaiIu(8+Gf%!?-8M zEK=Il)d~(LDRg1kpD_KNVGEb>$(FYICtT==BAOJ0WvtHipSh8KCZSeO&d#H^8FqEc z_!VwKX?=d{ytEYasS#ghWz;M&5T?OOXNFO(*qp1TMIQfh1*TUG-OoH7T+!^#wQPd- z>GUaT12g7Xzq@2hYS1NfEDF3ReX^SS3xK8PMBqwnDuHO1s)C6Yo3!*l8`&T5D&>T_ zL(@{EUIk~ZXPMk#DGBk&y07&4*+dIO!VHFgdRP}}h_1%Wkdlz}&+k${djm6rHCp-$(?`Hf<+W4Irp%ANK2$I=?h!%_LfLYj{eZJX4U6lhTB3n~g@pxm zHEDSXV|bK(#zaL)PK8NCgaRyg0|C4KO%WqoYwnJY%}ZK_(s{>o|CIWI+`nNP>`HLz z>du&4`k1s<%gKG3E6Revicb)3jEK$e;*-8W@bk_3_StJDf0f^x=5i5eLAxw1wMDgx z%3fX0<9W$4*X)rX8^!!{7=eshLPFvad?js*ix~-9LjTOxx8i)+#bakUOe$*q{P;8q zIr7}+LtEa4Kbl|`|13tbp!D$N^S2Ig%sNfJ<>f3;bUK0gk%tjLEMK;=>yj{%YhyzQ zhiGmM3$^OmF0ZcqK7W25%cMO+S>__&Bfw9ZUCw>)vn_(mC6V>|FYKKhPDN^|!y|v2 z)tEUa!a01w_lUyI`ohcG`p2;mEE<_8?Jq0{Cd?Rr?R$dwgf6Uumg)+%e6&ADt+;!p__C}NE5nnAXBc)B^#p(nKcyTAuCV6cntY<0t^O17P9bd<6i zVqiGj4W6}o-!(Coz*a%PD0*?VwIgEv`|K1wg=Vuv7JdK82B}yYSm|W;6>QIswQLvo&F0J|LR=^BCZHvxAx6+9HacYuPs8$b&O zL4o*y^+LhRJM(i3v;b(pyOP6=1RXrl@2R%l7Q8{uiar?kx+kdnycYX1@|}&L6B>4Z zFuH7NGjpEn01Y$zL6dSar{8}^4Haqy2k043$k`NX2_A$`g|k9N8VE`}$Jhpr=8-Et z9<5+&+yRpmB7FS+k+b!z;Y$&MMIi^Djr(kl4V}IW7Za9+Md_!QrkHaMasEc;Rfo6c z7=`7FR3g*dGYzQH5qMU7qyKR-3jg<41^Tf~!H@G&NC{D)j&k2y(gAs~1HfPtcHPY2 zz_b63VetUe=vUhZCu_%$Hfs>y{A)@P3bt(CIZ9D_m}*HdJR3svdu=@_4#QQtvd9VM z?Ll?i5l+Q3PPoiEsUa!mWBKSnRYRd9Onv7NfvaT`KW3nRd~oAYPk+-0_Rzn- z$;1rk@iR?bH$_564+6Sgu%u2@j;8BBe|E0!t=PDPXMF`CI>J*XV63Il0W1Vj095k< zA0J-{XW_rEF9LqW5PO=*A;OY&jl-zYct7$1W8eJIyrQgr-xtH)yxv~);D*ZiW2S#7 zjbI}QwhnE88>^ zNH<%K#XcD$`ST)#;T2LKpqMSsHjS45Jg^*%cWq;4qNKZRz_`V0) z>zug%9)Z8?dq#tGfMt3Kcyl##2~eB>zktA%jI*t+Eu^wEkXagttiXohGsZXpTUctV z>GGE<5(xji+R3+ig*_%|eM71-UDz5{ZWV#C6;I*_pksF{-Tm!GPX>JFoN|9phG^iuCW z3sR~bzM%Kz7Z=*!#JMzsp`9S3u86YsMMzAkM;ASf90jvu`W{6*?Qb?5Io$eFC`fxc z|EeEEV|Zp}W=IY@4>vbdT_6+0=244)D-c=QfW?^6ua?_msY?Lh`JXTWrCtd6DJ}D=%!YTi;5Yw2IvweinAnl@7r+Z2 z-f4U7KCl^wB&OrI9G=Y_+DaRTy&?obJ1D8#;ulx)x7d^XzWwFz_4pmg0L#<2f&$8Q zbh^4y=byB}jZ%)2b}vxUa3FX$fcnHV29lz)&#e6roYZ(}AT-d|BJ^G3N%wbc0PnDR zRNasUEUshbJ_@)V`l5FC5~>nj6zYqT0{r6>+OTwMZ?gw)Xjca>q6jJR*WIimn ztaj!`SVn~M<*n~ap5sOc28V=n0F8wuU=+e)^bM0n^K0>lVZl@A{Qz1Ise)caa+~uN zh9Pa-&F${?FN!lV$Ot^>l_gs)0_wO9^qo)k+D~uQeC$Bjs;@4NMEU1@7AHa0(k{r& zMtLryGb`2y5_z7U>dfN4`^lA&fM#hDuQPdf+D)$pcF?XoGRnuIH(O@_hV-Wdf_MUi zDhJstdm7KPXMv5xpO~`2g@JBCqyW7F0Prw@pUG3=kP45eCu3yyvYfvEek?;Qq>}Uo z%BCqSD!MU7fJSiWYc%{5VR;jx7lZbabvN^>v`b*cKI$~Px9v=QU;t*;7Ee1KghjNutjBEbg>pX{=tLC$KcPO9oDOq0I4iWqKPPyKRJk?)*Mc+GR^ez<)XLNV^9!C-#~XGB z@d-8`9^hKcNK^T#!i)T-Bl$jtF3rX3%z0`?)7}Bs)ujYo?>FZ$hsLi#09po{qsn^V zpUS*BS6}tt?>qu>tsk=7cC}I1cYc?}t7N6~wuZ5UKEWFciMbFFA0f7BMrso|h03rug{Ra^k45OHQ;D84;cNKoS8u)%p}e75u1 zRv&cqKin)XXdmu3_x|TpLz9{1GrM~$cqeRu2mL@ct`P@$G+?^zY*&bm=Y}M|4*iLJ?ypvf7qS zxEe2h-;Ql4FWss3?Y%#M-+gDa!okLN?EwaRQ0H9=*>wKvhso13z|EQ)Sm0TW19#I* z!=A{0asYTT@Ldy&lLj3|BTZ0w_~@e3eWfX#iJy$SUO6{SAsDqz^dIz2l}pYr8T$*TcvUJ&M{DQ`OlDgfT& z0l&dKn3i3cOacIie}w@vN)yl7D`#=MC!X+dHg1n|D>GnD zsy=xL+#sMq(a0gE#%`g>?Z0V)5&pERvSd8}89R~s4+CanF!pl2q0@2l`pfTDnFUTy zSs+|t;^XH}02WZ+JcsFEs(Mib9r%S_3&9I|UXtT*eLYFO_q;z#i&&?q0GX>gTlJaZr+2BEGPY*XJqfa_+XrZ1CSb4~JD%~E zXbK&6<4Y`Q=yAi}mi}Pa)yhC_T79!rQ%5X@3PovYLs42!<|n;>UAHYXCtu1CVq5?l zK0QlI%lM*BZe_5#OHekz1a?Bi*%@7h=_N)1B1?RwUoBFol(scJ z0QnlytjhC)4dV$fJg|<2sWwuicAVmW_w%(eN8AU9shDv2u~KN@^(*nLf#~-I)Z*FX zgk)r8V}(iyX0)k_)@kj8`U0cxw6x|-orDy(4G=KIyWh7ce5{StraA=nCkgUd#;j(? z+GnvE*aLsF`|ps<{?yLtz-#(M;=QZ4)P1A67R{fdx&^GSnzojxSEw@Aq`_*_NL8`X z*;=j9xulpW4;A=(hA?V=eLu!&If(`&r=R{?GQ5H$BlX+VKLEA1qV_vK6t~Qi-QYs& zc)9wz6H*|rlhY9UZXncuD2nJJ^M&bPAP|}DENEs@4kn!T{I(YxLn zsy!KBnJnB5RUEYmPQGVnbL{&kpl|tb^6IF ze!RS;-uo9XnD!{~+k!F8(p`~=l3-^|O5GePKAQP9_Xx?0Eb zO@0oMKe+x~mMt)K=l`1fZUB_7tN6`?5(;!*--z*0Fju1*WXN?p=W#!O?;@g`#c&!2 zlpxM!6Lk|sY3OeZn(e%6T0~MDQ(45n;H;|T%gci~*mtf@nvcjrmPd)KqT*($Wlxm` z(*c}B1nd<$3xQ1)F|Xq$`F{>I5t8TIOQf+TcKwIrlXD5`hwFOrP4S8A*ZYA$-eF}l zd!aS(3PU^$`Z<==zWD23zkby-H0;p+fa=DuD#VZzW=|1i{4yFR(%&^i;;o1}=3b!p zXk~TOFw;2gMqA}@@X1b!#OCwUkEIeb)YbGuB@C;ChC{UdWzI7Cq*+nNx6uFjoj`A8 zOUw0O5~%jQwc`&Lp_q062`#snpsVw^C|#gZE>`>4*l=-i5%MhznXNX6yZlv}|I&TJ z71zqP_A`$E9rah_2uNBp_88~C@~~X{T=`y}=)PH!hOK5t0QcY(gd7ae&?zf#AJP1D z_weY$-(FgR`7E0eKao`A%i6D{g}wS_nFq?&)%8r=@nmO){v~L3cffSL;Dj}~wi@Ge z3Q;GOt25AP_8Kj;557=&9~Bm`hb6T#hSQY1-SjNw>excPK1 zv9FxRptSAGYp|V310Ka7n_L_PE>Ge8xN_7lcnXC?Q63cy<^fa(x+%T4WctN+OxQ2c zy~hh4V7z6U|ISV-P~o+rM&lV&9Vin6IMh@I zgIQi1fU+1n1*3p;>sQu#M+62G4}cKTPi7(X2&@_K<)Z<)BZ5#CfRW#vEJ^uy2!#nN z^&Inr?a}(x!DwTDgRTlpt&Q>N`J1rr%S8CZ2`l0z?|YPWflEepDLIrV|1UJ-n*QbH z{Y1H5!`jThab&)Na6sn9ACF!I0&4T+wY~)2MqXZC5hyXZTr($lIU&K6Yc5z+aZLvg zrC~it=7oS`dH~Vy2mSqyDfJlP2dx{>A3nEi*@?AP!A-t1yX1?h(IPAP1WodK-=Unn zpN)n;XG{iDk)bBF#TNh>fdR5z%)}PmQeQa0^@zyHMNfB)Up9m25DX|w?^jtD#({S3 zza`!8SG{RkQ4YwK&3%q%F2UW4N+Yw+8HpD8qk^uiv8PC}E--akJWzP7-obeqvA(3h zG3t#*CPH%#szeVfXc!hd;smm`<`s^-&!Oj!d;kgb*TI_G23GS98|?AVdl3NU78P(y z+r+dL1)c;IKMH#Kg1Il>ks;w>L%%gmQ4ZWc*AE2m;*XFY5mql|aU&p_Sz;jPdpZ5z z^|ePERNkrHVQrrf-0HzqA@hsL(zYj?oAHksZFHO6yMipkN}#CMv@aY^d36HmZ(^!-e=yx|_U+0vG^8(q?aXKPP10{SxihWsEv zcmY;SJG`W52*Cl=o0*^~@=a0ww2e&edWFu-c@c_c>7Af8Y@Le~m{TST<7f5+_5kZFjNs_ugGNVfHvbIGPANz=WmG{e8@ zdVk~)rE8Mz?`~{`!?exYr{%jl17jlFZdG-?5P-|JAHC|&#{Rfpv1@>k)E0=0V>Cg7 z%Vjn!tRfL~Dhh+(Sv}faHxT>#UTpb6`fhCX%(;HSl>sg==pZcZ6FjWil#z7aX&*Fr zKCct~-hgm+o+ScVnr-c4Pz8u(c!8vwk^so^U$~E0mSsZ`b$VgCP zs<`x36BJXIA|fKb3)9+LxV9Wdc-&wLD*E!f$WRsBM0vCLe9--go~#dmMoU%#9+=>v zfNz5ts67Pa$c{bqxY%D~va$b^Syfd<+fl%b#X{_Ncxb0qV}S=$b4f{syo)dR z!R-qG3alcH&U^jXVYi3HQg$X2(m#ma;rAi}A&t2IE6AP}65Bb(cgua7SbR+6qu52n z9Q23kR?Z8pA?F##bPj>_=F&!nPdrDaF;#aP2Zz(vC_;92wkwH_Vs~M^*&X=VC6lY- zy4&?>LD%~r&<-y%yA4ZgYH6h=a;>?KIxK>DF6_c8v}gea=%Xijqcs4gbC`t5qO!Ed zwunR0_wy?aU7rU++sUlF`_wp~y?)bv*0>-z{u&+)i`!ux4U8fEd{hDRJa4*LsX&3n zW{&&rR~0D93p^^BD}!@2l&`O^;aU!-fs3k@plA>f+G+zg$!LDKaB65s778q4tpJMt2%vFYXDutY zH8OeztxxCX=JYz>V*%e?L@&i>Md)3|xV=YtMqmm96LbO~ZGz83oA>wkp?W}7r4;G} zdYwxkZwbG81;2#K5-u8Sa0e#;00ED2c(f`(YKvybO8n_>LLl&I+u7c>=*Qgt-7=M% z!F8iF#pCyJ?w|1`t~Ndp^d63w0$Q19(~}}D4=pI*+>w?p5N>VWFGkqRMK>lZ6UPg9 zIDY|qAEhD{bfDMx01RQ|{|{SV8CT`DeGRyQ4M;Z#Yys(1x;sR=yF|J{xi=}Q&1Xdq@?>@sOR4E{_g+F;e#CA`+3%ybIdWv9CKUBRRSgn)oXl-4xGYJh_aDd zr?%w4R^U+JEhG*oqSGp*38Wp!o~LdnX2=u)h`IwpJEHBi1Gef_}!H&8nTNM zRof2U^XiT})cfIde@x8S`0wP`(bHG7bsmQ_V2iTW%WTlt5Ct}FX0F|MP0h^@K?`{{ z?H&7dh!9=mvYfCb_++?h9lNxh}4wd1{VpgPQ=6q?fCVByXCc)Ve zNpOEUBV*z%0<-EPrMld0QNaK(et8$(jRPMC=R4dr7z&1%aJF5{03VIGQAEewQjPS- zOgEmH*;;}0%*jjce-5SsQ#}$bp&o9s!C#L3{|LCF7dUgvOUg19lM#WrMPJ6parN}{ zjBc*ZY0!7(8oBS*MR&iol8j`%2EHL}>uv5WWPC1*jy}rnT}R;Zih+K-$NYoaELb=} z!^U@#($^s0p;JjmuawPHfwdl-tkhEybNDpYRbP^bk@oB!{SVSOkeph?yQIx!AbZ=! zAK9{vCh*6@l#TZ849arjuiH%&V$U|@z1|77I~rk5FWLk$e1CRx`KX1NTv^@_G{IpV~~chPzjiz zTwGjtLGkX=B`Lu8D1m3*jIF~vNh=-n`gnE)BNZeYmvOd8bw@Xc+(AtCS$ z{pjfE>ZFt<9edPZ7t1T)I{js-c6s*!2o?o3aklXL+7Av;B2jv zwG8MEJ-RN!*JB{e@SH72u;!|p+<%tu`CXFop%_9qW&0-a=If1+xfa7Qk5izzRMA+mViLP7!pv2SIOc=m8q>S8i0fxuOv48I=2h1& zofiYdOLH@)uWy%egjR83V3ff9ni}}?L`R1OOvNm`uj#Imf9tho*eh5qJ0g@bbk>X{ z_!cbUPO%>ubK5K{E4$)<4@_8ZqXT^o8f8YaCCxhay`a7^?MkG;6FKRlELvR_*fdh4 zRG>g+$+`O4Um4PJd*ikHv3qbZDx#V0%%qT5PLAJ~ACddCpL_XvZvuSi9xWzM(#vuS z!8;WGo9FW1{A&f7hft1o=)P)oA;A&&=g*$qwGzJcGC9NPG-e})#44#t^oLK#01igS z?&L1>0$cPa7e~N~I}inzrVY3@w@C`(*^VM;Z@nNYH9*EBA6V}sd<6)JA0Bu{UPl|B z5fx^OVoY+ujCGfoH%c%o2|LIM_iOFuQ0Z`{N_92meoAWEowcjTLnX6301M_#jyHNh zq0^JyWd+ujy9?gDqAYX39MOMSppaIl^*V`ROsgH}MVca)w?U!bc@XFy{tRpjp!<3Y z<|@ERL~X*TN&0-Qe3TfTw+ttXWJ;M6R{TaI?rAc59YD!8kDH2nY1;0k4umS{ z1-HNN)*2-inES4NZ~J8G$ntTy4?O=y%S1{(ptsEt z00HNpHwW0Y(fZ`2Bc~|j468J~Hd81{(^se4-!}GI+#ueTUf#SektY1itW$&4Pc(Di z^lQEppW`xwkTq}pd#x=gSfQbF+rDM&Dj+weLXl) ztHowD@w6(zikqu;tZ&%*k~y3uFoJCNFcZq~h+dQs%^JQ$ni>+x0AhW8#(0kTeGmfb zv5I~Mnc3hnX|ZcC>-;FzMyL2|w&f~>x0%eW+uif<-ZLUxOi4RD+0pMv%*Ke@wvhpm zj;_afAOi2d&_}Qb7U+@($0g-0%ew^18&XTedr#8s0rFO=b1+t3l(e?^j8BC+L^twu zE~wS-HeGkogd)`$z&<@AseaSQj#pnt-YN}9V-p$vGH7yF#*3&#=SEx1hyT-=aK?SR zm38gBFuTsNenn;uph~#Mpa<&v8Pwm!+nwwVm>!STdtRl1u|~HWLHb9tbU6jd;IQuR zN!J}HymQDQ_2sVq_)(op`5hGaQI#%a`1AMFAkJr9Ucus{y5pnN4OeczHDa96g>zrX zqBWn+i|;j0jfieGQ&B?wM6n^*_}KV}qTw#FG+_xNqMmzcGJDP98>_|!y9A+%28e54?lzhTA7 z>I`9KGk^=cQteZt6Ed1Z))m1@Wl#zgte~_L%?|Yb*b>~?FB=&^m6^ zg?b`&GOP7LS1Q!6m$XiI=T=jVUqkg`or!Zfd$$4R#+A{~Q?$S)`HUuKb96h%y&$7r zQz;y~U7;+|qQ5d1;`11)iw}F@h`HR!zV6OZE8bc+>>hw7HdVL?hD=JRXVv|bP@;&R zgcfU*KJ6_)s!9pMHi8hryHT-~ov3);Y~(e*a`d_tLNQTE6bhj;$FEjzok3oM7a)gc zLhZD#7kq;s-&2hg9pvCDE#UD>LdbCNEqh1)rAppY*^jJa1`ccp_GkzZLURi1Zr_Vn zg!S|lbE#*`be8YlQ5E>1Bt#xIq823T74EXoWlZYoK4&zrZLlZ$&4#2fFgl4B?+C?0Rl|RJj@nhE za_`66K4bx-Hn^f_^_^1P!e?1mh#rw}qca7H6qc+uHfS^ASk2*?kkN>j0Py7!v75*| zVhNiAD74QrwZsW7CvqF!5jD~%&Z35=+Yy4te#bq1M_Dp7LJ_+Hs~DYZtW`hCz)c}F zTAQ}j64!~bM?DyR>hacA3prPqD3C%0=s%&gU@#*oar0nU}S}4Tl8(t@2 zXUwm1pucu?IzSLu!)j4KK! z?udr9cpism`XYLquMLuV-dxqwymu6WzQ9U{Hu0#Re&*=`yX?lnUzHb5w3AsSrNFmR zis*={YdR}F{jkG;G?@Koan=i<6aFv|5%Ch{$NmWnynONSule|L-5uqAFE<#O6;hFqXo)Ap@g512idy)ZAn8W#qtZ51w#QhiI*^8)^tly{92Nb497X}e0D}e zrdr&AGMz0DG}H_?#llZbOtx~db{?Fh^dFjo3;p-SegBnGVUdpiVUhVO18w3CNdjf` zlJTEEc3?$#w%PaDF#>wh|(VVVFl38cxjB4+~}oQ_CKYWMA_J9m&U0hWx~kU>(vdHhb_2 zv9jvD6x9G)uz8kP$O^9#3o-cXH>IFQ)rVG6()=*`0x^Z9&#|DLehx3Wf0Z;iNc4kzXK&f z5e)?43RK@tqHsSmjPIc%kba$Ea42mfImLE&{vEFt?I0(tJmM+7yeqrLvtxd9S&!&- z>pAQ;Q}~Y!AhFhj3J_qD3S2DfSsYNzI+ z|H)22u(=FX>mH+u(qz38+A@wt1A_=w;IuQB2oA6Zka+VUJols9E};GMmhp2r6RN<< z+DEbB75Y+bLzwlhSsxIK(5vtm<^e&~_ru*W?D5YxSzi$?Q6`J}ydu2oK{XX`8+8lA zWJ+L$sb<+pl1`I$7!UTcQA;f-%~Hn3*8$zin?m)kqp&bh8Da0U*puBk#>DQ5 zPoaZPE`sHsT)^d5m_*|wjx11jtlGX`B&MQ?Xc6Ws z+DJ&KtW0=q*B$j0mSDSYWjcwB5nZ`stLTl>Kd%deg-?#uS7>9`Sns=Ec8z0EcXAiK z{4O=iPBQl35Ozzz=Fu2^?fFspeImpsRp4}qqeyE{GL5) zIDE{7U+mDh3LOytK#IHcX-IrE%cY%r4b%GPvDMxZrg)AGYwO zazZ&{pEDSF+{aN{K3>hu0+popyavDIItn}tb+x=XouoV#65PgZdk5zMj_{tZ!5ShP)%x>sy#xOb>JhfSJj8)a(+D%JvkX9*17 z!IWu`HfG!5EpwyNEf?>K#A2@Sp49$m z&DkYNzC6N!R4hJaE^Lpiv_K!C)5=}5%$gO5JZx|06rcrwVLrTVwv2T1;-Hahe2;B7 z1}8t-T6GxzZ({lV!yOl4CjUXf-1yC?D$7?5tfsVgi4cv;q% z{}`S`CaS4|mil@)vyF@Sz}u|G_7;BpB-op~so& z?CNkh@4E|N%oEs6r8?p&@ZG#uOP z7+>oJylgyGb)W$j0wktgpb$)w%Nox{`9DM-PAmV2L|*GVqOg4?PHQ^9@pJ^|)RD54xaUegA=BO2(7}gb8HT$$B z%smH|?f`Sg#v@ly`X>XqY0jx&y?=-Yz@Z%Sj=+O&B2SJ`m23~ZcmK9M+uMBpb@K1e zK2Fy3B?wqkrg)a!A^X2TK&mYTYx?+7xW;GMQE+v62l4Yv9Et%tl<@a&I8fbT0qohr zpBDugzS%%$_b&ggkbKuT+0)abM)5Tb=oeK04R~w`^hf!it=pSg-7pq}+Uv(}F#_YI z(!v$;yGhLyxm!?M1mxA^9IEN4{|%aK2w)T#25U?BM8MSpimGfpdKHPLLz%55uvIgs z-g$j%6s+VG14}_79KzA&9ug7-$cPzvZhv%9&99KKg)4(meb_wOgv zdh}iwBb?iS7FF>}LAy%;B;O1B389k&Ax0uTRrf_G4uGO+Cx zg)g1+PO;Gb{fR7bp!Dr2iz!q5Xm=)fU)RvsQwlar@PRD~obw zM^|*o=f8i`J|E;{fLB(xhivkYW%RQqR?~<74QN|sSt_L(r6hvh7PXN66mC}eG`>Vo zY2mNY10L(L28dXE462@gu>ePQi6+ujI!>t#t$nZMG8(MblmV<$HjwvAw-*XP{{1H6 zUbO*2wFtDWf)VYYJf#nK9Q@}!*3)`Zf+M8FtfD|czdesb^GpUbeV*f&O9i8W(>0M_ zA~AGA%cW}jxJ)2#Fl8V=o$-Wnz84{G$?S2d*&S~WDh+~fl4pocb>DX@K1OAth zpx+<~`Y7yV$n2MZ4#n*?zz0%@0-z0vD=%mL+&4{fVv`|?CyqbxuTl}bP^@F9NNL3S z6MRs><^c6zk$(A15~F4`i$PQ2`do=7EAD0qCP)SQN|1aG14&H#X`H4gUuNk|H0sm; zBRcpTDvYif#%y$h2d?xtgM6X_8D!>R^aVVNVaqdc)boMT?kx>2mDGK!uOEm(ScrMK z^Zn5zSuy;tql@!%Wx(q_3TU+X_Be1ZgFSPN3@ps74DbJY`u_e<4ijndK7Y2$?4TnH zjy&EFor(A@@HamC5hJ{%5UWVUU{L76O9XE(V&s&gezcL#{CURVxptpYr`InNuX|qw zr2l(d!n`3T!@`m&QcpgUp7$Px{r)Gg*gs!VoZ|_29);a`L%j!`v$y3u02LjrygttZ zwm*-a8_ck|b<_SEZ?-|}5CcH0Q_7Kwa#;X%RTeP)-te(!nyqsT+Mg|ADsV)ff2%r8 zTDi{Kh!h~ZSC-kvKWxKiy{}5#rzep2zwq^^p+hLwwUdluy@Xd>&?l<(|2fFVon=6o z!eF}-o5B4dfY7>k0m*D{SoroC3Jx{Yns7G#cN+ia+qTI=@6V z7j)4;wA!pNn1wNP> z1cOOHoKzaH4H$rJXoJ`nwmIJW{m<$7gQUm;iv0$-dbIvEV5cAIvBhrMoeS&(Re^@7 z-J2!jcg6jeQv!Hh2m+3TEI7Hz_atJ-^^@XWcFf#)yiI^bYCgn(gw6rvyDC_|>PiM; ztD>Zl*fsvqN;>mr-MvedgpV#(ifLTK5&!4!1knqG`w$sH$Xa&Epppw^ z)~i$6YpmM;wJHak{0WRxn6w{@@nO1k0~s70u&N6#4F{Z(YCMhn1dBZ}e2nDcr-uHG z%^*Uq!xH`)YBR>(tuFfqEP_UsH%F!mRy}gxzE3aujWPFl!t$``-x16KHK0RoXtZJJ z**+g40k_HB^Ka_{B;mG+h~URYAjTO7?A^0*aiO`j!4%bn79V=cvD|#qZZfPUcVmkI zpU@wm<5mE);a^HC1(W~(*Fs4cAmno~0+zQGA*ZpMA_3K*@}6|fNTD*-_iFPP)w!ds z$q1pFGt>6!{E}tR4b3<7J(qNQRr63fhCJ`n=Rh4pJi_^>knTwxso{IJDD&S92@4)1 zjx{Gv4G@A4`Om|#6 zdM`N{^jO|+9f>MCxbnq-aYAJwfrldmCO-t45lz4`9fh^3)_zxE24gUh*x z4*!72e(j*F86Q6@U6o5u&;0pQo08xy8jhmV%$CA;n)9-NvYCpNsIWX z^FtpNUCBl5zT6!!kuz+gK<=w)kE?gWH)mAWAd`8fgC~}-g}TBNVNnCjK)7tCGaCcM z?mb1v_$QeErVj&pC5=FB1yRwIyuG>J48jyrYP4I}U1-e!`}yb-n~0b|3*r|qJIF>X zWS5{LoeQKon?lB<%_d!_zoR@Z_SwfR96*lLzSB9rk)%^BjpRDk`!`PT=YHtm(uJsV zIVU8zYGUi8@{Q&HKvaEYU?zsX^xfox?iKkE*16T_h z7kZyKyRjo%QsA)VaEQMl8ZFYl;2~Q>ACBksSkhwYg|=~@CT)CyeDZq7e=l&P$XhI) z+Ft^t#3VMOde5{tlFcI4*o=FlejhC89c33v$crgl4(RM7z;|tH-+){R^d?W5_rk?W zG)gT1NUvg~prGIbv)ab}|9(UON_jvk-i6ev+r^D3r}?+W{LA{v)ZC{)PKL} zCX|35B`jlG_Ce$K2<-a_2IpOF-OIo;T%5ZLq;sdkyFW{Loq%M@q)N5cONEC45PBka z1`g&8y3EuBvGNWb-pq6{Oji2v(>x9DIsi3g$> z)LLNRde6SSy9fc$hX5!9FCGrW$Dt9jwyD*LH%GK&2zt>>KAffmDn)r92#q)U!|ML` zYC2(w6yN75f-U#Nu6hlLIV- z-#2Vbl~Vw0GpN?XAL&o~kga%(Qgr|OP~q~OnOCT`Ev5tdzahLqut?kch?*@@KsRk9 z9jJlBvB)e2;>o9t7t1PO{=m4(MBzOLJ@6iTHJg{a0d{ef>eZ`cL-~b{oer3T5?TMh zh!P`tx7h-$h@w&)8Me`N07l{JyvbWyT8@r3Rp(e|pMy}9 zcUlj~FcO4TH9d*vjEi}w&8SLCQqT51zh5t(|0f|uicDicwY*+y_%usrsMWY)Fr4}t z++FEEeT7r-kjpPCqTZx~@etMb-1h0@q#k{-$%FdrHq&hJR&F55arL3PMGam*{wK%% zzLHo#rurU)cFHWEVb1|IsT2tl(dl%h>0@NJFhf(YtUDSA248##cOcF^0Gz0+@Lhcm za`49Q2pHN{7~Yv_Ddz0g>mMi;GF@)X*&KT`m)J=7 zWGeu)eu8lW3>lz^6?>mOD%YFluzg?O(FD#zQo5!VRPM^{pMm5Af&m`hE zkzoDBXi|3=jjAqg?ii#&6b2;xyHXy2vSR&DHemgUTp}>Z@evn&47S<-_YHy14J8Xm z9yU3y+RP_PX=*X8<5r7cx5q`i-JxeG^fuD$Rn_gxvG5q)O>{CJ%Z0aN! zk%*bz>!Jpp-n%>F1i$XicpHGtfm0Fo>8@KD-oH==GlUH_KUs_h8fE?5?F9o7mSLdr zlXBwmulM+Xs>16l%J-8Q_Hb-|zK`z=5^?fhZ`ZL?7(`R-jYr2@c@2ACEB*s|c#a;BEq=WvkwE>nODyT5i! zN}_IAIY*zklaw6(5qwM*9=+dr^G_@@2x|L+o@{vz3kpm|F(|Kh6Ho?UdEXbjlH(h% z!tzW|U%DJ^C^rlLg);M)MgD|lfOpEjICE4$)e}P5g)P7!y6o0 zDEAs8l=)46m^6a#H?sISNS`kYObx1nL~WK)@3fi?FqSf?YaV?grB!$!c;^_F7kCD! z=PDNMs^>N4!{p%vgRWag4C=+b<{F%Ix*Uwu?%S`S!4msP=P*os`*-8G1%uAucm~jk z8I2aqY+em*CzLrjSqW4<80A;yz$Q=n9cbBL4p!r4I$R?%`!5Jl=e>Hq>g4CQO>mPvU-ZVHRdMCsX*G{`W|Dyb#oP+XTJV^1*rjbq0aV)1VhsEW z#9%=fGKiT?WY9KLXAr9=s?6lV$ptTF9F@KCF|gfFHV~uAn+Mk1Qza_tq(2_16&iCr zee*DV(9yoA&hY8oXPQFsB79fm%~ z_#f>T<`v|?_01*^m@1zi+2}jLZ!()7mhaNNl)9$&K)Oqt?0*ro;g@r@jdvNS+(T>Z z&OcuN4zG*Q0M(Q-XrNoNkX{0~=4gMfx!v70=WdUixCIny?wfX=*}v$WOXFKY)-O=# z=CS@fvYV|F1w~oz%qM$Q5fM0Ibz&~sTU~b02Y=7&oG%oaY~%i|8~Y^$D7v44is2!h znL(?sJm{;@U~Nc-3K zG&;gzgMD_%t393vAbj$u6|0i>=~D%DaHV@1J^i76wBL=(+uUv1r`mA!CHrM@(pBU~ zB*L6jG0q(n<132e=i0c++m?xf#ySGX{7@s&1rV)Pum#2gv|P=MvJ}C7a(Xtlkxe_G z>X-GoIC5-gu0{vYOo3J*bz~6yN5QePwiQm5di?|~js zK%tb84Z5G_0d?5opawhh}%R(On!dn)J^L zK)8F-@L}mAh`&-MOEeV~5jA|I)Juho=Jh0WDrv7`8Y$8Mj^Pz#QNjb&7f` zQcbEa!4j)?PR*bl6G_0NWi%emC?*95p*QFQn0O(736KwYkGt3Wk=4PPbg|;znUB`e zpsfBVJ#Zh50CYZS2$=-DP9njwZ$g?&$Cx@O=G)+l=v&al7)u(zm*1)C@C1Q1qnYOR zhJT|yo%CTe-V?j~?YB+%*6HykXLUn?oSmXn?ha#KjCA`aPrk|JzbV?7qmYxX=m|?B zcVDNM_jJqK&HWY}p1`Mx(@c>V62C3UlE)fUTHC->Cg~V|Cb62}Zi5U3HYs{6V;xJt zSSE#Fo|os*z~pd-aB^#r?kBs%VFn;U%f749FX)vr;qZa?DVU0v2c;D|ne(Iq=kSqBq1s01*jB{KbOES{Q;165}fuYAyO}!fK*|>ia3G{u+Yqv;0U}QrTvs2&YZcOo%v9L&K2xz*FDC%nBSrIT0Rcp5?99Bp2& z2j7k|&-bO;A6y8ZTG%C{dw#%7ntYf6`P};DLIe*F;j3P*`ohmis!#6?Lf)9m7M|8G z@13V-_1^^{;~V0f1~+pL^TJPY%DCmfN7(Q{XjPZ^uSb4!JJ4Q$Q3DD z?ys=-@gQQ9?s6{&B=f$n|4JzOC2&Wr+`}T$H)DS&iA0&FwLc}sboJvm<<&Nh%~QR@ zaDIwL;~o)qyT=UL;ROp^=@fUd{1K=kE|X?u3T^paw{pvoxIC5SLO4M}mIhaenvU)2 z`Z|rz2V}6Zq^W75q|u?ZEw#=yklRp_M#F#(U>tDwGD^Ar0=~$;FXFK7vMcE4$VNN| z^^&D(GvIUkl83Juhe1xGPGnOO7Du#2FMOUZPoU`@#ev=Pfv%KnkssQc?wkqReX4Y%lK@qj`J%_w$k!q$1XKB(vJMoA zkY(c2CpsLuT~xd51Tt-QPYeWxd!12B!17$_r^^K4Owt)$fO3{wCh;Hv2gd4@3ND1N zccE8@$Jh-=kN5>dWY;dmDfQ%v+$O@RJl_3_cj4EmN2yhU28SI&e6>e`yWLZ)f|Cy{ zEUP_4 z!$bVoqhXNADSo;cM;gr}M;x9za;dlf0QAkn%tavt1IAh7Geqmd8F$6khFnKAO*$_i zu@xoTp6*LU++cjJC05Q3VoltQolz|qI{cmfMT`=9zm*cGJ9$RZ)xir;gI5`h7EsM! zKK@4W)3!4jH!kY@?yg@_%sxKp;DRSU zukz3*SWaZ<>2k94T+G|7u#$pcN11HuFTYt0fRPr}*Epi*ZZC$@<<0s-=ZaBKbqnOQepuj3hLg~S6HQO9sL zrF$jM56};*-h2sEYDb`xrh3=h=?cgH@av;!Z#Cl@G;tF>i%W9l!~1BXAKou7Ij?d0 zcrFLbROBRC5}Kn;mS|@-+F7a*T@n>hl>z)COIv>9N%dLI#PfX1i~#b}w83vPPUA!> z0z1m2GhFH$V?n`F!9!__*-Fmjv4|d4SBkx`y|qe*Pbp-7SA?QV(l_KWH1q5u%lCR{pml6HFR+eDXh>V_VuC3!&gbRcRkv-K}R1Q%1T^w0LwM?;tQa z05%}P#YZajOF8XcBDGC+8p;X=QqgN7A#WZ|%P|Q%z{4_cw_NV>TYam_V`|){h)oAE z|IJ*GgWY6t;(*~P=<4+Gtvm_Enb3z{Ws~^=jxHeFuAe^{0I1qbL6A<(F$PS~NdsQ7 z*3!Iu84xf>+vTleK$dNTS5_a5j`%peQuY5+>(pTO+HTMXkUgro1;p~k}}bgHJB%o^Fgg%GhpQXfg?A} zUk#&s9hnIas8`>UN`-%CDYX=>XmbF)D`kFq@-%EH3jBfBpuRaRv;vOOa}w>er&>E-FKcsqa*Zm6 z5>Evo@cj!Bk&jfyygK^bdso~^eiIKoQj4>8qWdR6_QNjb9sHX!{fEVvNH;!5U6zpq z&8|YjR$r^BC4x@MiRubxB*!!0b*x;bXWWm7h(HVAYCii21+-&i8FXS39?22R-G9#7 zD}$BRXMnZ!8Srr%T*Yw9I1;qI5{1!@gI_%gYqM`w84=6+k2usbDLJ+LE zY4_CAHVuM^lN)$BZhvK#ZRyac2Xj*jjQj=iDKv-K*@}f#*H>56anNjxVA6ynz_oF$ zD%WziJaG+gf>fH{pQaNR{mEke9IL5L@vCE$b6DTwUDkwpK!-aNzVFTs%o2aqXIW<0 zYOsdY?FNN-sl8J9R<8R=VNJW%m*BvsrxFa@@asurs$DC^h%ZHX4?2)Q73+RAQluZ; zmaH?Kxijj2_fj=z;iM&+Xd;!S$fmkkf3{*dz%yD@)a$rSXU_=jvW<@!#}>tD^(4== z*g7*ue;WH(A&l+E>RFWPX>Rt}>Y-+W9-Z710`yvp?t@lO`@DW+yO3!`3*>P^S%oO6 zB(zfP!k#^Y`?>O_7~{NI?nw3b^@Q~Bb0_pUpJO6^XraCgV_N$e@&dUpPuQFlRy5#juptGG_%X%}Y)q)9L6V!gXwY2HPwy=z>{3fgG_>*zhF-!i5E2TBLyVR;?8n_FGU zEShhH%hK53Bl{fuu9D%UV9!BLL?@;w=e2sI4O;Wh480E|!wxB)yol5%HOFdF!WBDL zuCY)q__YB1WmMN})$j4ig$4eEUxFgiL-}F{DxQXlDItbc0;Zuz|6K-N?sF0UCBF|{ z$}7gUa}6Ku%$fXS5l}D!ajj%c{Z}BP&sq1_z*fH81;1NCPW$;;_xCk?p?Mq^k}Yb5 z>7s0;hloG&h5+Gm{I-c1qRVrzI+93qY>8DE0e7b4htxMbQw0Pa-nCe zE^%;{qi@BR>%|~U>Pl$fsB)&g7L3x5VHaPBux?G_bs&?}q=!b}DJX1yJ*mB$O@9t* zOTfi=Y9rBOqAde7-s`h+(S^1NjI4@xsU6D``g+mshtN4es5GnDdq8AVOyhfm-&uSw z^m2#~RQAh~w-fMq%NlSV&^AbFy$31(XY8>;VCyA38$y>1u1PT4`dm$H4iD=C#@Y**c|gO#{m$`PBA(yJEpwASufP zpuhhTt*eyXs6O(lOUor-Ho6-w`m5x_GjefPLr^80^U4BM)uu1;Fn7{{N9XAhVBdZT z!3uIK?N?|pw%rz{g_Eg5+cE?{S+q}JA9(Dkz?d(c28CQK3#S{<-ArBP@=sH3xS~FG@W&E z%9PI&eL?RTwJCQOkEfb!?~0-U2^IpE&RoEyU;45r6DGsJE}DI?c!wn2Sr73uPYbTNY#{5LJ{QqCm$8a4xSccq z@d7X(de8`A?^TX12jYXV&WBL_l?GLxzUbR)N4@tz_mC()|b1c4X1UW&9u@he?A`o+f}shM>+~;831yYa-+tdfYoN0GvLkitaS-)8vkN+k0>fi(TQ9eC+_(84kpzRp5onaZXnQ19-cy{6 zR^|~NEmkh~WGWn5t9)>0cS(B^QgE6vzLdAVv6xY?^QNI&2q!Os5uc-QhV6olEY1UOqT@%xXs=aY><9j>t zZLe@5ypm`PRi4Jvx*IFXT$2zIPuJjXBZwS*y{K}3D{Ri?<6(?=Q%jkKK(Ga?fTEV6 zewDN}aJS5-H&q@7;$1T`-_w2XuFp_+J_M!xW&UtB9S%ZkD(F0m&FIg~(_y~WB6-bk zxvXtI*B1IC2+EVbfD*Dv*MExA^-?x#cFhR#^C4VMGI43(tzXr%DFL-6bpxkdMA>b7=+*Kvy+9q|tUci_JhtdK4DlEMWugvmjA=kw%(c6@#gB0z9t@M7s< zN|EqmSXMGk0znAuHE{G^>qBI7_roO<$2Bx{P>CptRR-X58GkK`m6jlMGJZH6!MqS( zyufqR1AP&X*|;6nUj9Nm(Fc?w8^FLnmPR3!ZZaf1IM520H!N#KKAtAZhIC9gyi+3O z_Il4xW%IrhRxa!UuIQCOH|QxRc9Pn-Ig<6Rm#hUk``uo<6)kqw0|1lE>!)mw9-E`2 z*uF-nwb-(JLz&tvWu0L~;S4vr7q*DF8Eq}$Z_^` zxAHIVbv|~PV;oiy!rBj1$RSU}n8iehBcLKLgO0kc&%scqGBb)R)`aor!9pga*AaXC z4qeUnw9(Ckmgn3S5+hhLVN$*?605(TX-n|OuEB=cr3=q?5M`{G?!&Q!GiglU6JFWt zc9Zd8O=Nb_YPme=UTp}YVynLPY+#;<592tGR~~2otblgnX~?~dMP}eGMe#K5NoDUB zUD>@?8ay92QJG2W7;9c!xYuJIs*JAjuG~b$pIYo*lDhgDV$~}ReMyXkuK>nZ=eIyH+I5AEAv~gvY|93dtO0o2`mFq z>z@L-_bDpkcMaTSUXOL<3E)u51u^!;tINc>K6pr zSFTUCeF{)b>}Cqc3!1AHtaMejJt{s7>GR{N;~c)sZ9k@{iyyLSuo9enA?*3VB2bT& z{)<6MkiAF9MPm^QEK*wY`SUrZ}i?)>T`S+dbmgJC%cmb-^>!EKM3+3v` z)7OI5Tv^#J@v-Kw7h06nA(gBI+{9G3jmvH=Zalv0QE3k6rIL#$^{+UpZAaQ&^qzn8 z4WTc07h3*@`>LaUkVJ5VN(0gr4hEz-a9-E*V%Ed=cj@7NceOk($v6fmp3}>SKxBxf z;Y~>a-6DZfbfaz>&{?G4So{5BV@M#r1OZ;Ml5U{;J@(uLFVKC<1J$M+nhur-m|A?S z7MBOZH2!9-4#~EUgnxq>Yz?Fe&&jpu7)1G&Q-PPZ+@(34c$NT!7hk7Mh{QR#7_V5( zl&<|5eWB>nXfPeg4PO*_385U7iOhyi;D*wLilzoW4>G}ds(pk^Di-S?)o5W}uKdzw zonjGTvZUEs)Oi}#j)C1t3KcH2SNCs%c!bw8Y#T`KXQK~&UWZ#LVUMLH{Mref76-d_ z_1=^yp_1Y^DOEBAV%rAX14@0>`;?;=JvP+tU~WhB3^PM^*4f%Wx3eiqVi&OeE4&+o z)SDl)t5+I3sNSs0NR-lO zVz|PU2pZS#1_s*_NVJE#{Hm5_wGg{red*jD2sc2D*IDse;SD={m+XTGlddRB)1t`a z=kV4nDm2DksRmjo@i0B?lGYiy9!Ecd5b7;8f)@qBV$n_ozN&dRQI{UAz+mDysf`YL3T_95GI1&rnu};OM9RGQa0K*fmDO8(rT-|-{!zL2?lu^AgsR{dbbl<~R%_<3t-uRKtPGFs zWvmJCBz)NgLjv@*d_|y?Ki<78Xgl@_p$rdJm=vRaO;8srlp0HtCmPI|1mlMp9Od-t z#2Ua_)#ySZsPqgDsJHdr`@l39fzL?u`gx7p+D(8zguN7R$?Ac$?zGnr9fwk_Hh;Jwr9smrcrhQT z%6)iL&%DL1b!5l~_WkCLQ%v|OVy^9>#n3%eq4M6*Fuf>fUall@CoA4&@3#*GoSA+< zb%i4=VwCD%iGF7^V^6s5jX^gd?R!D@DQi)~qv3!Xj^F^8z0MMCrIT)pUG9?3IDPvF zeP&q|PHx~w$uFNOME)^FUvL6GUD#JLeqL9BHNEMLt?1B+mj1BB%Q6a&u;}t8*ayGE zJ4(~6v7gd>E`!o7jq}a(NJVB^&DSISt<0@tiB>8{Wa2A*J1lEIY(8APWJUadO8LqW zV21Rt~#GDmMKj!7Ho0l9V z9iH0V!tMtY!e%zIVJ+SlPjP1pPhV5SKPFHVbq|R2uI}Ey)hpEfq&KM!MtO2{g2K0b ztd|0Mi3L7-C`EJ6#;0$SYNc%WV2wNtSYZ;4iPyxOk?u)09Jzjr8fX(k<#ZzC0ZZr? zO?@R4Y2Ae;AA81-&q0vUOe&foIPvHyX)*&!-V>+Wn(Io&@VQTuE^e1gjadtnrRz3Xt|(WXG)IvLsWd7ENxaqo_Kqm1S!j|jANw}nhe zpW01Ej-qx~=D)P60EC4C`}X$6c>lJw+B9T+jw&7du7+yJC>(J1#FzlmsS}+-%45_Qt2k<^dots69n-0(ivj zbg^8aSZ_hY_ObLnm{8+9$W<$V>4}a6KttaXJ*Vx}#OeagMcNe-Nk64nO1y7~oJAz} zj$zFrBcj)Zy{3}c0ZkB;VzurKis#ed3ON+tmyFKFIIKVl<1bVZjWj9i#r)8XxkFOw zQ{+?lBFkSRx3U=A4`0n?E!fNAP${VikXB9Dgp8x|EyG?wG zzJNPn{A|`7tE<;=W8k`@|3#Baw?_r=B<7-C6-X$mpwocRI((j1A`PmMqC>M@gs2$C zwQEd%V!w3)8mvdPL(BQQ_`B@g8SJK^4+y8SoG43%>#RzcN=q{&c`XlOs#-NN{vTUs z9aidfja&7p^+8x6|p|KYgXm{ zxtdG?%p41!ud^)jcWXLtZD05{?01~^iX;OzixTzz^6A%y@GV1QtrvlbwqyRQlx}6e z9X+hw)y5dU`V*u3l$q2UTOAvjx2Sdw5VksBLo^fXPIMu2+qQlCF!7ka|7vJmjBI%D zGz#O&Om-Wonjp!iT186Qse>^~E@jf3Z;>1KeP-0qcl!Iw5irdlPBgyV@L6RfE3c+? zYrDdD-qYW=;zshjKdM)CfPdU~X7;X&X(H8BLwEg*Q>v zwWKIWDQ&Ki)QxF94G%CgCiqF6TnvBdC=%7${NkW<=6*WiW`hL)1$;ucTN%|8Fh|aM zN_vNpCm6JP!;q8&uoX(;$FQq(d?=o{o4;38D7y ziN8u%z%!kwTNjHO6MjpgePgVAQHb>UR5cezLuxynS3hk4#2xb6Xo^hNPTLyAYh>*Q(oZ z7Doi-f2JLXOJTM7ygzL@Ef&fRtG$i5e(dxAcOUEDoz(a{d;uGGt06?^jjBO~{42pi zU_|#_8!erhQl7z!uY{q6-?unH5~4`=P5T!pKNxhB!1|#)_#eo{@`dh+6j`L`NIkpR z3VC5ez*CcOKx7}G6{x1gH=7VFf_sheHJy|xOJ4@mf@=|i=g=Uk>%cu)ji^GkD`+A# zSt5kyTr4+H!Yx`{RBwSmipr%Zh-JG(Q2UyZe!B36#U^V>L{@!+3TA2wXaZ#^2MAGo zX42#L-@O10o!r< z(}3nmh&>AotXiOA*cvMo8?#W`clI?J6wYgLw1!<~2^n?y^>)8=m8;I#+ZWKZScrw4 z+fdV|D_zf1=v=_Or90YlegxuDLE3=p;9hcm7qP@zMJ_sY_03k%$I2WiT*SH((m(|c zgKj9v*!8n5L>qbffDfW8H;L%4EDWhbPG-AZkeriuZ^QSFFD??NP44N3qQAb~wS_o@ z<|nHp>sMvamJipdE9^{GLc78h>0lA~5?~jsIXrvRe&Wg4f(${{g|KN6Qzyv8B8(5= z9BgEHV~JVF=2JoHIvx{eh17bMu=PP(&dOg(m$to(yK^A<+%O>LX2K?p2USA=6k!&%;IA>2qDtscFS+^S_KbL()1m(|g0 zV=?SMHv<|jR%1iu$-2_C)Fp1Y%t@?y<&czX^N3mbE9FciBHL&3^g;s$4oGwph}1t! zy&uzV7w4xXwaVk#C)4+0>|}+1c<2k?ygt+Kpc*Sy>FBpmodWE%r=x}ex`&O!D4lZp zBN?&2K+#|c-=zHto9=QXO&xbHlmE;Q?=Ms+^U*{~z(qs~7W1hMsIz5ErbBBNr#_3z z3TM9fw5$f@SM>E!J2B$w7MdQa6Wq_Qc^fGh=wV!eSbJgw**yqje=1Dw?keF7Ka>Jr zR>Cd4zNB76-5{6v0ndj3+Ecp_&V;z9$E(UPqQ^5dsLpL$bDRsuHa}%pAkuGD!ey*K z#g(Asox8wBK<5=DODcA2B~D1ByJku{Y3MjdhMt;dT?k`@ zX9Dd?QoK@bC-p3UgStGnoXWfvO6YB^!U7W}5&S3ICgQ_ocylxxb>3KF6@p#Pj$jL$ zn!5aBi6l0(x(wCXe8Rt&0H_K;9ccj#>n!a9hk*u8soXye(E^QNa+O27(rrsp3b(*y zdwpG4egRh{Za0~(f!J1{vglb8v;$SHz@b{KC-IM$l9mGw8UF4~4Em`~gR+1jH~uNYdg8+WGx@egfU1MXfG4 zAeaKThP-QZ9(AJZ3uU?7-ljU4{mMB^zCnn>5>Z_?;8WF0YkfrQzt1;+*TdM8VoMU0k?#vEMjRzUIe$frfZdSCdLqPQ*TPZAJQp z7lsB=g?2y1Ue91MYK-;};k25x{o%$kWf=#G>U7?JgAL{ws;B~1>S7K1y#W}lijp}< z5>zCMIRiyjl#WN@-StRL(rY=0T}*>=@rwn#)v?t58tHmCEb$)>JB0D8l2?2L65M>Q+w^r%MCedoRvT3F{_iK}UpmSubON>8Vf zw0@YR3iG!Ye6}0W@HEP@&B9(qgCAx`Q2HoL!`-n*NhspI;`4mB5Ql#pv^z7v;#l8K zlB_S=sBFtOsK&4x1Wqq2ZDCds;#o^~aR5;&slV68n=pf(nd!!eb~?IeXBE42vcfJROWt3W1+?4i^86&k{} zZkz4Ww2h;(1jhasyoau5%okKO_LV;SC}WQ+lztYDJJYs?K1ac%HGYG3;sQYnO_ny$ zI;B&Mw?PMMOwZrxA5s~J$&rq5S7q15%^$t$EyNeWP&y%4TQU}wGe#P!u`#KtIk#aKehatxS?x) zZaRTlNp<%GN%ACC@6}g1#!Jjl3B0!jA>;*4@w2oRnQkmJHxm_pbtgov*w1c3pP44I z3#S~Q+cyUBC+!3cf5R664xfn9)eVd-{^K|i^mDth#6+=jul|=A;pwd% zlRD)nf@L1RJFS(x4FGD17a747*`Kc+{!UeY6;y@Hl@ryhqar+*?dhv~AXz~}jTS17 z(qg7AKZ4=`9^4XX_vDw>=W5Swo9YKLs4^gAZQE$A?un%R>9gdSDW&lB)^3k)j8cYQ z!B29+c~RSQpJ?q~`>c2KUU;2}xCiJ3U^{dhwuo5jHHD635VFFA;!-v1t_0t|pSkOMp!#oa~h^ z3^5db=mYCZNdpU_B*GlgCTXct3)jRTgk^?Y6?|rcQ8Nb($8P7H!HrvV zW7;M3<@kJX`|l|h&Zpxzy1KzuCJ>y?<03nTy%9HFuR&yI05R13G<|nfXl3jq3WY!% z|E2a#y!0>hT-2BC#G+Yvy%EFTC(?#saM`=$)!L(0Wu{@fS%`@R(32|fkir_h=RxIr znq+hL;&Kn^=t58w1>c4q#&>r~H*mYfwt}b}0Uz=q#!D$Yz0SlatjX^c=}V z14_kPg@OU=gNg{HXsMkKi+{IzcC$DZDW8gF^PABSbIfJsZJUjq`|N9S1Q3_alsv=q zL(y9nZ}DNt_GB>@WW;;L6l?m4kQ)o*Sdn*kcw+ z*;apXBoF*BJ5 z-lWScuv%!cdyrt2`aO7@h zgiK*X9IJ8>hJi3bgx1VxI}+22M}%pd$xO0WnV>G{j~cr>Si<>|T}_Yw_zjop9nOSxlaYr38*+UmV_-ZC(@Cj9r6hatxq`Q4 z-9iVsLpB3yu_0zue?q~BZbrGF#7JxIcF4TJj|qQqKRC-%<4!gU%Mr7VrF%v3TE68$ z$K89G&$>ru$~)ugwyN%_C7(`>zW@2L?Ncm6fpY%Kwarz%?uXymm42!a#uD?(CFY_i zx;Pd1_TPgSL_K1siK_^MSeC!=Df;|gS^VIzXzbR^(lGz+a!*EzSTtcC|Haun&G8}^ z*9ryEv*4x|>F@oNIi2`YPX3llp>^b*ttZ2*u78KA2 zwB(FrvDA8R3rLIk>Vap;a7&@y@Fp%x0vvKs7-^&D+g99R-*1{3VJDmXJCzJR*l)YqgbSHV8HPRdA`+D_lpWdWK*P$c0+-BtBLE?j=k2LxB@t zOoegOJ}?inAE*1Ksb#>_5^2wLs8Jrt`eeWEE<%Sg8{2DDV=}a%ZA|=Q6(+S)Ik|%b zz5D_#R_Q^S$IzRg*E(k)N3pIJ^!O}`a>-NW(2zwUrem)}*uhen8UJlSzL;VEk|}!9 znze{K=3n!{3x1u82!5n;_jrp=<#?o-H@?U7xBoB>!L%yv)3hsmoC_OJc}H?OT$p{c z1Ll|&4(5>e@njf!+Mm}EIz$%RQ9hPi>>VN7+VX{Vlgl_XQG-Py!d3?&YIV#;}sz&g9#JspUFQsSn871C12^%>Jnru;aGV^ z4aI+Uko>`Au;TD8EVUn5yWzbvuk8HLsJY$Y-T@aUBcE4SZm>2Z*)gGtb|q zc|^Ci0RqEM0Fk-yRj+JtubZ_{CIT(mD_yXWB^0nr0+g;~?hy|UlJv^x2m|Rzjk0g9 z+usGgEVL*M^7>i>?;Y}p1m^o?)X$bW?$imBwCboWMo?~l&HO;PNzPebFrs7po_ch- z<1Fty^}A0s%R;4K4QlfjnrC&>2ZtVGO@6b6rXQoPB&PF?XyrZQN~RMHs$bQAh`ei5 zdCRbI%=L9Di?t;|caArL?q;2!pQGYj4 z{A%mR%Wg=+pL#4aWESAY*#5$CQ;7f#@k&5g9u~-mcGk}p?mjW! zG|yT|)F@AF-GzYu`R6bCf}PR0GeE>3>Ip&(OhFUXJC<(8YbI@@K*2TSr~Ua2wv+oh z^pUIChfRJ4z8$sR!S?;DdU4W@&*OMwDbXj@sP%)hP?DBRQ=Uw^o{R|YC*~BW(=ogv zArIVSay=0oGi%0lwwApiFd<*1moMHDO)#DB(?pIVTPSPKnBlmvGIb-aeqdBxV2cYc_cbhCE)@Gnotu2tEwj9n1d1?}Syq=z*@H zT|(OAZ-@X*evfPazGJrgrF>{G3y(>MzJx`Ow+!nS`p4!dGI!E7VU^UCv+mZ zlya*p5=}JYTRF>+gHJL7FfQp#r*ZfAmlNE??@tt&Qe4q+wKkl4m%BVZJqOdH`0PyQ zu~(SC^~wzDu4`VY-HKU?tM48Bz7OOUsT2$znwVwY8XF-?D4%>(X(eQaK$l0 z!CQ9!e7<=t$V4?Ov_9A=dTL!Ug|(ct7lVnAicP!7k%))1$Nu3^gUW2)wu>p>I1|+X zf8uMQv>G!m+bbR2SE`TcOAd)i-ZsniigheDN}IBzD!i4SRar`Yx;Hz4DJac{t7`eg z7=+@URwQUYFm?IE7vlN5vL&x8o$i|K0+~v@l|h^ z(%14_7>1>7OK3SjsXYBV#{gOn06tEe<&D@fXCMhxo2z=wDB-Q+VAZl=4C$P&k9Lx_ z-1~gazju^Pd0ExRlI2-W`m*gZRF|yFQjXBs{S4DQ%z7Win2sc(*%3_TtjRUxP?PCo zZA`c-bJbba+_x=qH#=VXmA;VeOK(@zo*ylim3;lRX6HF3Xu3q>igDR7>Yd-pef>G$ z0T~Cgd7x>*sBAWSmh(l)9uhaAx?`NG7sfg6#Pd+CIdegoo$&0vzd6PcXs)jJa5CoA zQdg-p#n)xG@&5;tZWnJ?r_eP^U1hvTiK@&*#R+Y8Ey(?8_!ERuE&$V{lKR>>eCaBo z8?+bhv>dhPMB#J%03ic4Xtd9G&GuWPVVG`XrIE4Pz+_Aww_f7+0$o%$W6(lsaYm}d0h>jv=N#^7S*cdv zw`DIrnCdt>m#=-*s$8pqtYhs}q*+?$%JSHL#H)Z?d;@kpiZTYxtoVXhVt{^=T)8*A`|RSObJ=&rC}?@w>{mc zyV^56+a;Mn#g|obsokk|+6<4VgQhd&^~u_^<(km&n=(1b2)#!P)|*!8JXw58$|GfduOJ z_5Lo^0*MMgXb*x&U%C*dIJ-BL@*(4)WW`t-y`ZmW4=)lcLJ0`_AN@^FG(r*^1w)1!lYSgbE{{(VEhxgzqBLm@B@-&y-7q zuHRiwWfz(pE+gjhu=bo*Hm;NI6U-f;o@D$~^m(po>*An}rm=&?`+-vWJw2nmPfsC(@ ze@*q0LP6T{B_f2XxXjY#YPJn z8d1!DSF}f}hy&;&f-(k(u`R?;Y_~u5v=!ga`eXF?A#Rt2N~|6633^_XT-aA>=|Z!Q zu+VhMwQ$<81xVyaL0%j|a~!z6;g*z470?TL9X`DJiuT+AHU|}=$V*c7T(0(v64Em- zN*1d69_*}Df_7oTl`Yd3?V}#BEY{Uej1>2ZRQBWhryL`1E8V_cyhq0xiH4-DkbYq^ zj+CVt#7)-J$!UD~HG#Q|;rC7F&fdqQQXJxx>@9-jJhwcFPMshw}BX7XKyaJ0BU_6y?^3ndR^jrU9X1ZHy19X z0B{A;4uJhxY1WuTy{kh@bX>2(^$R6tuIh4FP1ct_4tC0t7uo9E4kq-&r#c)5+}DvJ z7$}7qYf-*5)5P!Yk2&*{&6Kb*n1ow5Dc;j%?~TGP+m)M*Y$mn&vFQmbKOPfgL4t0y z2Y0&FqB*}~t<&Gg+$|TW<<)A>P8Qx-s zed?VhTBpW^*j)tUmES=I_Tn0JN#_8xh~`m9L#2KfQPz7y}CKKD$n`&Bc%}88&5Vd{aMC=wr&rRpB-Jam~BCel9TvYH&#HU4qjF@LH ztH2a=9@zS6ln4|@K zXkd|cYXGmiuMafVh@GqetT|hquK~m2)xJ=_=}XwC@jidGyOK zvCeVN5at&!#^oI1rdF4F#VMf~5*pP-^66{ry?)~*FG{KUG<=G#Xe?w}R7Sn;HsNWL z;P5wKZb=-bme5RfV84Xg5=nibLeAv^x5BYKb=mX z#b%G2p0B(BYzOHy9=0k#p8D9)@pf|r{{b5g0QDOzFA$wX0j_6K{-50diU`5atgda~ zht~^GG8Dcwve2lu;($>Q$R?-xFAFSWE1R&quEzrLtzdqILq`&zbj*PCRRV(+yOP)Y z{r$PRh?}b;IWS6CjcYRyOELk}V*dbTTao+*qtwQ8@Z~mYqp(JL=U_`78QoeB93EKD z7XR*$|IlV_qMDQIPk>~p?zr!-Z%udey6;@o5=sHrth8DyxJ2qKEHSsIUr}%gM8WAq zoZ^Wels)Y1{nsY+sJ+Jy8f|`tR40q28S5S9vugQc2jb(a{hiAxg;)Ds-k6WOHm6Mf zjxc2RQ9d|6OuOY$Xshp_Wl_Z6SxZ5Uf1TuWZzQ{=FgfSX4LLEH{)A6l-c%fjl=y(M zQr(#J%3+7tZ!y@X3L}u=haL{*cyrcgA-`aaqSHtC0WxBper3IEEfVn>1;7=Zq3MLn z>+yUW{^^Yb!`;>K^AGO_xfZMYz8EHyXu7w>bnhD6{<=Oz$mgyz`gRhA{RmY;gu))7oH$q@mL;re=@%6WRNM{HuaWKR6=`LkPv%Q zWpT7Pi|EqYbj7j+#bIKP%dg$l`TVVm;Kb}wW5r=^YOig$Vaq*F`%1f-edX02Pfa&o z8GXk`2WDgs;y6DGL|9pDh=w%#x};r` z#M_s-YC?G(JD*n4hi<-PJ;QYFi8H1FIjiQ&{Y%T*jT%Dtw}1TGgxOxm>HGeWw0F)E zoDhucjSo72F}|&Z*?IHq?|}vuNV!A49JmX$U%E93vN9JPOn=Zn^MPY4jA`d8y; zBWWB(fSdf`;c@>nbh=9KZJ%D!p;$Bij#x7fCV3vYh`^(>5yCD?o@gxkO9=B^{9OE< zLzta~N8XyzS;xb+;jP8RmfLUJWTqyg8!n?72AOB=M`0LK?tq%X0AQ`~uU|1OTqA+j z<(8pgpy#1nC@-k>(0$s&mPoB21bC=1)J_N6&6G)!zED7??5`IuMyI&PlfDQTa%f?r zR?3fTy_~arLI^i_peaDOd^?6YyT4iOFkr zw{s=PqmPeJx|-9Xk3ZS$HCIg_45u^2%WT|=jg$H^Kh+Ek2qb*| z-KQBs9p(<(kTUkGP$r zZ@_!ih6JgAf6uJfFIh)ny!DJ^woI6sb|s#GF_lGJ{bLCZ@;J_6>R3@@-?g6T(r!wg zRfxaMNk9cbN0GK3)3i!C4b-QVA(SL+ zFye?~#1=Sf_5*g3piNf9bs<*3! zjXSTtAs>c2np+ieyFKrTrv{=wCYVr8E2(wCc^I zb*B%2Sh4mGpf~}D^@#w^-MHjT2P7f)e17H1W$HdcGD;_P`j9uVnLz)0m16~JDST&I z01^q&!3$`Yd;+-YLB}yZDnK*EY;-`D^q&HO zV^djG7VWe1H(uHjm=}$(j8js*5eG!5Ozhd)a0jlH&Om{p;*Rw(kk|W|eBdyYHNEVE zJIx|{W?HXR>}Mgjo>u`J=5v8Ryi5Y*qfx&vu))~&$PG)i!l#850u|-jzU1)9nP77LOLk{FiR!EU(%3+ybojy zGicz2oE|=Y@PCYc#kYHmhq3>qxC;!wGXOUhK~kxn1R|4+xoH?)&{HLs(|hRop-;1F z6Qk6M3ZqMkA-11%i0uI7rY?uB=UdF-x=2j095kKq*Q<--L)P}yp|7}w`T{ohdIP4R zc=gLt-^h?k=1rw?TfUY|ruPo~c2X;dg*ZbWlJw%v2L-EHr(oJc^NjeY3;N=FYE9W~ zR68}5TZu{iP+Xj!<&J^Vw&v8hxdY{=XbelyzKQgJC!_fWVj8DaBk?Lsm3EZ#&+(4+ zy@Hcpx!_+nV|#9x0eE-XkED#e2tcWBIaiUwI|}nv@V@lFS7_Yt+1jf2ao3C2fFmcN zBfHuiWDE)u{*^@U$WfKx-tE*YGSW1ZaFf)2@P(*IIMS4-{lJK$)G*=|Cs0dS`D?hW z+Gm`mO$;M|;~j$P(OJwS8eDYLUf9b(0am_5xD{rmFIJ)9IRallIW2Kc6R zYQ6qkds9`NgM{$cgIXdH@SEn*&RHx3otgaEFEEpJbz`eGQ|EN>8GlPw z0I2(H2G0G9Z~tj>t|=j0J#ayD_P5Np%O&`}mGc0zZa!6-qPD%dLXJuZd$(kis6FGu zpijf@*We%Cq1CSB_p4H*+z-l-(9bF7F^-|*)x>RdNokRu&eWT4h`|%d)*54Cy&in^ zn?ioQ^|HIB?=pL3D0GE38GXZ^)}1u$>0IZDaJzZKLN7^lkC}tNH01hYKp{9k{EGeX z>$~7+=G&tgYd=V6sFP8ktNCU92;j-ILH2??v?L8MiD-ajob(10x2GrlL|Vr0@i=Ts z%lrrv>HlR+!57zW{J=!iV4*_Jdm!WM0Eo1(^9T=1a0U&)aH6qOz99AcCA)I9RI=H< zRAMt+dhI|$GaUz6fsdmaD?pAq!*-iodhK1nrt~;DQs!yKN`^oB@kPU{9UIZK?fBG3 zHQrj`z@~e*i<1H63$!rFS=_51Use*KB#6=B8sS@0!t)cSdP+pr;5jj$tj||n$d|50 z*R!^>)uP-khxDKYt=2h}QHT5YZb?P1Zrk_Xlqd1fO#oV}?GuFQwgnxkgiinc3-SAb zSw=O~BqK1)>))Xithzq}XowFUhJZ7g3v>_S*{wB~L%IoL1*qZPc{oL-FFN&>spVw^ zzvm|0O)L%Ex8cuc8O<=PWZS*u4nEw?zOQGGCD<33rg zzh8dI;!gx&&0nIwkUe?L9z4#eJ00M7fQ>uF4gtWkwq zMje!WyH7(gRyM*^TG3lbo8*~kN$JO1<@K^*4xotAFFNNDsk4eau%olf4^b0 z=hin|^NGSZ5R~Y(Qq`pbrHg@dE=O`Oq_L{01$LY9RH?=k4p3<*2YUDOw5-DawjF<) zS>o607j+KqB~*S5mFTYKUBjkrUPBKi%G+Nr^{=2%182KyJ~9{k#kW8>TY z^DpW$zL2(vyx!_cZ)}&ek%^G+hWYEcyzg9}oY_Vf#1bTR6C4gN)MyUtIr1=!kdZuv zM(nQ;;Bfxeix>~x&MC_xNxex9jb&?a-4k`w$=zn!8>BUE%w@>rJ+cRH+uTLmWm-^b>!Bg8~FotPp3l!&(GtL7JDS> zxz3w{u}rDCsG?WqXO5(QF0~P`srov9y3|$nV&QYx(1WZ*Oy#0sDUdwYSnu-3PHKJk z_k#X&dx1YfK$*1F>B?FmM#h;pD!W~1&`fey(42xR4s{Ufl7XKhqGQHlBsI@f)6Lrq zvxFe^+t|oMJkRu@md;Iujm>6TBJR&MrY0{6yHRhtRLS&417^X?DM&6xxLAQw61yY4 z&Fm)oFA-bkzZIogs#ZCe!`YrSDLj2%*cZTgUw%CB-d0=|h)iqBy28}^RHvYA- zl(?5G{8b*RK+``gfWyU)fE0mHE&|2T$!8#RGQ66WniBnPW| zw}yM=1HE@r^+N}$WANayOOSpsoQ{^acO_avviq6-$GS>vGRw4E&lza2eu$ZDc%-E` zcGs}fIp0*B?f8|D@$tlk;r!dv%0u{ha3n(8<_I7xeQ;Bfy49mT7VA>5lLBw6F7dQy zc>bV20o97I#T}4P^K6&fqnksiJ#Tgjo>ZmPg`cv5r{GI1<0r@Mzh1=b7|FL?VqDEz z>G=K@71*E9865sPrNpPO+MISeCg)mYb|nkD{j~9uI~_jG9Kmep(Ejn?j#c!@8c4lOFVe`ImALwrq2WGGkQv^t*C%S)eu_0Ux8Lpy!u;3wwTpJDtjK)kOZjk9S8r?WUqbQpv4|*uKOl}W z>NE?g0P%Bmi;vq+_lh*2i|M3^tGjIs#GL{;QT25Yo=EaP-Z_?hL;Mf#_|KmEstSql zcA4}=Qo8fJ_koMFR9rCE!mh?2Z}P7n-!8K9P!{sKc-7N#(A^l_=%}1)lFf3Yi$dJe}!Df!jEjJv}xyra%-I1dgzDnWmo&2M}{0PUEnR9-!gG z`rnUnP43sLXPxMUAlFpZ_P1I2>lXXx!q6jKp*{ZLKmAEI#uEJY$4+3?z3!nNwS0i{ zY7B1B=*2hIbIQTUgu8`jVi1fea-ZSv@_K=p&UHOmTS^W$`rkw5JBF(M+AQsk^(c4V zea~B66Mk}J>wlj)ip|^jIHWBNY1tIEq7NC0{r?#E6~3p(-p{Tm&Zt}%3seO9S+-+I zgmVEDEt=c*<&yWUbqcprG28hIB2QvI_w&l3rz7}ZF99p^%Kh8V)uxv$4Q11hxsfjm z6DP|u{{7g=SEQj1>HJ(0bXG>vMYtbzr$5zq);;|mzGEOf+N%-AZafA{4x~2@^~8YU zoD`rq_ZE)fF z9z8v&7E{wQ&wtLN@q2xRTM+zn?eb#w#Sk$83S|OVs@-`oT7?-IQtNhRG6*Q7qc5&r zXbXZMS8GInG7V&L|F7fA4hec6KaOB5@X@j1stY=(eZ!fzv+MYmehp>cOyAoy4|Lx%EK2QQ%IA^CT&_tuMGl-&`uPeI&DDPetqi#M4>w)_z3FI7x z!!hZE_KR_`dVsrAwUrEj?k^cMC;nOT|G0;%qB?`&ZjIMx?rr96F1;uQHQ3)1{cLvn z&zKx!K2VNmut%K0?N23>Ceb`rN+hG&Z~SyH1in!U_;J9bA7Sfxl00=N7*U~m3GW)> zCN%(YrjN5Vro#YTmJ7J{ryy2GD0L7{Emo^2UwoZ*2~dtn05O$D`v2S3Jy@#@Px-0G z^O*T|tp|0D>cn^3|9i?~4&NrNI$1&5rh@2O^|{_0_38^; zUROK)prNO55kw*Tg$TuV4|i@fdhM<4pMg8>wjRZi3+|nGu!p`hH%@|w-ULou{($8h;^U1$ zjNiXD8y8alg*kz@>|$q4FAA za{d2XKO$ZQ$Rh&F!7wGt*jJADn*SW^R&lU^S2JRB0{}Q32P7QESoF-Gb$|W_Rn|Ej zR(gNXML`KtCH}L8`6X8dd#GO5s)DQ^wW#L~S4;=SF~ZM;1G)@ph3cid90fNCXE6>=aE+rz*mX@4`$ulVlsl)-zbRrM4bg; zOqERxA&)A+%2+1~$2Ym27=|(g3%}MCsco`f4+a6b-c-2`9S9Q>IF>z?!m*iN6=z-T z&yoQmewe^{v{Zy#=#|^)Mx1Jy=HTPQRfqfmNof??GA_$!AbnC4;yZv~Pz!QfAjWE~ zM8;q9UNU?H`n>~MwrvzyK(i`d)CV|l@!U=p4Od*`US!oH08v=BO+e(n(&4Z--{`OR}s>71Z+)%)9W9W{Ls33+`{D` zChl~3O06u`)Tp)_4`VURX<*W_0-*rVfEd*_WYi8+m?1xX1IHxs34{q!6}4$w;7^hO zxl_lyQ<;(DF)rKsSeBKgGdr8vIxDlMkJ~5P*1sy-2XOOIOjFJw4Uo;{((V zWbJxH2E1UiP(P5Q_uNcm5a*JK*_*|qtpLWI*AB25X3axjZf+AWJs`7yBvZ*La0D$z z)ye1`fJ_}jBApuYcrp$dct~^cST=2BbU>3#!meE30^N}BNg6q#O%9{&1OoDKoh-02 z_qdYd%nc}TzkQ?!tiGVgSA3e_ElpE{Z^PARLc_fFXIM_o&K&Vkj&=e0_nc>S*|O%rzGXzL2cz(t#nLo~QrM)J!Alwdty)#_1&cC(XFabxVon1)9bG^}z;>d~h|5 z>g(RaxBitimFV1iiogl0uBaNp49-hx`A!xz!!p36UR2mF0CqIc^zP@sNKgZw zWb~Ld-i9Q!85wGk6tW=_aLQ}F2MjZ%<2Vr!3bNxTK_zfYZn4vsu8|~nJlyP^&RJG8 zEyfJM?~i;_C{<@+pzmp3CRe{OB>b>y6?*(1Db7P6_{_%;!9Ty|oU@)g7f%^-yL`2P zR}E4K|6JbLED(=W53h5ZWmaVJ>0PnE`*YwC;eHYWL1e&_i%Sxs0dQ5;7pC<;%d|Lt zgW8M?i^w#%y3IbEQ^fIBvk4&5Gz&zUY#xCNGKj#`O58}=2jnqZ zx+eqX9%h;x3+gG^AXR_lN^SyO;3+4Nm#eKq^qLBdL@iu>^&2!!rm`+90&AiM#_RG$ zFTvYFak+N+L+1g-t2r;G8{9qFbPZ5%aPo@%Y|TL|2HXfeAP{L*64go%Wum_R0Ae)F z_YY4~;Tx4$qMsL2v9UTpX=3^cWH4#K^eDoGP=FCpdfKlqQ~LZ8z6g$ni}#tH5R#lTN!@wPMMXw2$M`6 zVaDWt8xF_PR)9NwDu0w9+jxK#wn}VE`3>B*y1ELlXb?}CyL4VQe>p{^IZ*XQ^$0=2 z-$JcfLB^iSEZ;fb`Kd`9qz@;(1|%<~ff~6^8njjht7$Zr);OvVp7y&I%>)>pQ0V}m zkv9w&_r?ItVi;)ji4sy42sk9x6ZG+=2u+BAG+#Q_5y{tXMQqgtknXD4;Vjq4$)lyx=ighPVDZ>;YK?yY~kgDOV4a4fh{D>&nHOO6>plRZauBJ8kw> zHO-iT%ddLnKn6iK;>91&Wku#G+>zu!?|;}S$gF+#K0j~U4L;ehE1f|inXwjM$zbZrrEYE`yLlI4<_1+}K0w0^MWj2*!2-MQDDA3I3X{4j=f zLA5}m!htNLvO&H0z69H9Ld^TtHCmsc4P4|6PHE1Kq>Qf@xLd-ve!WoJ%rb~MS-He9 z2V}$4pfEWQ7@GbDGHn-p({JsjD)o^Lxn3ZIR&lBsIYm{8MdD-y8LQ7e9{D_e1X4lc zEYS3)K=7-W!RUm*&0%`~*B5wHndu6>inr9AtUyrBo=|-HLKylsWwoh)c6%UBcz3$u z2nSvD3>1@p5ZOMZ`w*69n3m8&_vlnhE0^9*qj0a-5FBalP8407nGxX}odP|j3)W|J ztDsj zwwgdkgORX_q{Bsz#{OgMQQwbju{ zyDYAnwljXZ?N@-CO7ope9BB~Nk4Ve{n=cQ(66c34NAO?C$r~qvdKpF5KxSOSAN^}1 z2tX|rhC@Rt=^r{CZ{L~&A;HGxvmmDf5Tci|ka!A42K+)`LCGfEC9W3w?hm~SbRa+6 z#y>)UH3mo_I*ev!Ug|8=x-glY*UgfNBgQm=aF}PR8yDv37QurGISbiT>~1 zRN@4bSG?*id%@5g=$9dmEJAD|+Kr=Pke1B7$&I!#;{m!DqM+0^K-bsg7(>QA5dPY6?B#34P!EsW6ke!Nhvs4ILT`IT)H@8H&pDJ{q`nDV#SGCu#2cq4udn?B>IVA58# zWL=zbh9{N%67FA_CscRH`3FvN%ix1a!gZ=>stS4wf*ZjZP|hR%1{JKFR^}5D0)b8* zMb-AW#)D&$yf5)|tz;1ccl2dtw#QH4)((Pzrqo!7Uf5IBmQuaEyR4E=aGwP$>(X7$ ztn72P`QuB3iEehK$PwQap*XD6|sfj#tjHK z>u@$CKLkB$i=KC56Q&Y0a`WOC15jFpySZ65@*Onm?yfN*y7Q!0Lsgxm-leCrT}Ct zJ5A!zR#9)Uy7AU7@zBP=IpJSj!!gSG999s)Lj0XftklvUCt_pp6q7NVWI@@V1^XfSdPXLi#bGl!^A~tFG=J0{DNb^M5(~`_V z-j3jGlyL1MuFWCLKvEATOZj~=4pnMzzlADlaAJwRCI~bY(((&+sOPVOUA{=fk-8tv z6oeI6ad&28tBy&aMxP+A-1oeIMRg#-A)94LI(g`H$M<+W=uJd~vH}|Hp;#7e29ZZm zTTXPly}0-Vd^_iXw|~!TcyRsf>!jwwx1K+xguk+BA~1eG=b45hA1oL1ciSqf$R*In z{uQibQB``~plR^EZE|qGSL2$M)7rlGs7N%KpP`(zquWu+dbm?yRZ-^AQ1NE z9ZO&*$lI+{1Y+-XfKEs^FVmsdlc{6h%1XC{cq`CJoqQ-@e$z$B`%uhW(~-QJrWw|M z1p3myTC2Y}MHa0g-R8ukD22^F&_!28G5n$-M#yST?)Td06_QeS^N5B5t_wItUIJKDBMulr08gei2 zG>jr-pC62>zMVg9#698`@SvupIc1J~KBNA*sWHGgkZ4zyx5DMSTbW+Dik<#N?8oI| zag!;<8kWj&<~!esF|0TUhtW|PL|nI(<=%`RYj z-H`W1WAt?}%DNq!;{y*jVh>u}b-t2IAjP=mw&9a-(oG!GWiU0pA>k!HS6rxZ5sOl* zT0CjGPT9?sU-+(wGS=0)LZ#Ha$lWBSqPlTqRmWCeQ*HfBwnbbi7mT#jA2B3{qOUje z4@uoUje~t1HZ60mHnadMUf-nQS#wbxGHD`<|tJhM>8OM78H^^pvETdkhgJH!0* z*aPU$Aqd7Q*CLh3Ie&QYsvq2W)oAWB6LV}`p-!-Jn)s#8=I{n8FSbe>{<=BUpAeM7 z_al|9`-tfkd49L!+1AdDm6;ovmR>3Gh@jsH$rm6u1iX8v>s{&TUWRy3Tu-NbkF2*& zN}^-~?JG>i_*r7tr@wZD4y@r7?7aipeI~Plrh->@ziX?;1&8xde!NXCEGRx;VAc6q z=}3JzU5(uIUoWf``lEt$PylY-*P7Vw5aHo1Mivp>xCNolPyJ!P7mqVoD3bs zn7$Wj3n(!;H?4fvh|FVl;UTVgM`Ag!u3$j`Jr5sa^Hvy^SI--q}q|-VosX)>c}l*=ROm zlP!hb*wUulRinkdmcS1%5F2E(wW|0DnwuW<;yZ5y7g z425M3!FPm{knfQ1C0upiB;b`BG<-UeWyG`Y(b+#*YdW5Z-8)uz2dS87;vg8CJto=4 zYi5AU8ngGWUWRL8bB&jJk-qDAz%>1!OM`sc7m#4L&>!N#2dG$tJvPS z(?udJ@`ZMwm2RyD>l~`!MlIx2;Pec|hvu~p1vP2h_jkf)Rt@QPo+FCODj65&oKKtT zANM{i`KHPiT;#;yG8t}8O|wB6ZrsF+r`X|yiE}Tk8k>#Iut)O!L%+H^<)4uIXwt3= z=2ja$-Iz%;_z>*wFntdXzVqp|Ob&aR4Gr}z=A)UMw~g~-kJhhK(=1g^7-j1`T<1SG z?48tLyx*mNCWWqMj7?-LQK<7`z0Q?B^Z-`+;}N;HXiyv3PGkUtvya~2*7ngn|Gk8r z+YWWjkQSX#jAhs99QWBXYL8sW2YNMcGbsd>=*j10 zMn_g`w*DmN%j2r|@@LQMjsyi3YA~|mw-l-oM0 z@-1Sjamlzm*4w3EBCAElf+Z?pGQp0-9rJQ9CCzWNL^{YS2~^t<1!2cRwLwZU`uSY& zPMLOIRf5zE|3^y05!LXx&KO4O&RWG7QI?<{NCeN?u!btb9eEtQyBwZi;$eO=g|+R@ zd@E^B?9fLV*%)b1EHEBorqo#h6ei;Us!BGaKq_H|d4JT{7*~2wUA;rQzcvbm!mX$4 z^A^^O;C;eph2b9gg%XJ7n7d~SZ!2-S+cMD*bj}bLEIs39B=p>X#F6Uy!y2Dt6Y-x>a?}!!#T)2Tqz5| zu9ZOr!Q8ac??h)*jM4z_Y$qi#qwts3iP#h+x_b09FLyws1Ra+~Dw!9cAbYsG-hzIKJTa z+^9BuJ!FOW>;d|Y3CNEfE>b>_?HSx&{7!&g`tpu|x@Oe6gT%Q(J+^dE0HVT1+J4X6 zVhyM6o?XmN<9q{(v8id{)&h14xzYB#*JF|i#N4hBX8-#XVk>76iJ&M9z&IThv z`!ggkNQ<@5o7~~NiY)+fJ{UGc-icCu4hkx@FCuJ0T|bYq55H+J!bTLN3&8~5Jt;x6 zmKsU&^ZGA|3oE{Fu`$E{!YJV2BST4=7y;mMIf38WuX=Z_pDvuAz%!&7I@Z28dWxZ3 zs(roVok)cZYgz#&k1qhCMunUeui9}6Crgfpek9)H@UnaLqs6clyUql_a#=%3>4u}q z`J%N=^*eNg-Noo!^bA=?)Q=3UUL|UX8Au{@K zXp}1ji_Fuj6S!uuER)<|CM;I2b+nMub;USldk<2K44r2FKxM?MdZbQ|@hNnkNc(@y zXW93&r0WbTB`}~Q$-9>kMI(bNH~E-8h!>|K2BnNZo|5hH=yNuog9IG+NOgj+C`vKZ z>(omy4UkyjNck~fluEb0iv_ypL9oN2gBKAyVEkEr0F!Rs<*V6zqoy?~54XJ3MO4S=K&*PL9-(cnTJ0jd8w=e<|DuTe1LFpKJoX`~DAo-CjGrcvF3Jn@;He_PQ8#Xg~k225l_QS(*rzw z6|I;9sAvL@k)XdD+69ic>ZFz~_IIL;BAHL6Jo9wRucSAUbVdv|7sQZ)if2utVB*6_ z4uHVngg=cJ)IR$Ra2k71<}+b}1f~}Ge9R-?a_R_rI0A*{1Z{;uEoorLm26vQmM`!{ zh`)XSBXfSsjZ0C*NAnv_S#pg2T@~a`PT;-|g|FmD}@tz1Zu|>_QLT z;CI?!89&8D?r-g*n;iu1Hs3Ek0t-kf4?1sreL_4*U4s zP!R{SXYecC(a@eJlE6X#Mn$gkxw|>vkcr~|pn4b^TF|VWy;Y{X7Es>^^MrB{;N1f? z?~mJfNuq+Z+lL>T?}wzLTBm|6kP~ra%a2Dsj4yr3HITTxsRA^pJ8;QWt5(XkwM9Flk(C{_Qwq+yto(~&M#3h0w%2Ej|Bsz zEpf$PprwKOH6iux9NBm?>@F1}i?$)UPN|W^0P9y~aaOe1PODPdev~1N8o}Ww^o9EH z3}}PUxBpg9Pn%oXCVr+3v|yn%yvP^<{#acBd+l^ASAb%Xx z*YnG@s1Vy&U+!{y`oa}3kG}L`SOs{&kQahnhyLbxeGD36g@Mo3YS}bWCs4Eo$osm$ zwH%y0k;YW`Ot!Id9WnvxTbApK@4|1)k@{7a-m5x#9rW^eR;ZaPfnJf!1CKev9Ls#O z*5+X|*KG_pnr*SV-0XMdZdyLm)c;1++c?KZlcYo=W~IhKEsS{55jB_qy$CD;6YsFA zt@Nx2rF|!anq47}m61!}Dy-t%N5J%`usPx}<)a2cxr;Nd@S)g5TbybKc%wYLLUud6 zHEfH%C{QgyEF5;6)6LilQ!AlnLeEaC;=Kv67v=Db$h zPQ3MQh2jTRF+&N97Q*%(TLOyyLIAYT4jyl%4vH<=4sc>)QK2Mp$8Fpg_=3q^7&;ex zFAh4V00vPKRMQ5!qKC}n((2w(ZR1hH@0=o+J4nIt6^K&znZ-?yF%hL zpr=c1?xJfqC?rxCY{IyF-aPRARR9iN!ojjTU+HSb5SibTqeM)a$NjlJ*DRgTq}teC z8YNs7B)>6!I0Gk6}B1+7%NwvR-lv$dh_Rc*m70qqo(>_0*53pI?CxkuU;i1)J z0A7|L1K?%dg6dW$RfbsuHq{{zR^M)j>5+3Na{WB5HdS06OS9k=dn zHtp#K^yux~Z<9Tm`2P0w#p__#M|KuV@1|f5r+3bbsj6q}lv!mWIUMzhNnZPx7(~cf z*50*>)V6HY>%L2>uI|gDo*ml1pL{F)5z9MKM;e2w*@~vu-|dQYexlA>Xb|?*Z!vy| zR8<<3hb|`?jdO%+ZH1`Q=RffZxUb%VD-rs1`{UC1ZKe*-7bnN_mYv0#v;bP4p5_NntV0gJ2ZPvTjk#dyJgp!pYYOuc z;P{u0$O>AnWL}wmcnt4Yo1P5$y1wrXS?Uh&vKDhb$%IPzj;YQDJX5Q-ds<_+mP3(q zmI}d+nXvFVxbr%_MGi;3e^C~SVo+{O<@=Gw;L68%64`rqO?gF1QK{xpuL7dd$B_t# z4);83gVfK!3?x41poFp@ed1xn$oCUa5uU7d*__lAzSvi(I{gTJ_5K22$Jb4pN%s)L zrq56IIBjP|-F8|DGu_=%(*NxNBAS5|sCciwan<+gv||k{DbT`w@-{yjf8qi2b`;BY z=h+t{*Std3=6@B&k%TN0A4w21yA;?AOy$qrnP#5cf|A!rkxhHN#8f?rrBXg^^;F}d z;tV?SFk3OL`Oq@q(>E3C<&!!{Wi8$QG*U(ru6W>8aPgztP_`=8e)XG^7Y(#tk=fU2 zCtiDLIiPMBP~0M)rjaX;F?lfW9e={prG0ZF_#gr+Izw7qd(xrs&cP3;qu6f}b~i;Q*GGsTEFOuzub99=2UGt*{g z1ZW@_Xn=q*!H*p^s7C&PDE^>Z#Lxwm2vWo#-Od|q)%QZf+gQYzk#ei_1A`8W?RxCJ%w>TnK~OmU&7*VTr7&>+rRkoom$IoyCh=AD*kI2*Y&17nRuS; z)1aI{?Scg+vpq)qT!5lMjw*I1h#)ApPNn)df7x>r2I;k{@mc>Ms6r8&MlQyFZWKbI z;mO}!)+}59#a}BqnF(nGR z!4?72aJ(=K0|DRu>o2GV*}L$OT+QI^N&RIbi=_ZVRV3zwJt8EC zkqFEh0FsjqyXT0_Ny`54phxl-<}yGl#@-Z+LYA2iC~?|=1Y&cLO?orDRj&3y7S`4@ zB3CCEqg2?zYmIe0QI;8wTBR|L9E@U94@SeorFYWG33yr9x`|6dPF4uiidtzJ8As*% z%h73H|AY+N(;{{ic=;%A8%frJ;Tj?%FuULmKMMEt~*mZ zM~`avdcn~?S##r1#B^1!7gGt&q`$;|Ur!3hc=|AFxIT$Yj*job73Cd^^jjuVRr2C1K!gRY(Wth1ffoq zYMj;Uh7p)b_{DxO3-w0lSNJ-%$pLnqeC&eO`=@GoS4u=uy0!sb?U%6yYfT8uJF?7z z9PIYnif^%O=C=;+r_Q>E6h4ED9jqwHB+*5}_6sQAD${vd=I()w z$YKH61$%RPj*cYHvCdPuM*WWFDcpHX;K;unTEk>IxT7gFbsO%0PegJ_R;5@e&rhRB zR?}YHcBYnRPRTg%s3{lzLt`b#Ej%XI-OS=#lP?0Ep+cM11#tT!PBJ*1vUz2_7dnz| zbUsYiZ_?ogg(Gi>q@NEuOvDq^f8R-{24}GEJ?U2j^&H#Jgsk!a6AuOkIx1Gtfa*hk zgNF-(O%$$F=W%2WK(JxW?=(3ZJgplGMB)90mzJwpu! zMmcw{$m}~lM3b7EZUV=_<$9DP`Vu22on5Ho#lF?a-a!RYFZX3}^@NwyLhju|HeO1( zrZH$hsd@5ZOp?vrk)k>KV;=k}e1hV`=SxFW%K1(PxAm(JQuhvLhHK7R_Xc|4R3;M~ zLo{NSgNKIoQB@cWtua5+gl%qVK6)Yb&S8lm{&A9zdWW4zVP9+&U-y}7G>N9$aH*PN zfSIKT-%z7Y^o3ZGdGc}$pr+bd;V$onl~pa}!@_%&AEusu{cM5mV*=;Xd}Ld?hD7Bjm19d$SEoQlx&wm0e!8xbV|NSdldV000`K!PSX4#`Fshd7XOzXL*|j zfwLsb&t(ObNV)MU8+HL_H7*84kqn>1T?!|6G|*sS`PhSK^6Gw$XfG z%V+Ma7gY)ZERev>(xiCnbj4051`1yN!Y-BIblx<<`uhf|L1(M6D0+1qLqgn6gRGZk z$s5|X{Q%PRjudJ7eeh$g12-5>w>nqILy~919Fs+IE~bYQ_ZN4;Xmj^!Z!7+fekROB zuy0Spd#~^f>}u^kUx%BGknuQoG+XWVoxc+L%(T<`U6nQRE)>#UrOASAMJ`!>?>xnX z9o~plKE=2G@os+flrc$vlkgPF&G^*s1-`r^XT@zu@k7Sitk10zZ}hbllFqvTsv9!F z3%XDFC&z6VQFZfN?qSJ3LKN##TU=F3*^Ewty;j^o@4L|sN`nle6iRskc}eVj+vV=? zR~8rOWIRo$flP1Xgn!zpDU45$St=nQ*k zz!dcI##c0@qUj^fP21Do(CVf=CrhXHd{zQEryyeGvS7IhKO)07!htcrF^nk&WsR_0xq@8op1VB8^-m1`IJ6|~I z{#G*Go}Fy~e=nv4*LIX8@TnQnl6y8^HbmjaiIZ)kdngU!en65{-1=zgq-Bv$dM0}1= zHP>`96~G5F-WZyuCZW$lBG7A}7OxN_yDlfMFJ-}o+b#f@P=J! zRP<31(GMs#j>3%4Fc2f>+ySTZz|)7wXTBKA01T-EuxI!DhN;l;=wbly3S&}`US{4g z`EJJb(V+huUW3jXqi<;u0i)6~wBpR~04CFbEeqI0Pb5X_IE7q=Ov0`pL*7pmWO8-R z19@}>T@}378#{^HtWzBwFZdGApesJwF6pZJ%U;zoy<6ya@y^(62(q-7P;NZx`ml6; zILC}r!}ALeVODadU?s$JdRJ0SoB8yj$&Na>TXud;ezGY&+L_7 zeOq&dp00Fm?!2bgn&l4j=!N_sFn77opxtJ|FrwM0Yr$}voO~umQt9I#+3*t8Vy9uC zqBQY_`UqF?nV|(^md?Jr0LlT@!_$nE#UkQ;H@AhFU^Fb8G|K&nqRI9A^ss=zKI!OL zsH=QPz^(>*gLE3QqJ~LCp-7+O4g+jlq&)Ay8QrbY?rDJ#r;5H3x#js$n%bI@bSKmL zxxSvp;<7bqX+-+El16)PgB!>8N-YtKL=H{AM9t%>T(6L!o7eS`J#pSW(DYobcprID zsXZ-h^NgIW+Q|q7U7W-B&cU+g7AMLygYfOA0Ir8qfWSYhw!%+hJ})SPdRDAwh0S?v!{t3$>4UkLs!BxqcEz7#Hx4dx9b_W8Gu)Qo6cYicV3o3-<;^yJX?9;P!3Xt-b%akpEJtF0 zCb}}Axf{fu(#BB`64Sv6lxY|{BgTw%fV_iO1xCGwSZBA4U>i?hGse2^2sTHzL7VJk zjNMezehkYgi|A~H4~dbDabJXwom~k**WqDzw5THj2g9F&gh&b`E+_;DrJKC_2`cesUd65k=2!| zvsvJpzY;4q1fjQ{P;c8>a%hsMtxAht+~@>6ql}caYo!11txXd7*&I|D=(E}8~ZGIT5>`Qgbppk zc!K3h&1yEPOylgsJf75i1(3;20*iaI`R=`E_m@V;9cndgsZt;ts)__3(v~r7reIsn zU(@*7iwv7#6X^#u7D?i2sgSnhK2=v<(G>DLmhbSD^;+i<&a|7==HcmIi53X9X0ov4 zik64;*x6{cc++nzWDtefQ#c>EJjJl8YYrJ5&QDEU@VXW8yGvT~R0eY82+ zx%B-0VOQtDsTPExI{b~P^|Ox4tI&5E=cwFR>oTC2-5g9dyf5uaf68Kkn>gUWh6t8} zDiCDY@ywMrM7H^V|LPSCqHr&v`NySnu`g29^BYbJK_RCHz5B|fj70Cwk4HpC#5(MC zbanTKKZn8Oig@I16`tr!33vo2u3N@xXW3!pT{z2(Fe1Y#M#m(cJ-pScP)77MI-6sY z@)C~mCI5$={6tXgILh?5Q1m;{vG>7R&D31SeL_I+3rVIv7DrPa;?y( zAxZ;m4@WQ;j=I|P54Ck+aq{#<-i0q?b-AX!p`X9Z1>p{?Fe(XUp|k00pKqs_C|Nh^ z4oEmPHsv`yTCJH5$d;ct2OT0D4a#yVH`q5|CACUuSIts4E$p*Oj5ac~xoF8&p7#~Y z;P}sVe4;sfgObzhojPe6pd)NArj9}zLwUJlPka1YZiMK7_OVg!4=eHrH-xIjw%_(U zBpZ|W%Or?+cNT1=5#QG+|IJ%)r_U6-#vOpbMIDkK>Y(g*6x;*-cE9S~$4*1H^$ zZ~Im)`sHL}-o{fvvwGvY?L1!e@a--tiQZOHobL}8iRjEHch>ZB@3CP(kESo_{7SLB zxyaTfq}4R>+MFJau<5>bgz)e(~_>B_o`eVSP+ z;dMCk(LPSvXt-6yv({#;YMbTnb~^M!&S=#~){`S~<2hjk0xwh|n05BUA*2kWpR(EK zVdDd7ZtbjuO^@F?9v)J5Y$>yKsxzoB(fz5B-kpN}Tn59Tk}23i1od!|N3RvdggHs< z6jubF4(Aswp5)-SI%1kjbaE?W%0ydJcWHx@7FW$TKKH4>|>J3$11Ot9NoF|Aq;X4ZWST-9%9-Aru-4N2vUC7?+rLt_BO=dmHP`Sr>A1{rA zr;*vn>e*C0p!U@k0Tg5F#ccqX>3|X};X=JF9OwpFm6_QPX28c<$7_zo&#$toyLdWT}oI<`z(3)tnz%VM-wx z4j*UM&Lx2*RFG!Q)2}FIcg=d7tqEPE)p-9fa4Ip?(S7*Eud!F4mv;r?qr9hpl~TNU zGdufP!^>d?=oW+Ztft#)6+afojN?}o?&x58-RZle(9am$-E2-XPQ4=KZ79NzYgI)XK!(vUWs1Q{t`MQb}!2TR?NZ%2IU>L${s+%x$X3R~JMPQW(?HG<|vC zXfYB%h_YOu&tCq2jvC3?2w}+Lf*No(>sX`wwLXHUBQn;!$n3<@EHdy$=Pj1=W$$XG@GGxR zwdS15H*S5tA`Jhm1Gg2NgC0l$~%3!Cnvc_g*7kP&zJxxu^q(w{Bx2Ig4 zLYw>QBMEfcVOoNTN|fG1NK$ zzVn19bcX%D&scFg+qhu-;Ca(L*$UB=xaR3JTFE2mk(~vjhQPOq%}-0YOU2i<9Yva4 zz588iR5Z%8gNHAk)hrd=A02Umt>@ZcAS->@v+(nl4j7ni5gg$bEZSgFb`R#;7#E>R zXC5h4!oq%YV0_fEjDC~k%ah~c;iiv^h3}MbY2M~eMWs)>X+E`Xq@m~0eYO*^rL|)0 zW7bxo$>K^b?`|PW`iAxxD8-mO&qP_SELR~IS&dz)ka3uvqG%sZ=aH}wX$;KjBDK9b z((A%M<9x(J+_4SJRWU_7R(oU4b8A4I2g!kuhax9rYL2C8p#4mnY+?!FnoEN<9}tS~p7K1<$EwRS_> z4Psrlgs%=ixQp*hIiOOgt|%rk=wKRg1G0=xc+<(b$ytw0J^TU^=%8ar1V1GKCBo+f z^*yL+-&8-<7)WOFtr3Y-9;SG|F))NwEmnr)L&SX&xNly()W_JpPxld< zpbgctTv3mNw*G}@|CO7y zh$C_7sSwmpAhEixd+A7OQUuQELgY>GqmPi)TWn=sDn8Z>dSWY7%z{c8ZpIudEdH6Z zP|@%r=(yfFM7>-6cg65*Ff!@QvFFyzO{5T&x{m}&5~3y^u3M2b@@dUQ_r;s>wAo|= zJsG)gRH1$-M6_~fq)A?Q5j{Wpl^8zdAhV+U{6*Kf=Zg75AN9ve!@M^?svKvXYl_k$ zhpF=eEzh@w)gKq}=#a#Gty|Q_S8>)ekRN-$TsrdQR%ImaSs1s#W|1niR535TLPnYX z9sgF`?lH^kYb1@~&#g6(&r)a+gIs1+g)UZjIwzk}rA~<=ijCgY(oG69EJU4tqcDC4 zZBj_bOJ?t6IVgRTi(Ih1)>$j;k}XO&kTzZ#j!YHZ{84gm>9XhA$Ub^hTl};ScX0PA zA0eV$)S`t5L*U)areTf*4&|2iTC6TCd$9S%zltTe0mxS?ot&f7l@&8{Q*e~w`wg#5_c}KsOLJxY-DT8in`Bty}#f-36GTJ*Z`Ve8i0hN8it zZ)rVh%m@4WS{;qM{kYQ<{$0atIhWX#) zouU%wc<-k76B(Q5^T>kceDm@pgNU5o?9<&8lEqi zz*PISAOC$6WubeZ(yAnwH_w=~|M_cvl%{6p-!Nr)irLUla)dn`bMiGeLEbonNFjN8 zI|>Rwy*#VjW=7ApA{X#_JEh3IXk?=4D%3HI_5q2u3WydF6bKuB_UH7u^z4XdPgiaK z3*-LVEjS}Vk!&VPhiJtbpO=zi9R0(m#SudrMVa;osx5@N58K~GFFgXcBLflGeZTOp zuWtmGB?GvHi$EqLJkk5|#5_;C3Yytlu|2G9(*ekbhN@uTjXogc8~qX(`@37`JNgs| z5W#u#DziF1RevnKsQD*Sq{zVm0Sfw$489x^<|BZip1lFe7N^aWZjiS@H4}gc?fVs? zm?;$z2Y6;<1%k_lI|xu>djnLru9H69bN-{T@4pN8YXyy%udDl3bq&@cgrY`+U!T$a z`7uF;h?+>rjU{LBPR~GuCIer7knRsK9m27D5}-_ZQOP)r{2y8lepNauM>5(9C+6<_ zj?Cc!8OmS!|9ulR;+xL80lCpCV>HOm0#C*S2~-RT3ka(3hGwr^s~l?WT6McB};Mt#}GGV?xJU_;32 z(TK|fPU}06nO`r&6A2DbOY*MJ3oj0{R4hJFZFL`XJ?5@CfwAjgEwiR z|1Bj4HqY%mDDpHtI5582+22Qa3vu8ruu0W4;(_6+A{eA#P-HJLP_4MjX*K?kQKRI& zD&cf!Q&ST{#u5m4KrrzEz!M>{ISAFA$Pf8(d-)5Q?v%LHz931&e@*;}-0!T4S&io( zMTej6%jlZ#oYQh==2^tS(|P)EW-;)HvAVj>Nv-&PXN%mkV)h;%>pxgI9)b%6cy@~ zU6wlW`Ro^irt!pI{x7^ve6}jBU~#??a=mI$gtR=wOc7HPaAp47RbgoZjUv9?<2k&B zT?7VVtBLqzmaW?4=b9m;vAnjrpH$3`=y@oZ^`=-H$N;ozD7lCp)ANr8LlTatR5n0H zf+ViK)HtVaZ_xl+{#2Q6KD3bvYmuPhYo<|bDxu^9&>8_Y? zPV(RzqRs6IP+-HHI1VmA1VtHUB2&g-g3x4++WF8Bd}4idxzIIQ7e|9tVUCmEQ&`U33n%u-iF>j1WF6&~;}xF_fu z5~xhXe^1$`9M(Gov zlJHU?o*SZOH59_z3`LKtF8LY|YX@vs*QPGEFI}X#)ktIWvmZ}2GNtQ4j)I>zAfLtp zS0)Xj0@{!FYQg8lBJ|DxtezIkIsb%dGbMFC2M#Z#I@{hr7GOdv0)eGGzXOUx?j!~>TYC%Nw{ zaqgl?6 z-*XkKC5%YI)rt|l=Y05uDey)U;afShu8?MH_0WFAET-djlE=k3y#GLA=@q^Po*Py;M?YH+~Y*Q~Rs zd%$QLL|jXt zE3P#Q3YqOVP`pguV|ltUEHrQz!hoWtSFXC zfKB^sqYg+7%jL%C{pGEo&H<{?OFg^jvZ?%Tp z+mjSx6oC{IC5B>(3Wc>mFJ-;D4k7Uacv>0+$*}qWlw`KIYICWywtFH#0UI`&ob71^SKk`q+E=}Q#m#{aD%2&zO zoQWe{FIeYGBa`~TS!{0epPa=A*_VTrpcAw^3L9Dg#o$8iQQ03=Mb`*KT2UIdAGx>E zSFC%}cpi|sEJm6s-$yp^ zkLcDq=6QnPy*63**&~kERWHY=RtIvcmRG0hs%AyFni3<_|20g6dHRk@8SIQqn9S(Y z7ll=k>x=a-VI5Zmt9JYq>mT3q^j)%&{6?_UkrDy2s zc<0EV`|G1P7GuV+3YHyAd>HLm)n~#31+7L2SUFl#agk8QY2e*eh{gBd&bYf7?}Fa3 zj#X`}CnV0Scx`$LA5GV|m>f?g3e*ctoxjq`Xg86gr6U1ZuI% zX=w}E8RF;&tbok$IQHlcw_zc(_W@Axi(TwZ)qZ3(zL-*0P`UxnbVAvAjV=7*4cal7 zs9E%}K(AJ!+#0{g{3aor&gjdYjpUZ$GA}1>v#A_Sb(Hm6bD@`PNP0o2$T*_cuK#{O z%WDQ0(XM<8?Gz5J2Kx{l?XnV;+*j9-&?pcOCX&9aa))0-bK_4HgqYN`&d&@Yo<>m!&`u#9dxoFP=(n6pqx(g&6 zPm1i}BgN@5+r4Q*VDQ5?7!WOGc2O_ZBi(PD`uJ8yw?_bo*+t_Fix+rR05#724c!^l z26r0}qj3W2R#|E}T?8Uo=chkN<}ePtsCLjR4!=W0WHEkl2_)QD+@BVE;WIoFwXU8+ zjW!7n3#&*z5&!3EMX&iXi_YfC+&Af%SWn?88vjr}Ioy!(e=k_Vc%(Bp@BT$jTA66M z;CAAXv~W}MuS?d!r}(taWZrgjV9(@0XUsr7f=o!<$A0naosG(MAO&I-4J;>l&&KQZ z`dCFYodWK~e#892f&wQu>)t?_4Uniau6!|UQYh?ker#7}^oWT`7TR>_K0~<(0yneU zQ^I^;TA%lkashBEqbUs&6%cixp;)5NLn=Z?*H+vErJKUet&QCKS zzm8ikd@o*3NxdK(9KcW056Nt8nzSRSBo={;M|>dW{c#1#lS!Cq2qIDem$*XM1ma^r z3TSqe<2=Lkj>OmPIU6;ONaXSdH^C!P$@TUh14Eb^RNPl=BBJYxzt2Ih!L`D#-}<># z?$hgk-tzS&(%Y4&#ilC7_^cM1CcwgGW$Jk|v=7PjL)ak>G5C2O?0U980*L)Pppx1J z>HsE{#83Gsr_x-(Sb->Z{l=Iowwgu&4lg?>O%sCXtLuAJ@MTsy!?&+OLY>x!6Os49 zF$>ALnh#-5f+v8ij~Qs_Rp`G}{ChKq&f1{h_R)6U$IKD9*u7gLTkGxk=5OP8(s zidXbt#Y#8~gD+%RN621>Km55N2$3$g{qIsspq%M#Xa)q(0C{p7g3;ay&WdbM*fFzQQ)~2es{#I1q7N5Dab+d| zuuYQNlk)e9Q-q>O@}x2DGHo%{k8LtP^7nOZHVLU90*QYPt_)hn|7jCS`0`A-X@}QXM<X(tc$$oms9_G@?l+)>|dsuG8T$0yb8pWhF_ zkDYZHb$TzTufN8Uqz2|^8-Vd{wgJiK23Rtw(?dA3R0P?9#~C=M6KJe}jMVw~6_nGU z`I^JDO{aG)uJitn?~KV@5<Y4{T%db|=!n&!18ZC&vJ-vb0(V{PqrMCmy zxHmEpB7bBa8yqKquybQMe`VKsZIJQ3kj580ML|lC5nxmwfcWX=6qN5hHRd1l`03r7 zP1&|{E8LH`Ao#^zOLcTrlLC1key;|?VSasx1af2T@J%7p<>ZU}m-dH?d@A8ZI-;AG zHmUM^Wb$_rZ`uIM#&yQy`gU&w9?ktBdDs1Xr#&0U(J>~co(>mjFI`=3U75^1xq|a% zWM(db6Tqpr)QRlB>+=C=rI+Swa+uk1!v%F&QpjaC1L1GiMe$A(`H@$ZT;q9Ddi_9H zNw7?sxI~*_k@!pE1v`(tVUtS8$#aFS2 zRHjl}AR4(Y39E?BbPXTFIph&yy?k-d-pyiOw=~1#1InF<$uTqgX9w%_5rVrx7TVx! z7ToLRf&ur`B&_wlD9NeIobAst|2ms|MSX1~3!}L8UpiSow;-fHAS+%RWc=w^5D#-K zC6J!SiH9Fuc-o&V?R7LByh&l4xw13v&}I1Jpm4MhZt|eV@w-jU5&=R?ai;!0w1!w0!0a!2!F1Z_JJgcW z;Uwo>g&0Vgcz;$Du{m{0k<7zWV@rD)cRj8M*oR}*ty$MbBvF3<9vn2D>q2HvB9cpr zjd%!RQkzIh3Y0IV?d{iZ;Q!tvzTd#c#B8w3A)W(UQyIwUjRBbyx0MUf)s+PYbMM5P zBXP4-X}IB8R$lid$w8r~mS{2gq7Ye8cx@t$^u zBroH8^N=5JJnhh=7%vXH_2*9Dupv#v!Q=bR*qn1z=E>E&I>gMEX5*-HibQqvR(Gwv zR)l{#1mFET6rYlXdlRi=(u6!ZK^b+9XDeT|pcAN|WPx^(Z(fWxy#x ziEfUU+FNyb=AJj5SNNAF_K$9U6TucE1i|80sV!1BJ@Fp2%+=ew+_m5HT1x%pi2nIr z`xqdS6_VD0aQz_AL8y|OcODt^|DPKyT8-B2Z5>dU-Y}II4xJuSt=IYUx@a}}Ilosy zH+f@c;_yL_T<0qF4$Sn!k!us%6@&o=+5_MJ@Y83%69yh-pgmFP-%I)R>|JUTSxiJ7 z`+l?melht?{NEc0?S}6cf$*-Fv!+;wT)gg=FiEq>9I=9~P;+lbGxeOu92Wf5wZE_W zoj2mM`;sF6=d+0}d}3Hb>Y4Rn`mqYNUhcU+=>PFQI9N#Ohk7g%>KiUO_Fb>>7n_$e zVRn~KbBiuUC$fGVocwdI@W2{*4~P2y^soOuyxP#QDw>DSH3c8#^qOW5e;LVq{pVGa z>Sk=b;SSi_`zdZQ$L&M*US(079zSm7!fW{@vRfUv|M_qbdL}nchX(%npTC{MtL}R* zismn->w?u~HdF2E7MUY4NdGt&iZ94cEAbx^of#vCKaQD6ES=#6>H(%+;8g@Lk=N_RW7kTnzcpMwlvHxKa8k zd6-L^&AvQ0pWAUc3)zCgDa?Ij?&pG=6zR%$wJRy7Uwbz>91BZA@<_(__wPKhRoY$2*RZanRm^C?{1LlawpR+{op}3& z{4GhtF%F8@*0w9%h5S+9O^!Qq47o9OgA>tYSEqll1H&WzO=9iUB^gtYu99rmuMVH(Zb5zFr-#-D29GDsD*T1 z9p!>pDXFjP_1!Ft|RgHfLM^P@& zu3)a|_0n6?4S~1ho@}7&zXobPhY)a7lc278s}46{Zu$O482Q)AmpcRIhs@O^3|!g| ztdZ;UtDqm8O}%*f`+9&{>{Gp2-HJ~==7U9Qtny)pRAuPdUE}H6g-H0@O{uq=yZj<= z5e0Mkk1ZJ?Ms^5Sb>=@{C+1bKJfy(*IY4!Oz<9+MLMoza|N6eR0ssWD6Oj@KxH zsTM@ml`>vVxOQcMR*IcGqpKU)f~iMW;n5!_}f6k%2^Z zlS6DU!NT8#*-@~69A+!|fw+VmC}7=di`n+i7D84q8eay!GcU%(Z0sWN}el? zdqywav1MBNm^1t3j{Y#8v2ym@qVT#wbbEZh1fIXRHHu!K=mfLLST;+&00)}~?aKJ~ zAdLxb`a>6X9Z~J(cI$S?aJ)@tW!$^h$oqAWw1?YCDO;9no)^3=b>H|w#+?d>!y!(=35)8)F*E1v6C9ps$m(46j zeLf63@(h}|+T81b7%>1$vY?M?^jQL}mOg5+StiZ=u1}x(!xY<6ou^_byF#;2VN5p^ z+PrxT6lWlsW)T(^F7NvC^EtbHaHWJ&^AWcMlkN2M-g5*4lAprhROZE!cFmT=(0|ZE z2m6~Y|5ZsfO`f(f)B&uXTgfr1ohp}tn^fYn>htr93+YxD#e z*0^iCX?3M;FEU0LsW~DU)mX(7kajok3$+f)zX?r^EPx7QC#l(QLC;(*-88hts@Wu` z-0&DFfJ+kQjeiz>6>p8%NqMLVV{oGpMZ7Y}c7X;eGOZf|Yj%jtx1zJL5PJ+Xr&HGC z8oUWe`S~Oz`#gJM*1g+%aX6@GnFnb4}R2g_B)y{MT zX8-G@87KyJh(X@XeK*&c-m*ZQ_x-lngen0pF0SjI1mScTryJ3?74%VLfQf_($`fyo z>Ko&P{O@xPb$#u@WSVlM^tRlO-rnA2Px@cKK3bgvvpaO`KJK@^jZX~U@sBe=4&axa z(o^zq8T$0EphnJA^9^HV3Z(IRYfoXSUJ=aC5Tb)G6;9z@3$%p3W1Fg ze_SKug6wno=3L?WOv|B$i_cGJae_jqFWAE11YZzRI<`ow&kYe8Zg?w6upH1Xyt60a z3?x{3kkk=U&Rm!qS4u9Jm>%tl0{sj`3~Sbk%FYa`0g&_POBqlpcc4wsJx<&oWWf$J37ZwDniLR3?e2x?2j;fZ&2^3$DroXs4Wab6rw9me6Iu@>lrVr}dit%hs>)GUG9@50W#j%yYqJInO{>tr)Ox>lUUX5qN28 zHt)>dp{ijIOmLTPJs7bgP}lc?d|7lBHJyr(9SYqUb<(UIDcMuHu%S@zkYrH6&Wt^$ zbkc8DzCWS`$4Q^@8LR7!gya z(=h%P>(+k~3rptTcuhr!AZvRL&CNJ~*p)>IIBaI+8gIm6XXfU&9Re;~qgo?Y^Q7sa zB?IhLyxMa_h%HxL{kYk+H*%ABksX$kYh-(#i5B3!hb4ynEeuxC6W{u6kPcBL8gmaUqh5#k2XFI7*$wL^qHL8>cByz7rPiEA43qs+lkF_Ji*7v9f-?Ay<5xeW zG>ntos4oAmQy`Vmem#`UZt;u zQO<^-Y)>t{n|3CEd@?Gu;`v__Kq*MBhNLe0rQ|Ja}J=9d9b9BGI(? zDo%C2?la z;zwQkSas=bBj0ICH59hNh%F#SY*B>pf)OD#nL}j)eL*W-xRDO+(HHzFwOKjMP+M6w zm!@gAHUV`L%1I-}Izw2AtF|!05~9vkea}sYaqM~yi2w$I&c>N;f_-BaoRk(yN%Bbr z|K$HvVxhru9{5>H-VHQRWsQw-bMPS;kw^~?4_lU2O_;X;j~l67@Z_`)dGeSJ`bt9l zBPcMy&?N<9F$A_;~<6z6Q(b zEPB_H{cHxF1u;$MRVP%2x3UWGvb+sGwp{=T3gi#LS@f~L=p>-fo^WpwPl;-oQfRx? zDBv2*jc-ezy_pL`9Oc0Q^wuZb=_*WeoVQD6NkR!Ojx-Ui6V<43eUnZ8VOsHb=;`Ut zrN6EVAh0B90z?vM=J!8#Mb?t6k2VQz3IUNAHpt6v9VT9Xw{koSb)8R07 z0^jX3XWp|cHaNYO07(a-4_1gjfl5q>^`4+N$5rtmLN5GH3vWs#~-YNa)tI66_4Y)j2C4aJ2A+0-7vU+Wj;J57XP8`bIH{36r^ zc7d3PB~dRsB{ys!z8;a7BcM|>g%_jb{7Vp5L-0#+pi~r9@{3a!e5Z0Mt7wApdk^ZGNEj7Nrq;KZelH-(+*M)E}oF_)EQHv$$7K7`CO-Z zyeXkQwJ(plfny$bXYlC?;+o*1KaU+0#hq0gyBb{}8lP*^r*|(5RGTHp zx-u!2d_OvoA*J6|bvCD>@`(S0+W6+;@E~2D@p`4FZf*Qr3a4iSANN)ZuPYwUGVtog zh6y!Kc@vwr2s@;B?W@|WC4$u?weXxX&`@$3FG-71EN48$k)mY2m81DH?p|861-HP2 z8hKI3M5Wa*oraD6>=DHg*3eXGVVk>ZxG#H1s9_!>>pYs0%Nji;ma0p-Vm9k(*vdoE zCkRq>rlwNtq(*(STRj5Dan|y)jM%VA3#N4>jg;~nis5Le&lH{Pz+tbs@GQnM#jRK= z#f9u3(M=>VlGCat-Fj;EoTFuqW_UZ#9*xD|H{uGp-HQk0RV_$!&v_H9MCZkBbq2GF zO^K0$^+_k1KJK}^_|CKTL!evifY_!Roi>Gagc(XzS%Jj~+uhY9U!U;GEf#7XR^gA2 ztBLBhi|?r(G2WSU_55m^LJZT?P{*#%cWMr=o~SY?BhnmE67gaoj^d-Dl<;oG53V}p zBs-^Jifar;sj(|!N_5p=i@cW6?P}J{*0T0JymBfgZ#u~_b(oDYt@M)NQ~5GE27v*T zI=e!8R+*%0dh^*{1+@06*4+Kx_5~Kjv4;)1yFVwJH_=2L1lwx1Py{&*ltPljtSMEs zgs8pwvNMlZjzHi&wUVB03D6%$0DVFI)-az>JQfnP{=+jsYwH1Q6{~p3hY)nTHaysr zz*g({&a^)>IjDoGkhGQ@V*(>&<)l%V?`EspR5wnlGER5^Bf)mWp>lJ>Yv8 zXYl1#V-D{#8U$w5A@xS-jXDjO`F(=7Ux-e3+*kB5C505wRyAWO*#=F3e^>#@@r@2E z21$!r&#hDt$kXSz_47V}n&u z?;2uH*=S9=k-Vfd;VaU(dusQF9kBsgPp)ttxRbuqFQOjH(Eec5GH@v|mB#{k_UzSJ zrPRvlX`2BU{%=pMRgKNjwzN!XT%QRgy-SIjV#NT*;~YrVk{_$CyamFZpq79|B9tWb zkMHMch+_9AV#p}KX*@Cm*BvIbJ`6rZ-Mo(ux?6ikB~g zr)jW_SLwmu-~46XPG>-;QMVuNX1mrXJE+2Tv>+k8=;q=YF8s!`TanzA^Bc&;?0v2! zSEwjUAGwoVWn;ht)D7Tq9-M#;GjQbim^5robD&?!V?GFngw2;(MQ(d3J4Ymz)dgs;&j~0E#?qEClo6;W|4Ed7 z#XxyIY+Id#Pb)Hsau_HU%FPw87P9EXQ7tNtsY}F=WEhN6FQggQHQuXJyVqBND#}!* zOZq6Re9|daBW!$gxtdEI*Tdc~r{^a^lwN=A8x(rjTXRkiQ<7E<2jKgIF~eX~160Vtj&{G7T)jKV z(tJr%nb*}M!uXon8seMjhxccTU>QpFe7$rphRbZUMiA--%IwdXA zzViK~6R6h$p7T!UC!)pvCK|77^f@_2_0(h%z-o{T%#$6jlKLrEV$jTQIjh6wV&9f8 z&U0h3jnLv2;R0b|EK2s_ly|FoHu)WjR#XqK?epF~(PBlOvm#fgu!MgM3+R|( zNx8@rVpK5>fl6|1+>C*;cU;p;McddqH`B-89@S1Hd#>o|@6_AoMH z@P6IW$Re!DPoiuj-R>1q=ncZEoKf{5*tKQP=j!NRnp;Yy-M#ztFFH-;jZZXJw8q(h z2qFS`*{;O-POWA6HBemJ3Q5+JGL;O~$_|vr>NWrVRsZlL8`G>&k}QJvX(}A z>52LIXI6mG+khyxarBpy^{-zKJcQS?<3M0)6HMhpw2yh_FNC`_XWY?I z%XQ3VOax&c?mL}l4Tjt~`)Bfi8R&z99Pz~E-OT?wwLgEiD#EoX3B2=8)3#^l45*fo z<*&m$pi3aJ95Z6|ZmLWR2yf85lH> z9cV_ba60;vF=Ulk)x@xrTeY&lF{a*~WvqOmLWsx!E0)3I7QuUvyj=yLTf z3VW!WrY{F>f-g{#ik%k5ncLMJdq5#5!0z&8UoGs>V|<&v&m{fz*X|jav!^c`)$LGF zG#V3YRzt&CKFMA&c<_E68;=HFVVwyi-w|qR;Cf z`P4+XqMK>(P@SKb*8xOY8ZtS-UUp$$fIT02WDGW7B!X$Lm;oRw5I38GvA%u)zDpsc zg{b?Uj(HV-FaAor{>Xq8Oof}${N!lL*F>j@zJsHrLXyAI?*q^^w-|13OPHbm`;XiB zfISj)kgV^>@Kn~mgwz>EJL}8)4OOwqtgwk+LU55}KV!~11Zm^mBMPBX;rCE{h_-2Z zt5vX)(cn3>^IVOxk__}9=uLn5j0h9Dy1P$cJL5s2KW*my^WHq*bp{T|datr; ztw5wh*uH@aKuwuXGqy6#xSRnTJB9akn-M|3STr#Wy=i*iw<5s;K3p8Yf>5kRW|Bw6+2k066gm2SNMMGH@fRF93i6rkQ!N%xCqPP7d|_HA zP{bOq<`>`0)mQ9u{s{xeo-a6*H>Om#m9ueb4>S%UiP~tHzPR|?e3|hw?Vy4ZFbQiS z4LwQaf;pr?l`2S5($9swNhZWy^~oN5sY+?fjshliv@xsZE{HXDAweQX(MP)Lnj75 zW_B0$%4mD2vhh^k5;ya=sBh`XoNEx=i}ERM!t~q(x>u+gc_tBTl@-{2-asPw9M&Pw z-o3iE8sC9WWP174H*j(cOZyPHt0k*PGzCR zPN=5aC}!%Vm^RJ1!UTes?|^u)zbdazb+Oy9LY zZMjkxsb>u}bKGofle$J4%B5#X+X@<}DDyaxbot}h0?)Ek5;b+!jQ z)`%UhS4<{8E$7<6Wb8l*^`ji3h zLV(=?Q;_H|z)%sCAqGmJ{p)qn2^yf?YB3vX-S+Iphet9LWzD%+dG(wUk zzbu1t^V-*YbQEpP_bAEvqRy-VJlbOxDK; zpD8tgYg@B{;if>c`4mtYxO<>6N(SmHLPl3f1GVEA49ggh^tyqfh`K1EQ@AmiCB-(6 zc8;_Pe612+(_~rNUj1Ma16w03ukC?$927 z#D_YhslXJ&&zjruEA8-CPxS=|Q{?;40^JBzsQ_0h*!yRa2(rAF{lmmW08!IxrgOAG zx76!L>kTzTE+!bvYC2GB9d(dmvK6I`gHV!=up6g1qa)M>!zs8nH`ijG@5l7_k%#K@ zCA2r|*#FXHE={7&!~>(=c>!(bIRvgh^vi}_oV@IMp^r{-^z)b6j&(mPDw5`rL|=)I zH^LAH!1+ELzy&fab8wiJ>^J2Bn1m8&-3v{x+?j@yZvjw#K`0T~Q*Go24xbM0WkB7Ze8(y9)O13i5~%;06)-avzHWQRke!^QKRvg zUwFs=@=x#805J(Vi5LbnLoGVeX>p-~{^G@pNY!2rwnZqvzS#~mB%ZY9fire`+o^Jzkge|w;|wnC5Hy{KuxR<((Ynr2lm{LHO%G= z^fa>uO=Jg1R!#y!e-49liy%xz)T$!lLosdxfQQ#Q z2<%w~TCCdzi}-m=A>-s0h5SL4VgM%__9W;Qdq*SrU2~XZBX!-F#U*99!wrva4&spNa|D3(~@gQ`RFd#?OVR3eH z*au>p@Fa+|Ep3wn0(M*AO;T^wR_TeZ{WI7*)gim|9gefWUQ4qFGyu#b+2l=kj%p?Y zCjrX+iHJ3m+!nS>Fa$-sub{Xz!Hzazs0LMZdl>GLWJkRP^y&1Wrc`oPVyppmaI!qp zyvIDvY|`Ncgfmsq3VUO(rN)`@=q(eJZe8~l4&c^R^k11||Jq?cEX-}WyQ>q`z4MoO zbTENujsqmj&wFtG59aXeeYHSpgZ%u+ogXgq`xoQ96`_xFo&3DamVy6H2b4o#k=eK0 zlbkt|H&-=XFLCMMSt=~ z|3A8-vrtn)J+#^Q{?94cr9xT80qERabN0;tu9|(%6bu{$6e8x!xav=!W(jTFJ`Kob z!{Z0PhaNxvdzB;rZo8vAYnMU)>kf3>gG%PEt#r=6k9&T=*^w@Qz$Px}Z~W71Uosha zYXF9D9@xI}$6NZXw~^igpB#8uw)=smZU7L3K6PaEvQOlNG!0Zs26FxOia)L0 zE(C(zm0q{(6CDskQc^D5I={cUAJ>j^-Pt4XleyJp>#`5^*UE!{zxQfi|9{v~rjS;_ v$axDc`=zHIBVCib1HLT#$-C++7q Date: Fri, 31 Jan 2025 22:32:21 +0700 Subject: [PATCH 33/53] update msgs.md --- x/asset/spec/02_state.md | 1 + x/asset/spec/04_msgs.md | 47 +++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index c1aff8f3..951c69c5 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -14,6 +14,7 @@ The `x/asset` module keeps the following objects in state: | `Token` | Token information | `[]byte{2} + []byte(token_id)` | `[]byte{token}` | KV | | `TokenManagement` | TokenManagement info of a denom | `[]byte{3} + []byte(token_id)` | `[]byte{token_manager}` | KV | | `WhitelistAddresses` | Whitelist Addresses | `[]byte{4} + []byte(address)` | `[]byte{bool}` | KV | +| `FreezeAddresses` | Whitelist Addresses | `[]byte{5} + []byte(address)` | `[]byte{bool}` | KV | ### Token diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 727d9cf7..01da777c 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -135,15 +135,16 @@ Flow: - Get `TokenManager` from store by token_id - Loop through addresses and remove manager addresses from `TokenManager.Managers` -## 4. ExecuteExtension +## 4. Burn -After setting the managers, the managers can execute their allowed extension. +This msg only can be executed when the token's `ExtensionsList` has `burn` extension. ```go - type MsgExecuteExtension struct { + type MsgBurn struct { Manager address TokenId string - ExtensionMsg *types.Any + BurnFromAddr address + Amount math.Int } ``` @@ -151,13 +152,15 @@ Validation: - Checks if the token specified in the msg exists. - Checks if the extension is supported. -- Checks if the `Msg.Address` has the corresponding `Extension` specified by `ExtensionMsg.NeedExtension()` +- Check if addresses is valid +- Checks if the address is in `TokenManager.Managers` +- Checks if address is freezed in `FreezeAddresses` Flow: -- Prepare store for the extension of the token via `MakeExtensionStore(extension name, token denom)`. That store is the only store accessable by the extension's `MsgHandler`. -- `ExtensionMsgRouting` routes the `ExtensionMsg` to the its `MsgHandler`. -- `MsgHandler` now handles the `ExtensionMsg`. +- Get `TokenManager` from store by token_id +- Check if `BurnFromAddr` has enough token to burn +- Burn the asset from `BurnFromAddr` ### 5. Mint @@ -165,7 +168,7 @@ This msg only can be executed when the token's `ExtensionsList` has `mint` exten ```go type MsgMint struct { - Distributor address + Manager address TokenId string Receiver address Amount math.Int @@ -186,7 +189,31 @@ Flow: - Mint the asset for corresponding receiver - Increase the supply. -### 6. UpdateExtensionsList +### 6. Freeze + +This msg only can be executed when the token's `ExtensionsList` has `freeze` extension. + +```go + type MsgFreeze struct { + Manager address + TokenId string + Receiver address + } +``` + +Validation: + +- Checks if the token specified in the msg exists. +- Checks if the extension is supported. +- Check if addresses is valid +- Checks if the address is in `TokenManager.Managers` + +Flow: + +- Get `TokenManager` from store by token_id +- Set address into `FreezeAddrs` + +### 7. UpdateExtensionsList Manager can update the `ExtensionsList` of the token. This only can be executed when the token's `AllowNewExtensions` is enable. From 33a8b33db21e97359eb958c527c2b3910ce92214 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:35:15 +0700 Subject: [PATCH 34/53] note --- x/asset/spec/04_msgs.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 01da777c..9ea54c6a 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -211,7 +211,8 @@ Validation: Flow: - Get `TokenManager` from store by token_id -- Set address into `FreezeAddrs` +- Set address into `FreezeAddresses` +- All account in `FreezeAddresses` can not be transfer token out or burned. ### 7. UpdateExtensionsList From 1b17d073daf0c56807e2b4bb841d4d51293a3ea5 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:46:28 +0700 Subject: [PATCH 35/53] update the spec --- x/asset/spec/01_concepts.md | 12 +++---- x/asset/spec/02_state.md | 5 --- x/asset/spec/06_logic.md | 64 +++++++++++-------------------------- 3 files changed, 23 insertions(+), 58 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 6bfa9bff..28cfcc44 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -6,18 +6,14 @@ order: 1 ## The Realio Asset Token Model -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 `manager` and `distributor` accounts. These accounts are assigned role by the issuer of the asset. +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 `manager` accounts assigned by the issuer of the asset. -### System of privileged accounts +### Token extensions -Privileged accounts of a token are accounts that can execute certain actions for that token. There're are several types of extensions, each has its own state and logic to define the actions which accounts of said type can execute. We wanna decouple the logic of these extensions from the `Asset module` logic, meaning that extensions will be defined in separate packages/modules, thus, developers can customize their type of extension without modifying the `Asset Module`. Doing this allows our extensions system to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we expand our extensions system. - -In order for a extension to integrate into the `Asset Module`. It has to implement the `Extension` interface and has its implementation registered via the method `AddExtension`. Once that is done, we can make said extension available onchain by executing `SoftwareUpgradeProposal` like a regular chain upgrade process. - -Currently, there are 2 type of privileged accounts: `manager` and `distributor`. Each can execute different extensions. While `distributor` can control the `mint` extension and custom the `DistributionSettings`, the `manager` can execute the other extensions like `burn` or `freeze` and could modify the `extensions_list`. It's important to note that the `manager` can choose what extensions it wants to disable for its token. +Token extensions are additional features that can be flug-in for each token. There're are four types of extensions `Mint`, `Burn`, `Transfer Auth` and `Freeze`. The `Issuer` can choose what extensions to be included for his token at creation time, and only the `manager` can trigger the extension's logic. ### EVM enable -While it is useful to represent the token in bank module, enabling the token to be in action in evm environment is very convenient and pave the possibility of integrating new features into the ecosystem. +While it is the asset token in represented in the bank module, enabling the token interface in evm environment is very convenient and open up the possibility of integrating new features into the ecosystem. Each token is automatically enabled to work in the evm environment when created, which means user can interact with the token through evm side like metamask or anyother evm wallet and more other protocol integrated in the future. diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index bf9d03d1..57753fd5 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -67,8 +67,3 @@ type TokenDistribution struct{ `WhitelistAddresses` is a list of the address that's allow to create new asset. -### ExtenstionStore - -Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed. - -Each extension store has its own namespace, which is defined by token identifiers and extension name, which means that a combination of token and extension will create a new substore derived from the Asset module store. diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index f8fe648a..b4649351 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -6,60 +6,34 @@ order: 6 This file describes the core logics in this module. -## Extension - -### Register new extension - -To intergrate with the `asset module` Each type of extension has to implement this interface - -```go -type Extension interface { - RegisterInterfaces() - MsgHandler() MsgHandler - QueryHandler() QueryHandler - CLI() *cobra.Command -} - -type MsgHandler func(context Context, extensionStore store.KVStore, funcMsg ExtensionMsg) error - -type QueryHandler func(context Context, extensionStore store.KVStore, funcQuery ExtensionMsg) error -``` - -This interface provides all the extension necessary for a extension, including a message handler, query handler and cli. +## Token namespace -All the `ExtensionMsg` of a extension should return the name of that extension when called `ExtensionName()`. A message handler should handle all the `ExtensionMsg` of that extension. +The token id/denom for the token will be derived from the Issuer and the Symbol with the format of asset/{Issuer}/{Symbol-Lowercase}. This allow many different issuers to issue token with the same symbol, differentiate their denom by including in their creator. -### Upgrade Extensions +## Token creation -All extensions are located in a seperate packages, for example: asset/extensions, therefore the exentsion or upgrade of extensions is unrelated to core logic of `Asset` module, all the modification and addition happen in only asset/extensions package. The core Asset module does not need to be aware of the specifics of extension handling. It interacts with extensions through defined interfaces or protocols. +The token creation process involves the `Issuer` executing `MsgIssueToken` that defines info fields for the tokens. Amount those fields, these are the important feilds that dictacts how the token is operated: -Each Extensions has their own proto to define their state and execute/query messages. By assigning a distinct proto to each extension, you ensure that the logic, messages, and data associated with one extension do not interfere with or complicate the others. This also makes the design easier to understand, maintain, and scale. +- List of extensions (imutable): + Choose what exetensions to enable for the token when creating it. The set of extensions is fixed, meaning that all extensions that are not enabled is permanently disabled. +- Manager (mutable): + Assign the manager account which could be an user account or smart contract account. If this field is blank then the manager will set to be the `issuer` of the token. +- Symbol (imutable): + This field will be used to derive the token denom, in the format `asset/{Issuer}/{Symbol-Lowercase}`. +- Initial Supply (imutable): + Upon creation an amount equal to the initial supply will be minted thus create a circulating supply for the token. +- Distributor (imutable): + Think of this account as the treasury manager account whose task is to distribute the token to holders. The initial supply will be minted to this account. -When adding a `Extension`, we calls `ExtensionRouting.AddExtension()` in `app.go` which inturn maps all the `ExtensionMsg` of that extension to its `MsgHandler`. This mapping logic will later be used when running a `MsgExecuteExtension`. - -### Message/Query routing - -The message we pass in `ExecuteExtension` is `msg.Any` type. This type refered that it could be any type of message. -After receive this message, we will unpack the `msg.Any` type to an interface which implements what we want: - -```go -type ExtensionMsg interface { - ExtensionName() string -} -``` - -As we defined the `AllowExtensions` in Params. If the message name is in the list, they will also exist there own interface in `ExtensionRouting`. - -`ExtensionRouting` acts as a centralized hub for routing messages, making it easy to manage and audit the flow of messages in the system. -It will route the `ExtensionMsg` to its `MsgHandler` - where the msg is executed. In the `MsgHandler`, the message is further routed based on its type to the correct execution logic. This additional layer of routing within the MsgHandler ensures precise handling through message types, enabling fine-grained control and execution workflows. +## Extension -This flow will also work with `QueryHandler`, as long as we can unpack the `msg.Any` and get the name of the extension. +We'll go into details on how each of the extension works -### Extension Store +### Mint extension -Each extension has its own store, which can be used in that extension execute or query operations. The store will be passed to the extension each time the extension is executed and altered on execution. +### Burn extension -This structure help the extension achieve the isolation characteristic of the store, which helps maintain modularity and reduces the risk of unintended interactions or dependencies between extensions. +### ## EVM interaction From b07b0f256c51b2597b30e53e96c172ea6c7539a2 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:47:13 +0700 Subject: [PATCH 36/53] readme --- x/asset/spec/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 1999c6be..d75e808f 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -13,7 +13,7 @@ The Realio Asset module is centered around a token model where certain whitelist Each token can choose to enable extensions supported by the module. Currently, there are four extensions supported: "mint", "freeze", "clawback", "transfer_auth", each handle a completely different logic. We wanna decouple the logic of these extensions from the `Asset module`, meaning that they will be defined in separate packages/modules, thus, developers can customize new extensions without modifying the `Asset Module`. Doing this allows our token model to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we integrating new features. -The token manager's task is to choose what extensions it wants to disable/enable for its token; and only the token manager can trigger those extensions, except for the `mint` extension which is handled by the `distributor`. +The token manager's task is to choose what extensions it wants to disable/enable for its token; and only the token manager can trigger those extensions. ![asset_module](imgs/asset_module.png)` @@ -41,6 +41,7 @@ We introduce additional extensions on these standard extensions: - Mint - Burn +- Freeze All above extensions can be called from both AssetModule and EVM side (by metamask for example). From fd8c617946125f4b3806c39ff0b950717bfdefee Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 22:58:01 +0700 Subject: [PATCH 37/53] base logic --- x/asset/spec/06_logic.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index b4649351..6c1dc8ac 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -30,8 +30,16 @@ The token creation process involves the `Issuer` executing `MsgIssueToken` that We'll go into details on how each of the extension works ### Mint extension +Only manager is allowed to execute `Mint`. Then mint the corresponding amount to the recipient. Note, total supply can not exceed `MaxSupply` ### Burn extension +Only manager is allowed to execute `Burn`. Then burn the corresponding amount from the address. Note, address that be freezed can not burn. + +### Freeze extension +Only manager is allowed to execute `Freeze`. Its will lock all amount of a asset of that address. An address be freezed with a token can not transfer out or burn. + +### TransferAuth extension +Only manager is allowed to execute `TransferAuth`. Its will update the Token's Issue to new receiver. ### From 8eb943d13a9d442e5d0cf09a0e73e1190c666cc9 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 31 Jan 2025 23:10:08 +0700 Subject: [PATCH 38/53] precompiles --- x/asset/spec/06_logic.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index 6c1dc8ac..740b631d 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -51,6 +51,8 @@ On token creation, all token will be linked to a erc20-precompiles, which allows The token itself exists as a coin within the bank state, maintaining its own logic and extensions independently of any ERC20 or EVM contract logic. The ERC20 contract deployed on the EVM serves purely as an interface, with its logic effectively bypassed. When other EVM contracts interact with this interface, their requests are forwarded via JSON-RPC calls to the `asset` module, which directly handles and executes the necessary operations. This is achieved by creating a `dynamic precompile`, ensuring that the token’s behavior aligns with its internal state while still providing compatibility with the EVM ecosystem. +The precompiles actions will depend on the `AllowExtensionList` when creating the token. Therefore different tokens will have precompiles with different addresses and extensions. + ### EVM Precompiles EVM precompiles are EVM interface contracts with state access. These smart contracts can directly interact with Cosmos SDK modules, enabling their own operations while also interacting with the EVM state and other SDK modules. From 5cd7e5d52d0ab7736a715acfa172d25b14bd3a10 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Sat, 1 Feb 2025 18:28:29 +0700 Subject: [PATCH 39/53] update spec --- x/asset/spec/01_concepts.md | 2 +- x/asset/spec/02_state.md | 4 ---- x/asset/spec/06_logic.md | 2 +- x/asset/spec/README.md | 26 +++++++++++++++----------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/x/asset/spec/01_concepts.md b/x/asset/spec/01_concepts.md index 28cfcc44..00b6ff2a 100644 --- a/x/asset/spec/01_concepts.md +++ b/x/asset/spec/01_concepts.md @@ -12,7 +12,7 @@ The Realio Asset module is centered around a token model where certain whitelist Token extensions are additional features that can be flug-in for each token. There're are four types of extensions `Mint`, `Burn`, `Transfer Auth` and `Freeze`. The `Issuer` can choose what extensions to be included for his token at creation time, and only the `manager` can trigger the extension's logic. -### EVM enable +### EVM integration While it is the asset token in represented in the bank module, enabling the token interface in evm environment is very convenient and open up the possibility of integrating new features into the ecosystem. diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 57753fd5..c495da3c 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -33,10 +33,6 @@ type Token struct { } ``` -The token id for the token will be derived from the Issuer and the Symbol with the format of asset/{Issuer}/{Symbol-Lowercase}. This will allow 2 tokens to have the same name with different issuers. - -The `issuer` is the address that create token. They can control all informations about the token, define other whitelist roles likes `manager` and `distributor`. `issuer` also can enable the token's single evm representation mode, which is showed in [EVM precompiles](README.md#asset-module-and-erc-20-precompiles). - When create the token, `asset` module auto generate for it a evm address. This address is used as a dynamic precompiles. ### TokenManagement diff --git a/x/asset/spec/06_logic.md b/x/asset/spec/06_logic.md index b4649351..4bd60b70 100644 --- a/x/asset/spec/06_logic.md +++ b/x/asset/spec/06_logic.md @@ -35,7 +35,7 @@ We'll go into details on how each of the extension works ### -## EVM interaction +## EVM integration ### EVM interface diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 1999c6be..0f31839d 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -9,27 +9,29 @@ parent: ## The Realio Asset Token Model -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 two different roles, manager and distributor. These roles can be assigned to arbitrary accounts (could be either user accounts or module/contract account) by the token issuer. +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 defined by the `issuer` and managed by the `manager` role. `manager` role can be assigned to arbitrary accounts (could be either user accounts or module/contract account) by the token issuer. -Each token can choose to enable extensions supported by the module. Currently, there are four extensions supported: "mint", "freeze", "clawback", "transfer_auth", each handle a completely different logic. We wanna decouple the logic of these extensions from the `Asset module`, meaning that they will be defined in separate packages/modules, thus, developers can customize new extensions without modifying the `Asset Module`. Doing this allows our token model to be extensible while keeping the core logic of `Asset Module` untouched and simple, avoiding complicated migration when we integrating new features. - -The token manager's task is to choose what extensions it wants to disable/enable for its token; and only the token manager can trigger those extensions, except for the `mint` extension which is handled by the `distributor`. +Token extensions are additional features that can be flug-in for each token. There're are four types of extensions `Mint`, `Burn`, `Transfer Auth` and `Freeze`. The `Issuer` can choose what extensions to be included for his token at creation time, and only the `manager` can trigger the extension's logic. ![asset_module](imgs/asset_module.png)` -## Asset Module and ERC-20 Precompiles +## Asset module precompile + +To enhance user experience as well as interoperability with EVM contracts, we decide to build a precompile for the asset module. All the messages of asset modules can now also be triggered with an evm call. Thus, evm contracts can interact with the module and users can call the modules via metamask or any ethereum friendly UI. + +## ERC-20 Precompiles -ERC-20 precompiles are offered by evmOS for better interacting with Cosmos SDK. Instead of changing the state of evm, with ERC-20 precompiles, modules now can represent ERC-20 token in the form of normal bank token and therefore can be managed by SDK modules (single token representation). Utilizing this feature enables the evm contracts to interact with the asset tokens via erc20 call, opening lots of defi usecases for the asset module. +ERC-20 precompiles are offered by evmOS for better integration with Cosmos SDK. With ERC-20 precompiles, we now can have bank tokens with the interface of erc-20 contracts and therefore can talk to other EVM contracts. Utilizing this feature enables the evm contracts to interact with the asset tokens via erc20 call, opening lots of defi usecases for the asset module. ### Link Asset to Precompiles -To link an asset to ERC20 Precompile, when issuer send the MsgIssueToken to the Asset Module, a new asset will be created and a new evm address is created randomly, which will be auto assigned an erc20-precompiles to interact with evm environment. After linking, all call to the token contract will now redirect to precompile instead of the evm. +Each token of the asset module is automatically linked to ERC20 Precompile, when issuer execute the MsgIssueToken, a new token instance will be created in the asset module and a new evm address is derived based on the token's info, which will be assigned an erc20-precompiles. After that, all calls to the evm address will now redirect to the erc20-precompiles. ![asset_precompiles](imgs/linking_precompiles.png) -### Mapping extensions +### Token extensions call via precompiles -ERC20 precompiles come with a limited number of extensions which are: +Each ERC20 precompiles come with a limited number of call which are: - Transfer - TransferFrom @@ -37,12 +39,14 @@ ERC20 precompiles come with a limited number of extensions which are: - IncreaseAllowance - DecreaseAllowance -We introduce additional extensions on these standard extensions: +We introduce these optional calls to precompile to execute the token's extensions: - Mint - Burn +- Freeze +- TransferAuth -All above extensions can be called from both AssetModule and EVM side (by metamask for example). +It's important to note that each token has its own set of enabled extensions, the precompile linked to that token must also reflect that. In other words, for each precompile these calls will be enabled/disabled however the linked token's extensions be. ![asset_evm](imgs/asset_evm.png) From d605b2251b51501ea92f917c5eaba1e5338dac6a Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Sat, 1 Feb 2025 20:32:42 +0700 Subject: [PATCH 40/53] Update 02_state.md --- x/asset/spec/02_state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index 2bd7e5e8..af02e1be 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -44,7 +44,7 @@ type TokenManagement struct { } ``` -`extensions_list` is the list of actions that user can execute. The `manager` can then modify the `extensions_list` as he sees fit. +`extensions_list` is the list of actions that the manager can execute. `MaxSupply` defines the maximum number of tokens can be minted. From 9bc990ce0f36a7db57380bb0403213b801ddbade Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:36:13 +0700 Subject: [PATCH 41/53] Update 02_state.md --- x/asset/spec/02_state.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index af02e1be..ce67f3cf 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -12,9 +12,10 @@ The `x/asset` module keeps the following objects in state: |----------------------|----------------------------------------|-----------------------------------------------------------|---------------------------------------|-------| | `Params` | Params of asset module | `[]byte{1}` | `[]byte(params)` | KV | | `Token` | Token information | `[]byte{2} + []byte(token_id)` | `[]byte{token}` | KV | -| `TokenManagement` | TokenManagement info of a denom | `[]byte{3} + []byte(token_id)` | `[]byte{token_manager}` | KV | +| `TokenExtensions` | Token extensions info of a denom | `[]byte{3} + []byte(token_id)` | `[]byte{token_manager}` | KV | | `WhitelistAddresses` | Whitelist Addresses | `[]byte{4} + []byte(address)` | `[]byte{bool}` | KV | | `FreezeAddresses` | Whitelist Addresses | `[]byte{5} + []byte(address)` | `[]byte{bool}` | KV | +| `MaxSupply` | Maximum supply of token | `[]byte{6} + []byte(token_id)` | `[]byte{int64}` | KV | ### Token @@ -34,13 +35,12 @@ type Token struct { When create the token, `asset` module auto generate for it a evm address. This address is used as a dynamic precompiles. -### TokenManagement +### TokenExtensions ```go -type TokenManagement struct { +type TokenExtensions struct { Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` - MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` } ``` From 55fc97495a84482b18e243e4b6ce7bce578b56a2 Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:36:39 +0700 Subject: [PATCH 42/53] Update 02_state.md --- x/asset/spec/02_state.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/asset/spec/02_state.md b/x/asset/spec/02_state.md index ce67f3cf..b005538e 100644 --- a/x/asset/spec/02_state.md +++ b/x/asset/spec/02_state.md @@ -46,8 +46,6 @@ type TokenExtensions struct { `extensions_list` is the list of actions that the manager can execute. -`MaxSupply` defines the maximum number of tokens can be minted. - ### WhitelistAddresses `WhitelistAddresses` is a list of the address that's allow to create new asset. From d38b45c12ee6fb620323827bb3bf7875b73a2987 Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:42:09 +0700 Subject: [PATCH 43/53] Update 04_msgs.md --- x/asset/spec/04_msgs.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/x/asset/spec/04_msgs.md b/x/asset/spec/04_msgs.md index 9ea54c6a..34eb2224 100644 --- a/x/asset/spec/04_msgs.md +++ b/x/asset/spec/04_msgs.md @@ -108,7 +108,7 @@ Flow: - Get `TokenManager` from store by token_id - Loop through addresses and append manager addresses to `TokenManager.Managers` -## 3. UnassignRoles +## 3. UnassignManager ```go type MsgUnassignRoles struct { @@ -128,7 +128,7 @@ Validation: - Check if token exists - Check if caller is issuer of the token - Check if addresses is valid -- Check if addresses is in `TokenManager.Managers` +- Check if addresses is in `TokenExtensions.Managers` Flow: @@ -214,22 +214,17 @@ Flow: - Set address into `FreezeAddresses` - All account in `FreezeAddresses` can not be transfer token out or burned. -### 7. UpdateExtensionsList - -Manager can update the `ExtensionsList` of the token. This only can be executed when the token's `AllowNewExtensions` is enable. +### 7. Set max supply ```go - type ExtensionsList struct { - Manager address - TokenId string - NewExtensions []string + type MsgSetMaxSupply struct { + Manager address + TokenId string + MaxSupply int64 } ``` -Validation: +This message can only executed once, it will set the maximum supply for the token + -- Checks if the token specified in the msg exists. -- Checks if manager addresses is in `TokenManager.Managers` -- Checks if the new extension is supported. -### 7. UpdateParams From 383a9ceafce67e0c535bd62f75c4ac7cc77edb1e Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:44:43 +0700 Subject: [PATCH 44/53] Update README.md --- x/asset/spec/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/asset/spec/README.md b/x/asset/spec/README.md index 06318b9a..a593824a 100644 --- a/x/asset/spec/README.md +++ b/x/asset/spec/README.md @@ -49,8 +49,6 @@ We introduce these optional calls to precompile to execute the token's extension It's important to note that each token has its own set of enabled extensions, the precompile linked to that token must also reflect that. In other words, for each precompile these calls will be enabled/disabled however the linked token's extensions be. -![asset_evm](imgs/asset_evm.png) - ## Contents 1. **[Concept](01_concepts.md)** From 0cf34008b9acc939f46d4c484a41c45a4535cf16 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Tue, 4 Feb 2025 22:12:06 +0700 Subject: [PATCH 45/53] setup test framework & test mint --- app/ante/utils_test.go | 2 +- example_chain/Makefile | 103 + example_chain/README.md | 58 + example_chain/activators.go | 16 + example_chain/ante/ante.go | 55 + example_chain/ante/cosmos_handler.go | 41 + example_chain/ante/evm_benchmark_test.go | 157 + example_chain/ante/evm_handler.go | 21 + example_chain/ante/handler_options.go | 66 + example_chain/ante/handler_options_test.go | 146 + example_chain/ante/integration_test.go | 173 + example_chain/app.go | 1135 +++++++ example_chain/config.go | 90 + example_chain/config_testing.go | 100 + example_chain/constants.go | 18 + example_chain/eips/README.md | 258 ++ example_chain/eips/eips.go | 36 + example_chain/eips/eips_test.go | 441 +++ example_chain/eips/testdata/Counter.json | 38 + example_chain/eips/testdata/Counter.sol | 15 + .../eips/testdata/CounterFactory.json | 56 + .../eips/testdata/CounterFactory.sol | 25 + example_chain/eips/testdata/contracts.go | 17 + example_chain/export.go | 254 ++ example_chain/genesis.go | 61 + example_chain/local_node.sh | 222 ++ example_chain/osd/cmd/root.go | 415 +++ example_chain/osd/config/config.go | 42 + example_chain/osd/main.go | 31 + example_chain/precompiles.go | 123 + example_chain/test_helpers.go | 138 + example_chain/testutil/abci.go | 280 ++ example_chain/testutil/contract.go | 170 + example_chain/testutil/eth_setup.go | 205 ++ example_chain/testutil/fund.go | 43 + example_chain/testutil/gas.go | 18 + example_chain/testutil/integration.go | 81 + example_chain/token_pair.go | 20 + example_chain/upgrades.go | 8 + go.mod | 7 +- precompiles/erc20/abi.json | 27 +- precompiles/erc20/events.go | 5 + precompiles/erc20/integration_test.go | 2868 ----------------- precompiles/erc20/setup_test.go | 5 +- precompiles/erc20/tx.go | 3 +- precompiles/erc20/tx_test.go | 117 +- precompiles/erc20/utils_test.go | 345 +- testutil/integration/common/factory/base.go | 119 + .../common/factory/distribution.go | 88 + .../integration/common/factory/factory.go | 48 + testutil/integration/common/factory/fund.go | 51 + testutil/integration/common/factory/helper.go | 119 + testutil/integration/common/factory/sign.go | 58 + .../integration/common/factory/staking.go | 88 + testutil/integration/common/factory/types.go | 25 + testutil/integration/common/grpc/account.go | 29 + testutil/integration/common/grpc/authz.go | 117 + testutil/integration/common/grpc/bank.go | 40 + .../integration/common/grpc/distribution.go | 57 + testutil/integration/common/grpc/grpc.go | 67 + testutil/integration/common/grpc/staking.go | 69 + .../integration/common/network/network.go | 53 + testutil/integration/ibc/chain/chain.go | 82 + .../ibc/coordinator/coordinator.go | 169 + testutil/integration/ibc/coordinator/types.go | 18 + testutil/integration/ibc/coordinator/utils.go | 53 + testutil/integration/os/factory/broadcast.go | 100 + testutil/integration/os/factory/build.go | 163 + testutil/integration/os/factory/factory.go | 209 ++ testutil/integration/os/factory/helpers.go | 41 + testutil/integration/os/factory/sign.go | 22 + testutil/integration/os/factory/types.go | 44 + testutil/integration/os/grpc/evm.go | 65 + testutil/integration/os/grpc/feemarket.go | 21 + testutil/integration/os/grpc/gov.go | 28 + testutil/integration/os/grpc/grpc.go | 55 + testutil/integration/os/keyring/keyring.go | 120 + testutil/integration/os/network/abci.go | 101 + testutil/integration/os/network/amounts.go | 75 + .../os/network/chain_id_modifiers.go | 76 + testutil/integration/os/network/clients.go | 93 + testutil/integration/os/network/coins.go | 90 + testutil/integration/os/network/config.go | 206 ++ .../integration/os/network/config_test.go | 140 + .../os/network/example_contracts.go | 30 + testutil/integration/os/network/ibc.go | 29 + testutil/integration/os/network/network.go | 358 ++ testutil/integration/os/network/setup.go | 540 ++++ .../integration/os/network/unit_network.go | 57 + testutil/integration/os/utils/bank.go | 45 + testutil/integration/os/utils/bank_test.go | 71 + testutil/integration/os/utils/contracts.go | 57 + testutil/integration/os/utils/erc20.go | 115 + testutil/integration/os/utils/events.go | 55 + testutil/integration/os/utils/evm.go | 58 + testutil/integration/os/utils/evm_test.go | 64 + testutil/integration/os/utils/genesis.go | 84 + testutil/integration/os/utils/gov.go | 197 ++ testutil/integration/os/utils/params.go | 87 + testutil/integration/os/utils/staking.go | 111 + testutil/integration/os/utils/types.go | 15 + testutil/integration/os/utils/unit.go | 144 + testutil/tx/cosmos.go | 146 + testutil/tx/eip712.go | 206 ++ testutil/tx/eth.go | 165 + testutil/tx/signer.go | 83 + x/asset/genesis.go | 4 + x/asset/keeper/keeper.go | 4 +- x/asset/module.go | 23 +- x/asset/types/expected_keepers.go | 1 + x/asset/types/params.go | 4 +- 111 files changed, 11076 insertions(+), 3231 deletions(-) create mode 100644 example_chain/Makefile create mode 100644 example_chain/README.md create mode 100644 example_chain/activators.go create mode 100644 example_chain/ante/ante.go create mode 100644 example_chain/ante/cosmos_handler.go create mode 100644 example_chain/ante/evm_benchmark_test.go create mode 100644 example_chain/ante/evm_handler.go create mode 100644 example_chain/ante/handler_options.go create mode 100644 example_chain/ante/handler_options_test.go create mode 100644 example_chain/ante/integration_test.go create mode 100644 example_chain/app.go create mode 100644 example_chain/config.go create mode 100644 example_chain/config_testing.go create mode 100644 example_chain/constants.go create mode 100644 example_chain/eips/README.md create mode 100644 example_chain/eips/eips.go create mode 100644 example_chain/eips/eips_test.go create mode 100644 example_chain/eips/testdata/Counter.json create mode 100644 example_chain/eips/testdata/Counter.sol create mode 100644 example_chain/eips/testdata/CounterFactory.json create mode 100644 example_chain/eips/testdata/CounterFactory.sol create mode 100644 example_chain/eips/testdata/contracts.go create mode 100644 example_chain/export.go create mode 100644 example_chain/genesis.go create mode 100755 example_chain/local_node.sh create mode 100644 example_chain/osd/cmd/root.go create mode 100644 example_chain/osd/config/config.go create mode 100644 example_chain/osd/main.go create mode 100644 example_chain/precompiles.go create mode 100644 example_chain/test_helpers.go create mode 100644 example_chain/testutil/abci.go create mode 100644 example_chain/testutil/contract.go create mode 100644 example_chain/testutil/eth_setup.go create mode 100644 example_chain/testutil/fund.go create mode 100644 example_chain/testutil/gas.go create mode 100644 example_chain/testutil/integration.go create mode 100644 example_chain/token_pair.go create mode 100644 example_chain/upgrades.go delete mode 100644 precompiles/erc20/integration_test.go create mode 100644 testutil/integration/common/factory/base.go create mode 100644 testutil/integration/common/factory/distribution.go create mode 100644 testutil/integration/common/factory/factory.go create mode 100644 testutil/integration/common/factory/fund.go create mode 100644 testutil/integration/common/factory/helper.go create mode 100644 testutil/integration/common/factory/sign.go create mode 100644 testutil/integration/common/factory/staking.go create mode 100644 testutil/integration/common/factory/types.go create mode 100644 testutil/integration/common/grpc/account.go create mode 100644 testutil/integration/common/grpc/authz.go create mode 100644 testutil/integration/common/grpc/bank.go create mode 100644 testutil/integration/common/grpc/distribution.go create mode 100644 testutil/integration/common/grpc/grpc.go create mode 100644 testutil/integration/common/grpc/staking.go create mode 100644 testutil/integration/common/network/network.go create mode 100644 testutil/integration/ibc/chain/chain.go create mode 100644 testutil/integration/ibc/coordinator/coordinator.go create mode 100644 testutil/integration/ibc/coordinator/types.go create mode 100644 testutil/integration/ibc/coordinator/utils.go create mode 100644 testutil/integration/os/factory/broadcast.go create mode 100644 testutil/integration/os/factory/build.go create mode 100644 testutil/integration/os/factory/factory.go create mode 100644 testutil/integration/os/factory/helpers.go create mode 100644 testutil/integration/os/factory/sign.go create mode 100644 testutil/integration/os/factory/types.go create mode 100644 testutil/integration/os/grpc/evm.go create mode 100644 testutil/integration/os/grpc/feemarket.go create mode 100644 testutil/integration/os/grpc/gov.go create mode 100644 testutil/integration/os/grpc/grpc.go create mode 100644 testutil/integration/os/keyring/keyring.go create mode 100644 testutil/integration/os/network/abci.go create mode 100644 testutil/integration/os/network/amounts.go create mode 100644 testutil/integration/os/network/chain_id_modifiers.go create mode 100644 testutil/integration/os/network/clients.go create mode 100644 testutil/integration/os/network/coins.go create mode 100644 testutil/integration/os/network/config.go create mode 100644 testutil/integration/os/network/config_test.go create mode 100644 testutil/integration/os/network/example_contracts.go create mode 100644 testutil/integration/os/network/ibc.go create mode 100644 testutil/integration/os/network/network.go create mode 100644 testutil/integration/os/network/setup.go create mode 100644 testutil/integration/os/network/unit_network.go create mode 100644 testutil/integration/os/utils/bank.go create mode 100644 testutil/integration/os/utils/bank_test.go create mode 100644 testutil/integration/os/utils/contracts.go create mode 100644 testutil/integration/os/utils/erc20.go create mode 100644 testutil/integration/os/utils/events.go create mode 100644 testutil/integration/os/utils/evm.go create mode 100644 testutil/integration/os/utils/evm_test.go create mode 100644 testutil/integration/os/utils/genesis.go create mode 100644 testutil/integration/os/utils/gov.go create mode 100644 testutil/integration/os/utils/params.go create mode 100644 testutil/integration/os/utils/staking.go create mode 100644 testutil/integration/os/utils/types.go create mode 100644 testutil/integration/os/utils/unit.go create mode 100644 testutil/tx/cosmos.go create mode 100644 testutil/tx/eip712.go create mode 100644 testutil/tx/eth.go create mode 100644 testutil/tx/signer.go diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index d6bb4dcd..39ed6ea9 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -34,9 +34,9 @@ import ( "github.com/evmos/os/encoding" "github.com/evmos/os/ethereum/eip712" - tests "github.com/evmos/os/testutil/tx" "github.com/evmos/os/types" evmtypes "github.com/evmos/os/x/evm/types" + tests "github.com/realiotech/realio-network/testutil/tx" feemarkettypes "github.com/evmos/os/x/feemarket/types" diff --git a/example_chain/Makefile b/example_chain/Makefile new file mode 100644 index 00000000..3c279737 --- /dev/null +++ b/example_chain/Makefile @@ -0,0 +1,103 @@ +#!/usr/bin/make -f + +VERSION ?= $(shell echo $(shell git describe --tags --always) | sed 's/^v//') +TMVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::') +COMMIT := $(shell git log -1 --format='%H') +BINDIR ?= $(GOPATH)/bin +EXAMPLE_BINARY = osd +BUILDDIR ?= $(CURDIR)/build + +export GO111MODULE = on + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY: default_target + +# process build tags +build_tags = netgo + +ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS))) + build_tags += gcc +endif +build_tags += $(BUILD_TAGS) +build_tags := $(strip $(build_tags)) + +# process linker flags + +ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=os \ + -X github.com/cosmos/cosmos-sdk/version.AppName=$(EXAMPLE_BINARY) \ + -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \ + -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \ + -X github.com/cometbft/cometbft/version.TMCoreSemVer=$(TMVERSION) + +# DB backend selection +ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS))) + ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb +endif + +# add build tags to linker flags +whitespace := $(subst ,, ) +comma := , +build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags)) +ldflags += -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" + +ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS))) + ldflags += -w -s +endif +ldflags += $(LDFLAGS) +ldflags := $(strip $(ldflags)) + +BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' +# check for nostrip option +ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS))) + BUILD_FLAGS += -trimpath +endif + +# check if no optimization option is passed +# used for remote debugging +ifneq (,$(findstring nooptimization,$(COSMOS_BUILD_OPTIONS))) + BUILD_FLAGS += -gcflags "all=-N -l" +endif + +# # The below include contains the tools and runsim targets. +# include contrib/devtools/Makefile + +############################################################################### +### Build ### +############################################################################### + +BUILD_TARGETS := build install + +build: BUILD_ARGS=-o $(BUILDDIR)/ +build-linux: + GOOS=linux GOARCH=amd64 $(MAKE) build + +$(BUILD_TARGETS): go.sum $(BUILDDIR)/ + CGO_ENABLED="1" go $@ $(BUILD_FLAGS) $(BUILD_ARGS) ./... + +$(BUILDDIR)/: + mkdir -p $(BUILDDIR)/ + +distclean: clean tools-clean + +clean: + rm -rf \ + $(BUILDDIR)/ \ + artifacts/ \ + tmp-swagger-gen/ + +all: build + +build-all: build lint test vulncheck + +.PHONY: distclean clean build-all + +############################################################################### +### Tools & Dependencies ### +############################################################################### + +go.sum: go.mod + echo "Ensure dependencies have not been modified ..." >&2 + go mod verify + go mod tidy diff --git a/example_chain/README.md b/example_chain/README.md new file mode 100644 index 00000000..42fa0cc1 --- /dev/null +++ b/example_chain/README.md @@ -0,0 +1,58 @@ +# Example evmOS Chain + +This directory contains an example chain that uses the evmOS modules. +It is based on the simapp implementation on the Cosmos SDK repository, +which itself is a simplified version of a Cosmos SDK-based blockchain. + +This chain implementation is used to demonstrate the integration of evmOS +as well as to provide a chain object for testing purposes within the repository. + +## Config + +By default, this chain has the following configuration: + +| Option | Value | +|---------------------|------------------------| +| Binary | `osd` | +| Chain ID | `os_9005-1` | +| Custom Opcodes | - | +| Default Token Pairs | 1 for the native token | +| Denomination | `aevmos` | +| EVM flavor | permissionless | +| Enabled Precompiles | all | + +## Running The Chain + +To run the example, execute the local node script found within this repository: + +```bash +./local_node.sh [FLAGS] +``` + +Available flags are: + +- `-y`: Overwrite previous database +- `-n`: Do **not** overwrite previous database +- `--no-install`: Skip installation of the binary +- `--remote-debugging`: Build a binary suitable for remote debugging + +## Available Cosmos SDK Modules + +As mentioned above, this exemplary chain implementation is a reduced version of `simapp`. +Specifically, instead of offering access to all Cosmos SDK modules, it just includes the following: + +- `auth` +- `authz` +- `bank` +- `capability` +- `consensus` +- `distribution` +- `evidence` +- `feegrant` +- `genutil` +- `gov` +- `mint` +- `params` +- `slashing` +- `staking` +- `upgrade` diff --git a/example_chain/activators.go b/example_chain/activators.go new file mode 100644 index 00000000..265e84a5 --- /dev/null +++ b/example_chain/activators.go @@ -0,0 +1,16 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package example_chain + +import ( + "github.com/evmos/os/x/evm/core/vm" + "github.com/realiotech/realio-network/example_chain/eips" +) + +// evmosActivators defines a map of opcode modifiers associated +// with a key defining the corresponding EIP. +var evmosActivators = map[string]func(*vm.JumpTable){ + "evmos_0": eips.Enable0000, + "evmos_1": eips.Enable0001, + "evmos_2": eips.Enable0002, +} diff --git a/example_chain/ante/ante.go b/example_chain/ante/ante.go new file mode 100644 index 00000000..059dfcea --- /dev/null +++ b/example_chain/ante/ante.go @@ -0,0 +1,55 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package ante + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" +) + +// NewAnteHandler returns an ante handler responsible for attempting to route an +// Ethereum or SDK transaction to an internal ante handler for performing +// transaction-level processing (e.g. fee payment, signature verification) before +// being passed onto it's respective handler. +func NewAnteHandler(options HandlerOptions) sdk.AnteHandler { + return func( + ctx sdk.Context, tx sdk.Tx, sim bool, + ) (newCtx sdk.Context, err error) { + var anteHandler sdk.AnteHandler + + txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx) + if ok { + opts := txWithExtensions.GetExtensionOptions() + if len(opts) > 0 { + switch typeURL := opts[0].GetTypeUrl(); typeURL { + case "/os.evm.v1.ExtensionOptionsEthereumTx": + // handle as *evmtypes.MsgEthereumTx + anteHandler = newMonoEVMAnteHandler(options) + case "/os.types.v1.ExtensionOptionDynamicFeeTx": + // cosmos-sdk tx with dynamic fee extension + anteHandler = newCosmosAnteHandler(options) + default: + return ctx, errorsmod.Wrapf( + errortypes.ErrUnknownExtensionOptions, + "rejecting tx with unsupported extension option: %s", typeURL, + ) + } + + return anteHandler(ctx, tx, sim) + } + } + + // handle as totally normal Cosmos SDK tx + switch tx.(type) { + case sdk.Tx: + anteHandler = newCosmosAnteHandler(options) + default: + return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx) + } + + return anteHandler(ctx, tx, sim) + } +} diff --git a/example_chain/ante/cosmos_handler.go b/example_chain/ante/cosmos_handler.go new file mode 100644 index 00000000..0f934754 --- /dev/null +++ b/example_chain/ante/cosmos_handler.go @@ -0,0 +1,41 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + sdkvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante" + evmoscosmosante "github.com/evmos/os/ante/cosmos" + evmante "github.com/evmos/os/ante/evm" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// newCosmosAnteHandler creates the default ante handler for Cosmos transactions +func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { + return sdk.ChainAnteDecorators( + evmoscosmosante.NewRejectMessagesDecorator(), // reject MsgEthereumTxs + evmoscosmosante.NewAuthzLimiterDecorator( // disable the Msg types that cannot be included on an authz.MsgExec msgs field + sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), + sdk.MsgTypeURL(&sdkvesting.MsgCreateVestingAccount{}), + ), + ante.NewSetUpContextDecorator(), + ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), + ante.NewValidateBasicDecorator(), + ante.NewTxTimeoutHeightDecorator(), + ante.NewValidateMemoDecorator(options.AccountKeeper), + evmoscosmosante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), + ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), + // SetPubKeyDecorator must be called before all signature verification decorators + ante.NewSetPubKeyDecorator(options.AccountKeeper), + ante.NewValidateSigCountDecorator(options.AccountKeeper), + ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), + ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + ante.NewIncrementSequenceDecorator(options.AccountKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), + evmante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), + ) +} diff --git a/example_chain/ante/evm_benchmark_test.go b/example_chain/ante/evm_benchmark_test.go new file mode 100644 index 00000000..d603d38c --- /dev/null +++ b/example_chain/ante/evm_benchmark_test.go @@ -0,0 +1,157 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package ante_test + +import ( + "fmt" + "math/big" + "testing" + + "cosmossdk.io/errors" + "cosmossdk.io/math" + sdktypes "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/evmos/os/ante" + ethante "github.com/evmos/os/ante/evm" + cmmnfactory "github.com/evmos/os/testutil/integration/common/factory" + "github.com/evmos/os/testutil/integration/os/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + evmostypes "github.com/evmos/os/types" + evmtypes "github.com/evmos/os/x/evm/types" + chainante "github.com/realiotech/realio-network/example_chain/ante" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +type benchmarkSuite struct { + network *network.UnitTestNetwork + grpcHandler grpc.Handler + txFactory factory.TxFactory + keyring testkeyring.Keyring +} + +// Setup +var table = []struct { + name string + txType string + simulate bool +}{ + { + "evm_transfer_sim", + "evm_transfer", + true, + }, + { + "evm_transfer", + "evm_transfer", + false, + }, + { + "bank_msg_send_sim", + "bank_msg_send", + true, + }, + { + "bank_msg_send", + "bank_msg_send", + false, + }, +} + +func BenchmarkAnteHandler(b *testing.B) { + keyring := testkeyring.New(2) + + for _, v := range table { + // Reset chain on every tx type to have a clean state + // and a fair benchmark + b.StopTimer() + unitNetwork := network.NewUnitTestNetwork( + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + ) + grpcHandler := grpc.NewIntegrationHandler(unitNetwork) + txFactory := factory.New(unitNetwork, grpcHandler) + suite := benchmarkSuite{ + network: unitNetwork, + grpcHandler: grpcHandler, + txFactory: txFactory, + keyring: keyring, + } + + handlerOptions := suite.generateHandlerOptions() + ante := chainante.NewAnteHandler(handlerOptions) + b.StartTimer() + + b.Run(fmt.Sprintf("tx_type_%v", v.name), func(b *testing.B) { + for i := 0; i < b.N; i++ { + // Stop timer while building the tx setup + b.StopTimer() + // Start with a clean block + if err := unitNetwork.NextBlock(); err != nil { + b.Fatal(errors.Wrap(err, "failed to create block")) + } + ctx := unitNetwork.GetContext() + + // Generate fresh tx type + tx, err := suite.generateTxType(v.txType) + if err != nil { + b.Fatal(errors.Wrap(err, "failed to generate tx type")) + } + b.StartTimer() + + // Run benchmark + _, err = ante(ctx, tx, v.simulate) + if err != nil { + b.Fatal(errors.Wrap(err, "failed to run ante handler")) + } + } + }) + } +} + +func (s *benchmarkSuite) generateTxType(txType string) (sdktypes.Tx, error) { + switch txType { + case "evm_transfer": + senderPriv := s.keyring.GetPrivKey(0) + receiver := s.keyring.GetKey(1) + txArgs := evmtypes.EvmTxArgs{ + To: &receiver.Addr, + Amount: big.NewInt(1000), + } + return s.txFactory.GenerateSignedEthTx(senderPriv, txArgs) + case "bank_msg_send": + sender := s.keyring.GetKey(1) + receiver := s.keyring.GetAccAddr(0) + bankmsg := banktypes.NewMsgSend( + sender.AccAddr, + receiver, + sdktypes.NewCoins( + sdktypes.NewCoin( + s.network.GetBaseDenom(), + math.NewInt(1000), + ), + ), + ) + txArgs := cmmnfactory.CosmosTxArgs{Msgs: []sdktypes.Msg{bankmsg}} + return s.txFactory.BuildCosmosTx(sender.Priv, txArgs) + default: + return nil, fmt.Errorf("invalid tx type") + } +} + +func (s *benchmarkSuite) generateHandlerOptions() chainante.HandlerOptions { + encCfg := s.network.GetEncodingConfig() + return chainante.HandlerOptions{ + Cdc: s.network.App.AppCodec(), + AccountKeeper: s.network.App.AccountKeeper, + BankKeeper: s.network.App.BankKeeper, + ExtensionOptionChecker: evmostypes.HasDynamicFeeExtensionOption, + EvmKeeper: s.network.App.EVMKeeper, + FeegrantKeeper: s.network.App.FeeGrantKeeper, + IBCKeeper: s.network.App.IBCKeeper, + FeeMarketKeeper: s.network.App.FeeMarketKeeper, + SignModeHandler: encCfg.TxConfig.SignModeHandler(), + SigGasConsumer: ante.SigVerificationGasConsumer, + MaxTxGasWanted: 1_000_000_000, + TxFeeChecker: ethante.NewDynamicFeeChecker(s.network.App.FeeMarketKeeper), + } +} diff --git a/example_chain/ante/evm_handler.go b/example_chain/ante/evm_handler.go new file mode 100644 index 00000000..fdb7e54c --- /dev/null +++ b/example_chain/ante/evm_handler.go @@ -0,0 +1,21 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + evmante "github.com/evmos/os/ante/evm" +) + +// newMonoEVMAnteHandler creates the sdk.AnteHandler implementation for the EVM transactions. +func newMonoEVMAnteHandler(options HandlerOptions) sdk.AnteHandler { + return sdk.ChainAnteDecorators( + evmante.NewEVMMonoDecorator( + options.AccountKeeper, + options.FeeMarketKeeper, + options.EvmKeeper, + options.MaxTxGasWanted, + ), + ) +} diff --git a/example_chain/ante/handler_options.go b/example_chain/ante/handler_options.go new file mode 100644 index 00000000..8dcaa065 --- /dev/null +++ b/example_chain/ante/handler_options.go @@ -0,0 +1,66 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package ante + +import ( + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + txsigning "cosmossdk.io/x/tx/signing" + "github.com/cosmos/cosmos-sdk/codec" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" + anteinterfaces "github.com/evmos/os/ante/interfaces" +) + +// HandlerOptions defines the list of module keepers required to run the Evmos +// AnteHandler decorators. +type HandlerOptions struct { + Cdc codec.BinaryCodec + AccountKeeper anteinterfaces.AccountKeeper + BankKeeper anteinterfaces.BankKeeper + IBCKeeper *ibckeeper.Keeper + FeeMarketKeeper anteinterfaces.FeeMarketKeeper + EvmKeeper anteinterfaces.EVMKeeper + FeegrantKeeper ante.FeegrantKeeper + ExtensionOptionChecker ante.ExtensionOptionChecker + SignModeHandler *txsigning.HandlerMap + SigGasConsumer func(meter storetypes.GasMeter, sig signing.SignatureV2, params authtypes.Params) error + MaxTxGasWanted uint64 + TxFeeChecker ante.TxFeeChecker +} + +// Validate checks if the keepers are defined +func (options HandlerOptions) Validate() error { + if options.Cdc == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "codec is required for AnteHandler") + } + if options.AccountKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler") + } + if options.BankKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler") + } + if options.IBCKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "ibc keeper is required for AnteHandler") + } + if options.FeeMarketKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler") + } + if options.EvmKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler") + } + if options.SigGasConsumer == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "signature gas consumer is required for AnteHandler") + } + if options.SignModeHandler == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for AnteHandler") + } + if options.TxFeeChecker == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "tx fee checker is required for AnteHandler") + } + return nil +} diff --git a/example_chain/ante/handler_options_test.go b/example_chain/ante/handler_options_test.go new file mode 100644 index 00000000..ee0cb9a6 --- /dev/null +++ b/example_chain/ante/handler_options_test.go @@ -0,0 +1,146 @@ +package ante_test + +import ( + "testing" + + "github.com/evmos/os/ante" + ethante "github.com/evmos/os/ante/evm" + "github.com/evmos/os/types" + chainante "github.com/realiotech/realio-network/example_chain/ante" + "github.com/realiotech/realio-network/testutil/integration/os/network" + "github.com/stretchr/testify/require" +) + +func TestValidateHandlerOptions(t *testing.T) { + nw := network.NewUnitTestNetwork() + cases := []struct { + name string + options chainante.HandlerOptions + expPass bool + }{ + { + "fail - empty options", + chainante.HandlerOptions{}, + false, + }, + { + "fail - empty account keeper", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nil, + }, + false, + }, + { + "fail - empty bank keeper", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nil, + }, + false, + }, + { + "fail - empty IBC keeper", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nil, + }, + false, + }, + { + "fail - empty fee market keeper", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nil, + }, + false, + }, + { + "fail - empty EVM keeper", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nw.App.FeeMarketKeeper, + EvmKeeper: nil, + }, + false, + }, + { + "fail - empty signature gas consumer", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nw.App.FeeMarketKeeper, + EvmKeeper: nw.App.EVMKeeper, + SigGasConsumer: nil, + }, + false, + }, + { + "fail - empty signature mode handler", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nw.App.FeeMarketKeeper, + EvmKeeper: nw.App.EVMKeeper, + SigGasConsumer: ante.SigVerificationGasConsumer, + SignModeHandler: nil, + }, + false, + }, + { + "fail - empty tx fee checker", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nw.App.FeeMarketKeeper, + EvmKeeper: nw.App.EVMKeeper, + SigGasConsumer: ante.SigVerificationGasConsumer, + SignModeHandler: nw.App.GetTxConfig().SignModeHandler(), + TxFeeChecker: nil, + }, + false, + }, + { + "success - default app options", + chainante.HandlerOptions{ + Cdc: nw.App.AppCodec(), + AccountKeeper: nw.App.AccountKeeper, + BankKeeper: nw.App.BankKeeper, + ExtensionOptionChecker: types.HasDynamicFeeExtensionOption, + EvmKeeper: nw.App.EVMKeeper, + FeegrantKeeper: nw.App.FeeGrantKeeper, + IBCKeeper: nw.App.IBCKeeper, + FeeMarketKeeper: nw.App.FeeMarketKeeper, + SignModeHandler: nw.GetEncodingConfig().TxConfig.SignModeHandler(), + SigGasConsumer: ante.SigVerificationGasConsumer, + MaxTxGasWanted: 40000000, + TxFeeChecker: ethante.NewDynamicFeeChecker(nw.App.FeeMarketKeeper), + }, + true, + }, + } + + for _, tc := range cases { + err := tc.options.Validate() + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} diff --git a/example_chain/ante/integration_test.go b/example_chain/ante/integration_test.go new file mode 100644 index 00000000..ed5240c4 --- /dev/null +++ b/example_chain/ante/integration_test.go @@ -0,0 +1,173 @@ +package ante_test + +import ( + "cosmossdk.io/math" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + commonfactory "github.com/evmos/os/testutil/integration/common/factory" + "github.com/evmos/os/testutil/integration/os/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + integrationutils "github.com/evmos/os/testutil/integration/os/utils" + "github.com/realiotech/realio-network/testutil/integration/os/network" + testutiltx "github.com/realiotech/realio-network/testutil/tx" + + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/ginkgo/v2" + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/gomega" +) + +type IntegrationTestSuite struct { + network network.Network + factory factory.TxFactory + grpcHandler grpc.Handler + keyring testkeyring.Keyring +} + +var _ = Describe("when sending a Cosmos transaction", Label("AnteHandler"), Ordered, func() { + var ( + s *IntegrationTestSuite + addr sdk.AccAddress + priv cryptotypes.PrivKey + msg sdk.Msg + ) + + BeforeAll(func() { + keyring := testkeyring.New(3) + + integrationNetwork := network.New( + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + ) + grpcHandler := grpc.NewIntegrationHandler(integrationNetwork) + txFactory := factory.New(integrationNetwork, grpcHandler) + s = &IntegrationTestSuite{ + network: integrationNetwork, + factory: txFactory, + grpcHandler: grpcHandler, + keyring: keyring, + } + }) + + Context("and the sender account has enough balance to pay for the transaction cost", Ordered, func() { + var ( + // rewards are the real accrued rewards + rewards sdk.DecCoins + // minExpRewards are the minimun rewards that should be accrued + // for the test case + minExpRewards = sdk.DecCoins{sdk.DecCoin{Amount: math.LegacyNewDec(1e5), Denom: s.network.GetBaseDenom()}} + delegationCoin = sdk.Coin{Amount: math.NewInt(1e15), Denom: s.network.GetBaseDenom()} + transferAmt = math.NewInt(1e14) + ) + + BeforeEach(func() { + key := s.keyring.GetKey(0) + addr = key.AccAddr + priv = key.Priv + + msg = &banktypes.MsgSend{ + FromAddress: addr.String(), + ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn", + Amount: sdk.Coins{sdk.Coin{Amount: transferAmt, Denom: s.network.GetBaseDenom()}}, + } + + valAddr := s.network.GetValidators()[0].OperatorAddress + err := s.factory.Delegate(priv, valAddr, delegationCoin) + Expect(err).To(BeNil()) + + rewards, err = integrationutils.WaitToAccrueRewards(s.network, s.grpcHandler, addr.String(), minExpRewards) + Expect(err).To(BeNil()) + }) + + It("should succeed & not withdraw any staking rewards", func() { + prevBalanceRes, err := s.grpcHandler.GetBalanceFromBank(addr, s.network.GetBaseDenom()) + Expect(err).To(BeNil()) + + baseFeeRes, err := s.grpcHandler.GetEvmBaseFee() + Expect(err).To(BeNil()) + Expect(baseFeeRes).ToNot(BeNil(), "baseFeeRes is nil") + + gasPrice := baseFeeRes.BaseFee + + res, err := s.factory.ExecuteCosmosTx( + priv, + commonfactory.CosmosTxArgs{ + Msgs: []sdk.Msg{msg}, + GasPrice: gasPrice, + }, + ) + Expect(err).To(BeNil()) + Expect(res.IsOK()).To(BeTrue()) + + // include the tx in a block to update state + err = s.network.NextBlock() + Expect(err).To(BeNil()) + + // fees should be deducted from balance + Expect(baseFeeRes.BaseFee).ToNot(BeNil(), "baseFeeRes.BaseFee is nil") + + feesAmt := math.NewInt(res.GasWanted).Mul(*baseFeeRes.BaseFee) + balanceRes, err := s.grpcHandler.GetBalanceFromBank(addr, s.network.GetBaseDenom()) + Expect(err).To(BeNil()) + Expect(balanceRes.Balance.Amount).To(Equal(prevBalanceRes.Balance.Amount.Sub(transferAmt).Sub(feesAmt))) + + rewardsRes, err := s.grpcHandler.GetDelegationTotalRewards(addr.String()) + Expect(err).To(BeNil()) + + // rewards should not be used. Should be more + // than the previous value queried + Expect(rewardsRes.Total.Sub(rewards).IsAllPositive()).To(BeTrue()) + }) + }) + + Context("and the sender account neither has enough balance nor sufficient staking rewards to pay for the transaction cost", func() { + BeforeEach(func() { + addr, priv = testutiltx.NewAccAddressAndKey() + + // this is a new address that does not exist on chain. + // Transfer 1 aevmos to this account so it is + // added on chain + err := s.factory.FundAccount( + s.keyring.GetKey(0), + addr, + sdk.Coins{ + sdk.Coin{ + Amount: math.NewInt(1), + Denom: s.network.GetBaseDenom(), + }, + }, + ) + Expect(err).To(BeNil()) + // persist the state changes + Expect(s.network.NextBlock()).To(BeNil()) + + msg = &banktypes.MsgSend{ + FromAddress: addr.String(), + ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn", + Amount: sdk.Coins{sdk.Coin{Amount: math.NewInt(1e14), Denom: s.network.GetBaseDenom()}}, + } + }) + + It("should fail", func() { + var gas uint64 = 200_000 // specify gas to avoid failing on simulation tx (internal call in the ExecuteCosmosTx if gas not specified) + res, err := s.factory.ExecuteCosmosTx( + priv, + commonfactory.CosmosTxArgs{ + Msgs: []sdk.Msg{msg}, + Gas: &gas, + }, + ) + Expect(res.IsErr()).To(BeTrue()) + Expect(res.GetLog()).To(ContainSubstring("insufficient funds")) + Expect(err).To(BeNil()) + Expect(s.network.NextBlock()).To(BeNil()) + }) + + It("should not withdraw any staking rewards", func() { + rewardsRes, err := s.grpcHandler.GetDelegationTotalRewards(addr.String()) + Expect(err).To(BeNil()) + Expect(rewardsRes.Total.Empty()).To(BeTrue()) + }) + }) +}) diff --git a/example_chain/app.go b/example_chain/app.go new file mode 100644 index 00000000..9691db6e --- /dev/null +++ b/example_chain/app.go @@ -0,0 +1,1135 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import ( + "encoding/json" + "fmt" + "io" + "maps" + "os" + "sort" + + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + "cosmossdk.io/client/v2/autocli" + clienthelpers "cosmossdk.io/client/v2/helpers" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + "cosmossdk.io/x/evidence" + evidencekeeper "cosmossdk.io/x/evidence/keeper" + evidencetypes "cosmossdk.io/x/evidence/types" + "cosmossdk.io/x/feegrant" + feegrantkeeper "cosmossdk.io/x/feegrant/keeper" + feegrantmodule "cosmossdk.io/x/feegrant/module" + "cosmossdk.io/x/upgrade" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" + upgradetypes "cosmossdk.io/x/upgrade/types" + abci "github.com/cometbft/cometbft/abci/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" + "github.com/cosmos/cosmos-sdk/client/grpc/node" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/api" + "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/msgservice" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/auth" + authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/posthandler" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/mint" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/ibc-go/modules/capability" + capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer" + ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v8/modules/core" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctestingtypes "github.com/cosmos/ibc-go/v8/testing/types" + evmosante "github.com/evmos/os/ante" + evmosevmante "github.com/evmos/os/ante/evm" + evmosencoding "github.com/evmos/os/encoding" + srvflags "github.com/evmos/os/server/flags" + evmostypes "github.com/evmos/os/types" + evmosutils "github.com/evmos/os/utils" + "github.com/evmos/os/x/erc20" + erc20keeper "github.com/evmos/os/x/erc20/keeper" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/evmos/os/x/evm" + "github.com/evmos/os/x/evm/core/vm" + evmkeeper "github.com/evmos/os/x/evm/keeper" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/evmos/os/x/feemarket" + feemarketkeeper "github.com/evmos/os/x/feemarket/keeper" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + chainante "github.com/realiotech/realio-network/example_chain/ante" + "github.com/spf13/cast" + + // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens + "github.com/evmos/os/x/ibc/transfer" + transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" + + // Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes + _ "github.com/evmos/os/x/evm/core/tracers/js" + _ "github.com/evmos/os/x/evm/core/tracers/native" + assetkeeper "github.com/realiotech/realio-network/x/asset/keeper" + assettypes "github.com/realiotech/realio-network/x/asset/types" + "github.com/realiotech/realio-network/x/asset" +) + +func init() { + // manually update the power reduction by replacing micro (u) -> atto (a) evmos + sdk.DefaultPowerReduction = evmostypes.AttoPowerReduction + + // get the user's home directory + var err error + DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".osd") + if err != nil { + panic(err) + } +} + +const appName = "os" + +var ( + // DefaultNodeHome default home directories for the application daemon + DefaultNodeHome string + + // module account permissions + maccPerms = map[string][]string{ + authtypes.FeeCollectorName: nil, + distrtypes.ModuleName: nil, + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + minttypes.ModuleName: {authtypes.Minter}, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + govtypes.ModuleName: {authtypes.Burner}, + + // evmOS modules + evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + feemarkettypes.ModuleName: nil, + erc20types.ModuleName: {authtypes.Minter, authtypes.Burner}, + assettypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + } +) + +var ( + _ runtime.AppI = (*ExampleChain)(nil) + _ servertypes.Application = (*ExampleChain)(nil) +) + +// ExampleChain extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. +type ExampleChain struct { + *baseapp.BaseApp + + legacyAmino *codec.LegacyAmino + appCodec codec.Codec + interfaceRegistry types.InterfaceRegistry + txConfig client.TxConfig + + // keys to access the substores + keys map[string]*storetypes.KVStoreKey + tkeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey + + // keepers + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + UpgradeKeeper *upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + AuthzKeeper authzkeeper.Keeper + EvidenceKeeper evidencekeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper + + // IBC keepers + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + TransferKeeper transferkeeper.Keeper + scopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + + // evmOS keepers + FeeMarketKeeper feemarketkeeper.Keeper + EVMKeeper *evmkeeper.Keeper + Erc20Keeper erc20keeper.Keeper + AssetKeeper assetkeeper.Keeper + + // the module manager + ModuleManager *module.Manager + BasicModuleManager module.BasicManager + + // simulation manager + sm *module.SimulationManager + + // module configurator + configurator module.Configurator +} + +// NewExampleApp returns a reference to an initialized ExampleChain. +func NewExampleApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + appOpts servertypes.AppOptions, + evmosAppOptions EvmosOptionsFn, + baseAppOptions ...func(*baseapp.BaseApp), +) *ExampleChain { + encodingConfig := evmosencoding.MakeConfig() + + appCodec := encodingConfig.Codec + legacyAmino := encodingConfig.Amino + interfaceRegistry := encodingConfig.InterfaceRegistry + txConfig := encodingConfig.TxConfig + + // Below we could construct and set an application specific mempool and + // ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are + // already set in the SDK's BaseApp, this shows an example of how to override + // them. + // + // Example: + // + // bApp := baseapp.NewBaseApp(...) + // nonceMempool := mempool.NewSenderNonceMempool() + // abciPropHandler := NewDefaultProposalHandler(nonceMempool, bApp) + // + // bApp.SetMempool(nonceMempool) + // bApp.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) + // bApp.SetProcessProposal(abciPropHandler.ProcessProposalHandler()) + // + // Alternatively, you can construct BaseApp options, append those to + // baseAppOptions and pass them to NewBaseApp. + // + // Example: + // + // prepareOpt = func(app *baseapp.BaseApp) { + // abciPropHandler := baseapp.NewDefaultProposalHandler(nonceMempool, app) + // app.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) + // } + // baseAppOptions = append(baseAppOptions, prepareOpt) + + bApp := baseapp.NewBaseApp( + appName, + logger, + db, + // use transaction decoder to support the sdk.Tx interface instead of sdk.StdTx + encodingConfig.TxConfig.TxDecoder(), + baseAppOptions..., + ) + bApp.SetCommitMultiStoreTracer(traceStore) + bApp.SetVersion(version.Version) + bApp.SetInterfaceRegistry(interfaceRegistry) + bApp.SetTxEncoder(txConfig.TxEncoder()) + + // initialize the evmOS application configuration + if err := evmosAppOptions(bApp.ChainID()); err != nil { + panic(err) + } + + keys := storetypes.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + evidencetypes.StoreKey, capabilitytypes.StoreKey, + authzkeeper.StoreKey, + // ibc keys + ibcexported.StoreKey, ibctransfertypes.StoreKey, + // evmOS store keys + evmtypes.StoreKey, feemarkettypes.StoreKey, erc20types.StoreKey, + // asset store + assettypes.StoreKey, + ) + + tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey) + memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + + // load state streaming if enabled + if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil { + fmt.Printf("failed to load state streaming: %s", err) + os.Exit(1) + } + + // wire up the versiondb's `StreamingService` and `MultiStore`. + if cast.ToBool(appOpts.Get("versiondb.enable")) { + panic("version db not supported in this example chain") + } + + app := &ExampleChain{ + BaseApp: bApp, + legacyAmino: legacyAmino, + appCodec: appCodec, + txConfig: txConfig, + interfaceRegistry: interfaceRegistry, + keys: keys, + tkeys: tkeys, + memKeys: memKeys, + } + + app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) + + // get authority address + authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + // set the BaseApp's parameter store + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]), + authAddr, + runtime.EventService{}, + ) + bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore) + + app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) + + app.scopedIBCKeeper = app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) + app.ScopedTransferKeeper = app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + + // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating + // their scoped modules in `NewApp` with `ScopeToModule` + app.CapabilityKeeper.Seal() + + // add keepers + app.AccountKeeper = authkeeper.NewAccountKeeper( + appCodec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), + authtypes.ProtoBaseAccount, maccPerms, + authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), + sdk.GetConfig().GetBech32AccountAddrPrefix(), + authAddr, + ) + + app.BankKeeper = bankkeeper.NewBaseKeeper( + appCodec, + runtime.NewKVStoreService(keys[banktypes.StoreKey]), + app.AccountKeeper, + BlockedAddresses(), + authAddr, + logger, + ) + + // optional: enable sign mode textual by overwriting the default tx config (after setting the bank keeper) + enabledSignModes := append(authtx.DefaultSignModes, signingtypes.SignMode_SIGN_MODE_TEXTUAL) //nolint:gocritic + txConfigOpts := authtx.ConfigOptions{ + EnabledSignModes: enabledSignModes, + TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper), + } + txConfig, err := authtx.NewTxConfigWithOptions( + appCodec, + txConfigOpts, + ) + if err != nil { + panic(err) + } + app.txConfig = txConfig + + app.StakingKeeper = stakingkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), + app.AccountKeeper, + app.BankKeeper, + authAddr, + authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), + authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), + ) + + app.MintKeeper = mintkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[minttypes.StoreKey]), + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + authtypes.FeeCollectorName, + authAddr, + ) + + app.DistrKeeper = distrkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[distrtypes.StoreKey]), + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + authtypes.FeeCollectorName, + authAddr, + ) + + app.SlashingKeeper = slashingkeeper.NewKeeper( + appCodec, + app.LegacyAmino(), + runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), + app.StakingKeeper, + authAddr, + ) + + app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, runtime.NewKVStoreService(keys[feegrant.StoreKey]), app.AccountKeeper) + + // register the staking hooks + // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks + app.StakingKeeper.SetHooks( + stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), + ) + + app.AuthzKeeper = authzkeeper.NewKeeper( + runtime.NewKVStoreService(keys[authzkeeper.StoreKey]), + appCodec, + app.MsgServiceRouter(), + app.AccountKeeper, + ) + + // get skipUpgradeHeights from the app options + skipUpgradeHeights := map[int64]bool{} + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + homePath := cast.ToString(appOpts.Get(flags.FlagHome)) + // set the governance module account as the authority for conducting upgrades + app.UpgradeKeeper = upgradekeeper.NewKeeper( + skipUpgradeHeights, + runtime.NewKVStoreService(keys[upgradetypes.StoreKey]), + appCodec, + homePath, + app.BaseApp, + authAddr, + ) + + // Create IBC Keeper + app.IBCKeeper = ibckeeper.NewKeeper( + appCodec, + keys[ibcexported.StoreKey], + app.GetSubspace(ibcexported.ModuleName), + app.StakingKeeper, + app.UpgradeKeeper, + app.scopedIBCKeeper, + authAddr, + ) + + govConfig := govtypes.DefaultConfig() + /* + Example of setting gov params: + govConfig.MaxMetadataLen = 10000 + */ + govKeeper := govkeeper.NewKeeper( + appCodec, runtime.NewKVStoreService(keys[govtypes.StoreKey]), app.AccountKeeper, app.BankKeeper, + app.StakingKeeper, app.DistrKeeper, app.MsgServiceRouter(), govConfig, authAddr, + ) + + app.GovKeeper = *govKeeper.SetHooks( + govtypes.NewMultiGovHooks( + // register the governance hooks + ), + ) + + // create evidence keeper with router + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), + app.StakingKeeper, + app.SlashingKeeper, + app.AccountKeeper.AddressCodec(), + runtime.ProvideCometInfoService(), + ) + // If evidence needs to be handled for the app, set routes in router here and seal + app.EvidenceKeeper = *evidenceKeeper + + // evmOS keepers + app.FeeMarketKeeper = feemarketkeeper.NewKeeper( + appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), + keys[feemarkettypes.StoreKey], + tkeys[feemarkettypes.TransientKey], + app.GetSubspace(feemarkettypes.ModuleName), + ) + + // Set up EVM keeper + tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer)) + + // NOTE: it's required to set up the EVM keeper before the ERC-20 keeper, because it is used in its instantiation. + app.EVMKeeper = evmkeeper.NewKeeper( + // TODO: check why this is not adjusted to use the runtime module methods like SDK native keepers + appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], + authtypes.NewModuleAddress(govtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + app.FeeMarketKeeper, + &app.Erc20Keeper, + tracer, app.GetSubspace(evmtypes.ModuleName), + ) + + app.Erc20Keeper = erc20keeper.NewKeeper( + keys[erc20types.StoreKey], + appCodec, + authtypes.NewModuleAddress(govtypes.ModuleName), + app.AccountKeeper, + app.BankKeeper, + app.EVMKeeper, + app.StakingKeeper, + app.AuthzKeeper, + &app.TransferKeeper, + ) + + // instantiate IBC transfer keeper AFTER the ERC-20 keeper to use it in the instantiation + app.TransferKeeper = transferkeeper.NewKeeper( + appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), + nil, // we are passing no ics4 wrapper + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, + app.AccountKeeper, app.BankKeeper, app.ScopedTransferKeeper, + app.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers + authAddr, + ) + + app.AssetKeeper = *assetkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[assettypes.StoreKey]), + app.BankKeeper, + app.AccountKeeper, + authAddr, + ) + + // Override the ICS20 app module + transferModule := transfer.NewAppModule(app.TransferKeeper) + + /* + Create Transfer Stack + + transfer stack contains (from bottom to top): + - ERC-20 Middleware + - IBC Transfer + + SendPacket, since it is originating from the application to core IBC: + transferKeeper.SendPacket -> erc20.SendPacket -> channel.SendPacket + + RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way + channel.RecvPacket -> erc20.OnRecvPacket -> transfer.OnRecvPacket + */ + + // create IBC module from top to bottom of stack + var transferStack porttypes.IBCModule + + transferStack = transfer.NewIBCModule(app.TransferKeeper) + transferStack = erc20.NewIBCMiddleware(app.Erc20Keeper, transferStack) + + // Create static IBC router, add transfer route, then set and seal it + ibcRouter := porttypes.NewRouter() + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + + app.IBCKeeper.SetRouter(ibcRouter) + + // NOTE: we are adding all available evmOS EVM extensions. + // Not all of them need to be enabled, which can be configured on a per-chain basis. + app.EVMKeeper.WithStaticPrecompiles( + NewAvailableStaticPrecompiles( + *app.StakingKeeper, + app.DistrKeeper, + app.BankKeeper, + app.Erc20Keeper, + app.AuthzKeeper, + app.TransferKeeper, + app.IBCKeeper.ChannelKeeper, + app.EVMKeeper, + app.GovKeeper, + app.SlashingKeeper, + app.EvidenceKeeper, + ), + ) + + /**** Module Options ****/ + + // NOTE: Any module instantiated in the module manager that is later modified + // must be passed by reference here. + app.ModuleManager = module.NewManager( + genutil.NewAppModule( + app.AccountKeeper, app.StakingKeeper, + app, app.txConfig, + ), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), + feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), + slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()), + evidence.NewAppModule(app.EvidenceKeeper), + params.NewAppModule(app.ParamsKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), + // IBC modules + ibc.NewAppModule(app.IBCKeeper), + ibctm.NewAppModule(), + transferModule, + // evmOS modules + evm.NewAppModule(app.EVMKeeper, app.AccountKeeper, app.GetSubspace(evmtypes.ModuleName)), + feemarket.NewAppModule(app.FeeMarketKeeper, app.GetSubspace(feemarkettypes.ModuleName)), + erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper, app.GetSubspace(erc20types.ModuleName)), + asset.NewAppModule(appCodec, app.AssetKeeper, app.BankKeeper, app.GetSubspace(assettypes.ModuleName)), + ) + + // BasicModuleManager defines the module BasicManager which is in charge of setting up basic, + // non-dependant module elements, such as codec registration and genesis verification. + // By default, it is composed of all the modules from the module manager. + // Additionally, app module basics can be overwritten by passing them as an argument. + app.BasicModuleManager = module.NewBasicManagerFromManager( + app.ModuleManager, + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + stakingtypes.ModuleName: staking.AppModuleBasic{}, + govtypes.ModuleName: gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + }, + ), + ibctransfertypes.ModuleName: transfer.AppModuleBasic{AppModuleBasic: &ibctransfer.AppModuleBasic{}}, + }, + ) + app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino) + app.BasicModuleManager.RegisterInterfaces(interfaceRegistry) + + // NOTE: upgrade module is required to be prioritized + app.ModuleManager.SetOrderPreBlockers( + upgradetypes.ModuleName, + ) + + // During begin block slashing happens after distr.BeginBlocker so that + // there is nothing left over in the validator fee pool, so as to keep the + // CanWithdrawInvariant invariant. + // + // NOTE: staking module is required if HistoricalEntries param > 0 + // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) + app.ModuleManager.SetOrderBeginBlockers( + capabilitytypes.ModuleName, minttypes.ModuleName, + + // IBC modules + ibcexported.ModuleName, ibctransfertypes.ModuleName, + + // evmOS BeginBlockers + erc20types.ModuleName, feemarkettypes.ModuleName, + evmtypes.ModuleName, // NOTE: EVM BeginBlocker must come after FeeMarket BeginBlocker + + // TODO: remove no-ops? check if all are no-ops before removing + distrtypes.ModuleName, slashingtypes.ModuleName, + evidencetypes.ModuleName, stakingtypes.ModuleName, + authtypes.ModuleName, banktypes.ModuleName, govtypes.ModuleName, genutiltypes.ModuleName, + authz.ModuleName, feegrant.ModuleName, + paramstypes.ModuleName, consensusparamtypes.ModuleName, + ) + + // NOTE: the feemarket module should go last in order of end blockers that are actually doing something, + // to get the full block gas used. + app.ModuleManager.SetOrderEndBlockers( + govtypes.ModuleName, stakingtypes.ModuleName, + capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, + + // evmOS EndBlockers + evmtypes.ModuleName, erc20types.ModuleName, feemarkettypes.ModuleName, + + // no-ops + ibcexported.ModuleName, ibctransfertypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, minttypes.ModuleName, + genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, + feegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, consensusparamtypes.ModuleName, + ) + + // NOTE: The genutils module must occur after staking so that pools are + // properly initialized with tokens from genesis accounts. + // NOTE: The genutils module must also occur after auth so that it can access the params from auth. + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. + genesisModuleOrder := []string{ + capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, + distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, + minttypes.ModuleName, + ibcexported.ModuleName, + + // evmOS modules + // + // NOTE: feemarket module needs to be initialized before genutil module: + // gentx transactions use MinGasPriceDecorator.AnteHandle + evmtypes.ModuleName, + feemarkettypes.ModuleName, + erc20types.ModuleName, + + ibctransfertypes.ModuleName, + genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, + feegrant.ModuleName, upgradetypes.ModuleName, + assettypes.ModuleName, + } + app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) + app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) + + // Uncomment if you want to set a custom migration order here. + // app.ModuleManager.SetOrderMigrations(custom order) + + app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + if err = app.ModuleManager.RegisterServices(app.configurator); err != nil { + panic(fmt.Sprintf("failed to register services in module manager: %s", err.Error())) + } + + // RegisterUpgradeHandlers is used for registering any on-chain upgrades. + // Make sure it's called after `app.ModuleManager` and `app.configurator` are set. + app.RegisterUpgradeHandlers() + + autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.ModuleManager.Modules)) + + reflectionSvc, err := runtimeservices.NewReflectionService() + if err != nil { + panic(err) + } + reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc) + + // add test gRPC service for testing gRPC queries in isolation + testdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{}) + + // create the simulation manager and define the order of the modules for deterministic simulations + // + // NOTE: this is not required apps that don't use the simulator for fuzz testing + // transactions + overrideModules := map[string]module.AppModuleSimulation{ + authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + } + app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) + + app.sm.RegisterStoreDecoders() + + // initialize stores + app.MountKVStores(keys) + app.MountTransientStores(tkeys) + app.MountMemoryStores(memKeys) + + maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)) + + // initialize BaseApp + app.SetInitChainer(app.InitChainer) + app.SetPreBlocker(app.PreBlocker) + app.SetBeginBlocker(app.BeginBlocker) + app.SetEndBlocker(app.EndBlocker) + + app.setAnteHandler(app.txConfig, maxGasWanted) + + // In v0.46, the SDK introduces _postHandlers_. PostHandlers are like + // antehandlers, but are run _after_ the `runMsgs` execution. They are also + // defined as a chain, and have the same signature as antehandlers. + // + // In baseapp, postHandlers are run in the same store branch as `runMsgs`, + // meaning that both `runMsgs` and `postHandler` state will be committed if + // both are successful, and both will be reverted if any of the two fails. + // + // The SDK exposes a default postHandlers chain, which comprises of only + // one decorator: the Transaction Tips decorator. However, some chains do + // not need it by default, so feel free to comment the next line if you do + // not need tips. + // To read more about tips: + // https://docs.cosmos.network/main/core/tips.html + // + // Please note that changing any of the anteHandler or postHandler chain is + // likely to be a state-machine breaking change, which needs a coordinated + // upgrade. + app.setPostHandler() + + // At startup, after all modules have been registered, check that all prot + // annotations are correct. + protoFiles, err := proto.MergedRegistry() + if err != nil { + panic(err) + } + err = msgservice.ValidateProtoAnnotations(protoFiles) + if err != nil { + // TODO: Once we switch to using protoreflect-based antehandlers, we might + // want to panic here instead of logging a warning. + fmt.Fprintln(os.Stderr, err.Error()) + } + + if loadLatest { + if err := app.LoadLatestVersion(); err != nil { + logger.Error("error on loading last version", "err", err) + os.Exit(1) + } + } + + return app +} + +func (app *ExampleChain) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) { + options := chainante.HandlerOptions{ + Cdc: app.appCodec, + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + ExtensionOptionChecker: evmostypes.HasDynamicFeeExtensionOption, + EvmKeeper: app.EVMKeeper, + FeegrantKeeper: app.FeeGrantKeeper, + IBCKeeper: app.IBCKeeper, + FeeMarketKeeper: app.FeeMarketKeeper, + SignModeHandler: txConfig.SignModeHandler(), + SigGasConsumer: evmosante.SigVerificationGasConsumer, + MaxTxGasWanted: maxGasWanted, + TxFeeChecker: evmosevmante.NewDynamicFeeChecker(app.FeeMarketKeeper), + } + if err := options.Validate(); err != nil { + panic(err) + } + + app.SetAnteHandler(chainante.NewAnteHandler(options)) +} + +func (app *ExampleChain) setPostHandler() { + postHandler, err := posthandler.NewPostHandler( + posthandler.HandlerOptions{}, + ) + if err != nil { + panic(err) + } + + app.SetPostHandler(postHandler) +} + +// Name returns the name of the App +func (app *ExampleChain) Name() string { return app.BaseApp.Name() } + +// BeginBlocker application updates every begin block +func (app *ExampleChain) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) { + return app.ModuleManager.BeginBlock(ctx) +} + +// EndBlocker application updates every end block +func (app *ExampleChain) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) { + return app.ModuleManager.EndBlock(ctx) +} + +func (app *ExampleChain) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.ResponseFinalizeBlock, err error) { + return app.BaseApp.FinalizeBlock(req) +} + +func (a *ExampleChain) Configurator() module.Configurator { + return a.configurator +} + +// InitChainer application update at chain initialization +func (app *ExampleChain) InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { + var genesisState evmostypes.GenesisState + if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { + panic(err) + } + + if err := app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()); err != nil { + panic(err) + } + + return app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState) +} + +func (app *ExampleChain) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { + return app.ModuleManager.PreBlock(ctx) +} + +// LoadHeight loads a particular height +func (app *ExampleChain) LoadHeight(height int64) error { + return app.LoadVersion(height) +} + +// LegacyAmino returns ExampleChain's amino codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *ExampleChain) LegacyAmino() *codec.LegacyAmino { + return app.legacyAmino +} + +// AppCodec returns ExampleChain's app codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *ExampleChain) AppCodec() codec.Codec { + return app.appCodec +} + +// InterfaceRegistry returns ExampleChain's InterfaceRegistry +func (app *ExampleChain) InterfaceRegistry() types.InterfaceRegistry { + return app.interfaceRegistry +} + +// TxConfig returns ExampleChain's TxConfig +func (app *ExampleChain) TxConfig() client.TxConfig { + return app.txConfig +} + +// DefaultGenesis returns a default genesis from the registered AppModuleBasic's. +// +// TODO: change all receivers to osApp +func (a *ExampleChain) DefaultGenesis() map[string]json.RawMessage { + genesis := a.BasicModuleManager.DefaultGenesis(a.appCodec) + + mintGenState := NewMintGenesisState() + genesis[minttypes.ModuleName] = a.appCodec.MustMarshalJSON(mintGenState) + + evmGenState := NewEVMGenesisState() + genesis[evmtypes.ModuleName] = a.appCodec.MustMarshalJSON(evmGenState) + + // NOTE: for the example chain implementation we are also adding a default token pair, + // which is the base denomination of the chain (i.e. the WEVMOS contract) + erc20GenState := NewErc20GenesisState() + genesis[erc20types.ModuleName] = a.appCodec.MustMarshalJSON(erc20GenState) + + assetGenState := NewAssetGenesisState() + genesis[assettypes.ModuleName] = a.appCodec.MustMarshalJSON(assetGenState) + + return genesis +} + +// GetKey returns the KVStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *ExampleChain) GetKey(storeKey string) *storetypes.KVStoreKey { + return app.keys[storeKey] +} + +// GetTKey returns the TransientStoreKey for the provided store key. +// +// NOTE: This is solely to be used for testing purposes. +func (app *ExampleChain) GetTKey(storeKey string) *storetypes.TransientStoreKey { + return app.tkeys[storeKey] +} + +// GetMemKey returns the MemStoreKey for the provided mem key. +// +// NOTE: This is solely used for testing purposes. +func (app *ExampleChain) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { + return app.memKeys[storeKey] +} + +// GetSubspace returns a param subspace for a given module name. +// +// NOTE: This is solely to be used for testing purposes. +func (app *ExampleChain) GetSubspace(moduleName string) paramstypes.Subspace { + subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) + return subspace +} + +// SimulationManager implements the SimulationApp interface +func (app *ExampleChain) SimulationManager() *module.SimulationManager { + return app.sm +} + +// RegisterAPIRoutes registers all application module routes with the provided +// API server. +func (app *ExampleChain) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { + clientCtx := apiSvr.ClientCtx + // Register new tx routes from grpc-gateway. + authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register new tendermint queries routes from grpc-gateway. + cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register node gRPC service for grpc-gateway. + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // Register grpc-gateway routes for all modules. + app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + + // register swagger API from root so that other applications can override easily + if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { + panic(err) + } +} + +// RegisterTxService implements the Application.RegisterTxService method. +func (app *ExampleChain) RegisterTxService(clientCtx client.Context) { + authtx.RegisterTxService(app.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) +} + +// RegisterTendermintService implements the Application.RegisterTendermintService method. +func (app *ExampleChain) RegisterTendermintService(clientCtx client.Context) { + cmtservice.RegisterTendermintService( + clientCtx, + app.BaseApp.GRPCQueryRouter(), + app.interfaceRegistry, + app.Query, + ) +} + +func (app *ExampleChain) RegisterNodeService(clientCtx client.Context, cfg config.Config) { + node.RegisterNodeService(clientCtx, app.GRPCQueryRouter(), cfg) +} + +// --------------------------------------------- +// IBC Go TestingApp functions +// + +// GetBaseApp implements the TestingApp interface. +func (app *ExampleChain) GetBaseApp() *baseapp.BaseApp { + return app.BaseApp +} + +// GetStakingKeeper implements the TestingApp interface. +func (app *ExampleChain) GetStakingKeeper() ibctestingtypes.StakingKeeper { + return app.StakingKeeper +} + +// GetStakingKeeperSDK implements the TestingApp interface. +func (app *ExampleChain) GetStakingKeeperSDK() stakingkeeper.Keeper { + return *app.StakingKeeper +} + +// GetIBCKeeper implements the TestingApp interface. +func (app *ExampleChain) GetIBCKeeper() *ibckeeper.Keeper { + return app.IBCKeeper +} + +// GetScopedIBCKeeper implements the TestingApp interface. +func (app *ExampleChain) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { + return app.scopedIBCKeeper +} + +// GetTxConfig implements the TestingApp interface. +func (app *ExampleChain) GetTxConfig() client.TxConfig { + return app.txConfig +} + +// AutoCliOpts returns the autocli options for the app. +func (app *ExampleChain) AutoCliOpts() autocli.AppOptions { + modules := make(map[string]appmodule.AppModule, 0) + for _, m := range app.ModuleManager.Modules { + if moduleWithName, ok := m.(module.HasName); ok { + moduleName := moduleWithName.Name() + if appModule, ok := moduleWithName.(appmodule.AppModule); ok { + modules[moduleName] = appModule + } + } + } + + return autocli.AppOptions{ + Modules: modules, + ModuleOptions: runtimeservices.ExtractAutoCLIOptions(app.ModuleManager.Modules), + AddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), + ValidatorAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), + ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), + } +} + +// GetMaccPerms returns a copy of the module account permissions +func GetMaccPerms() map[string][]string { + return maps.Clone(maccPerms) +} + +// BlockedAddresses returns all the app's blocked account addresses. +// +// Note, this includes: +// - module accounts +// - Ethereum's native precompiled smart contracts +// - evmOS' available static precompiled contracts +func BlockedAddresses() map[string]bool { + blockedAddrs := make(map[string]bool) + + maccPerms := GetMaccPerms() + accs := make([]string, 0, len(maccPerms)) + for acc := range maccPerms { + accs = append(accs, acc) + } + sort.Strings(accs) + + for _, acc := range accs { + blockedAddrs[authtypes.NewModuleAddress(acc).String()] = true + } + + blockedPrecompilesHex := evmtypes.AvailableStaticPrecompiles + for _, addr := range vm.PrecompiledAddressesBerlin { + blockedPrecompilesHex = append(blockedPrecompilesHex, addr.Hex()) + } + + for _, precompile := range blockedPrecompilesHex { + blockedAddrs[evmosutils.EthHexToCosmosAddr(precompile).String()] = true + } + + return blockedAddrs +} + +// initParamsKeeper init params keeper and its subspaces +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { + paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) + + paramsKeeper.Subspace(authtypes.ModuleName) + paramsKeeper.Subspace(banktypes.ModuleName) + paramsKeeper.Subspace(stakingtypes.ModuleName) + paramsKeeper.Subspace(minttypes.ModuleName) + paramsKeeper.Subspace(distrtypes.ModuleName) + paramsKeeper.Subspace(slashingtypes.ModuleName) + paramsKeeper.Subspace(govtypes.ModuleName) + + // ibc modules + keyTable := ibcclienttypes.ParamKeyTable() + keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) + paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) + paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) + // TODO: do we need a keytable? copied from Evmos repo + + // evmOS modules + paramsKeeper.Subspace(evmtypes.ModuleName) + paramsKeeper.Subspace(feemarkettypes.ModuleName) + paramsKeeper.Subspace(erc20types.ModuleName) + + return paramsKeeper +} diff --git a/example_chain/config.go b/example_chain/config.go new file mode 100644 index 00000000..dd857ddd --- /dev/null +++ b/example_chain/config.go @@ -0,0 +1,90 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +//go:build !test +// +build !test + +package example_chain + +import ( + "fmt" + "strings" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// EvmosOptionsFn defines a function type for setting app options specifically for +// the Evmos app. The function should receive the chainID and return an error if +// any. +type EvmosOptionsFn func(string) error + +// NoOpEvmosOptions is a no-op function that can be used when the app does not +// need any specific configuration. +func NoOpEvmosOptions(_ string) error { + return nil +} + +var sealed = false + +// ChainsCoinInfo is a map of the chain id and its corresponding EvmCoinInfo +// that allows initializing the app with different coin info based on the +// chain id +var ChainsCoinInfo = map[string]evmtypes.EvmCoinInfo{ + EighteenDecimalsChainID: { + Denom: ExampleChainDenom, + DisplayDenom: ExampleDisplayDenom, + Decimals: evmtypes.EighteenDecimals, + }, +} + +// EvmosAppOptions allows to setup the global configuration +// for the Evmos chain. +func EvmosAppOptions(chainID string) error { + if sealed { + return nil + } + + id := strings.Split(chainID, "-")[0] + coinInfo, found := ChainsCoinInfo[id] + if !found { + return fmt.Errorf("unknown chain id: %s", id) + } + + // set the denom info for the chain + if err := setBaseDenom(coinInfo); err != nil { + return err + } + + baseDenom, err := sdk.GetBaseDenom() + if err != nil { + return err + } + + ethCfg := evmtypes.DefaultChainConfig(chainID) + + err = evmtypes.NewEVMConfigurator(). + WithChainConfig(ethCfg). + // NOTE: we're using the 18 decimals default for the example chain + WithEVMCoinInfo(baseDenom, uint8(coinInfo.Decimals)). + Configure() + if err != nil { + return err + } + + sealed = true + return nil +} + +// setBaseDenom registers the display denom and base denom and sets the +// base denom for the chain. +func setBaseDenom(ci evmtypes.EvmCoinInfo) error { + if err := sdk.RegisterDenom(ci.DisplayDenom, math.LegacyOneDec()); err != nil { + return err + } + + // sdk.RegisterDenom will automatically overwrite the base denom when the + // new setBaseDenom() are lower than the current base denom's units. + return sdk.RegisterDenom(ci.Denom, math.LegacyNewDecWithPrec(1, int64(ci.Decimals))) +} diff --git a/example_chain/config_testing.go b/example_chain/config_testing.go new file mode 100644 index 00000000..20ff9faf --- /dev/null +++ b/example_chain/config_testing.go @@ -0,0 +1,100 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +//go:build test +// +build test + +package example_chain + +import ( + "fmt" + "strings" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + testconstants "github.com/evmos/os/testutil/constants" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// ChainsCoinInfo is a map of the chain id and its corresponding EvmCoinInfo +// that allows initializing the app with different coin info based on the +// chain id +var ChainsCoinInfo = map[string]evmtypes.EvmCoinInfo{ + EighteenDecimalsChainID: { + Denom: ExampleChainDenom, + DisplayDenom: ExampleChainDenom, + Decimals: evmtypes.EighteenDecimals, + }, + SixDecimalsChainID: { + Denom: testconstants.ExampleMicroDenom, + DisplayDenom: testconstants.ExampleDisplayDenom, + Decimals: evmtypes.SixDecimals, + }, +} + +// EvmosOptionsFn defines a function type for setting app options specifically for +// the Evmos app. The function should receive the chainID and return an error if +// any. +type EvmosOptionsFn func(string) error + +// NoOpEvmosOptions is a no-op function that can be used when the app does not +// need any specific configuration. +func NoOpEvmosOptions(_ string) error { + return nil +} + +// EvmosAppOptions allows to setup the global configuration +// for the Evmos chain. +func EvmosAppOptions(chainID string) error { + // Split the revision height from the given chain ID + id := strings.Split(chainID, "-")[0] + coinInfo, found := ChainsCoinInfo[id] + if !found { + return fmt.Errorf("unknown chain id: %s", id) + } + + // set the base denom considering if its mainnet or testnet + if err := setBaseDenom(coinInfo); err != nil { + return err + } + + baseDenom, err := sdk.GetBaseDenom() + if err != nil { + return err + } + + ethCfg := evmtypes.DefaultChainConfig(chainID) + + configurator := evmtypes.NewEVMConfigurator() + // reset configuration to set the new one + configurator.ResetTestConfig() + err = configurator. + WithExtendedEips(evmosActivators). + WithChainConfig(ethCfg). + WithEVMCoinInfo(baseDenom, uint8(coinInfo.Decimals)). + Configure() + if err != nil { + return err + } + + return nil +} + +// setBaseDenom registers the display denom and base denom and sets the +// base denom for the chain. The function registered different values based on +// the EvmCoinInfo to allow different configurations in mainnet and testnet. +func setBaseDenom(ci evmtypes.EvmCoinInfo) (err error) { + // Defer setting the base denom, and capture any potential error from it. + // So when failing because the denom was already registered, we ignore it and set + // the corresponding denom to be base denom + defer func() { + err = sdk.SetBaseDenom(ci.Denom) + }() + if err := sdk.RegisterDenom(ci.DisplayDenom, math.LegacyOneDec()); err != nil { + return err + } + + // sdk.RegisterDenom will automatically overwrite the base denom when the + // new setBaseDenom() units are lower than the current base denom's units. + return sdk.RegisterDenom(ci.Denom, math.LegacyNewDecWithPrec(1, int64(ci.Decimals))) +} diff --git a/example_chain/constants.go b/example_chain/constants.go new file mode 100644 index 00000000..037a5c07 --- /dev/null +++ b/example_chain/constants.go @@ -0,0 +1,18 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +const ( + // ExampleChainDenom is the denomination of the evmOS example chain's base coin. + ExampleChainDenom = "aevmos" + + // ExampleDisplayDenom is the display denomination of the evmOS example chain's base coin. + ExampleDisplayDenom = "evmos" + + // EighteenDecimalsChainID is the chain ID for the 18 decimals chain. + EighteenDecimalsChainID = "os_9001" + + // SixDecimalsChainID is the chain ID for the 6 decimals chain. + SixDecimalsChainID = "ossix_9002" +) diff --git a/example_chain/eips/README.md b/example_chain/eips/README.md new file mode 100644 index 00000000..18c1f4ef --- /dev/null +++ b/example_chain/eips/README.md @@ -0,0 +1,258 @@ +# Evmos Custom EIPs + +This document explain how **evmOS** allows chain built on top of it to define custom EIPs to modify the behavior of EVM +opcodes. + +## Custom EIPs + +Inside an EVM, every state transition or query is executed by evaluating opcodes. Custom EIPs are functions used to +change the behavior of these opcodes to tailor the EVM functionalities to fit the app-chain requirements. + +Custom EIPs should be defined in an `eips` package inside the `./app/eips/` folder of chains using the **evmOS** +framework. This organization of custom implementations is not a strict requirement, but is the suggested approach to +have a clean organization of functionalities. In this file, only the custom modifier should be defined. + +Inside this package, custom EIP should be defined in a file called `eips.go`. In this file, the EIPs modifier should be +defined with the signature: + +```go +func(jt *vm.JumpTable) {} +``` + +where `vm` is the package `"github.com/evmos/os/x/evm/core/vm"`. + +Custom EIPs are used to modify the behavior of opcodes, which are described by the `operation` structure: + +```go +type operation struct { + // execute is the operation function + execute executionFunc + constantGas uint64 + dynamicGas gasFunc + // minStack tells how many stack items are required + minStack int + // maxStack specifies the max length the stack can have for this operation + // to not overflow the stack. + maxStack int + + // memorySize returns the memory size required for the operation + memorySize memorySizeFunc +} +``` + +With the **evmOS** framework, it is possible to modify any of the fields defined in the type via the `operation` setter +methods: + +- `SetExecute`: update the execution logic for the opcode. + +- `SetConstantGas`: update the value used for the constant gas cost. + +- `SetDynamicGas`: update the function used to compute the dynamic gas cost. + +- `SetMinStack`: update the minimum number of items in the stack required to execute the `operation`. + +- `SetMaxStack`: update the maximum number of items that will be in the stack after executing the `operation`. + +- `SetMemorySize`: the memory size required by the `operation`. + +An example for an EIP which modifies the constant gas used for the `CREATE` opcode is reported below: + +```go +// Enable a custom EIP-0000 +func Enable0000(jt *vm.JumpTable) { + jt[vm.CREATE].SetConstantGas(1) +} +``` + +In the same folder should also be defined tests and contracts used to verify the EIPs logic. + +## Activate Custom EIPs + +The activation of custom EIPs should be done inside the `config.go` file defined in the `./app/` folder. This file has +the role of the single source for modify the EVM implementation which is defined in the +[`x/evm/`](https://github.com/evmos/os/tree/main/x/evm) folder +of **evmOS**. + +In this file, 3 main components should be defined: + +- The custom EIPs, also called activators. +- The additional default EIPs enabled. +- The EVM configurator instance. + +All these components will be described in the following sections. + +### Opcode & EIP Activators + +Activators is the name provided by [Go-ethereum](https://geth.ethereum.org/) to the definition of the structure +grouping all possible non-default EIPs: + +```go +var activators = map[int]func(*JumpTable){ + 3855: enable3855, + ... +} +``` + +It can be interpreted as a list of available functionalities that can be toggled to change opcodes behavior. The +structure is a map where the key is the EIP number in the octal representation, and the value is the custom EIP +function that has to be evaluated. + +In **evmOS**, custom activators should be defined in a structure with the same data type, like in the example below: + +```go +// Activate custom EIPs: 0000, 0001, 0002, etc +evmosActivators = map[int]func(*vm.JumpTable){ + "evmos_0": eips.Enable0000, + "evmos_1": eips.Enable0001, + "evmos_2": eips.Enable0002, +} +``` + +It should be noted that the value of each key in the example is the modifier defined in the `eips` package in the +example provided at the of the [Custom EIPs](#custom-eips) section. + +### Default EIPs + +Custom EIPs defined in the `activators` map are not enabled by default. This type is only used to define the list of +custom functionalities that can be activated. To specify which custom EIP activate, we should modify the +**evmOS** `x/evm` module params. The parameter orchestrating enabled custom EIPs is the `DefaultExtraEIPs` and +**evmOS** provide an easy and safe way to customize it. + +To specify which activator enable in the chain, a new variable containing a slice of keys of the custom activators +should be defined. An example is reported below: + +```go +evmosEnabledEIPs = []int64{ + "evmos_0", +} +``` + +In this way, even though the custom activators defined $3$ new EIPs, we are going to activate only the number `evmos_0` + +### EVM Configurator + +The EVM configuration is the type used to modify the EVM configuration before starting a node. The type is defined as: + +```go +type EVMConfigurator struct { + extendedEIPs map[int]func(*vm.JumpTable) + extendedDefaultExtraEIPs []int64 + sealed bool +} +``` + +Currently, only 2 customizations are possible: + +- `WithExtendedEips`: extended the default available EIPs. + +- `WithExtendedDefaultExtraEIPs`: extended the default active EIPs. + +It is important to notice that the configurator will only allow to append new entries to the default ones defined by +**evmOS**. The reason behind this choice is to ensure the correct and safe execution of the virtual machine but still +allowing partners to customize their implementation. + +The `EVMConfigurator` type should be constructed using the builder pattern inside the `init()` function of the file so +that it is run during the creation of the application. + +An example of the usage of the configurator is reported below: + +```go +configurator := evmconfig.NewEVMConfigurator(). + WithExtendedEips(customActivators). + WithExtendedDefaultExtraEIPs(defaultEnabledEIPs...). + Configure() + +err := configurator.Configure() +``` + +Errors are raised when the configurator tries to append an item with the same name of one of the default one. Since +this type is used to configure the EVM before starting the node, it is safe, and suggested, to panic: + +```go +if err != nil { + panic(err) +} +``` + +## Custom EIPs Deep Dive + +When the chain receives an EVM transaction, it is handled by the `MsgServer` of the `x/evm` within the method +`EthereumTx`. The method then calls `ApplyTransaction` where the EVM configuration is created: + +```go +cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID) +``` + +During the creation of this type, a query is made to retrieve the `x/evm` params. After this step, the request is +passed inside the `ApplyMessageWithConfig` where a new instance of the EVM is created: + +```go +evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB) +``` + +The `NewEVM` method calls the `NewEVMWithHooks` where a new instance of the virtual machine interpreter is created: + +```go +evm.interpreter = NewEVMInterpreter(evm, config) +``` + +The management of activators is handled in this function: + +```go +func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { + // If jump table was not initialised we set the default one. + if cfg.JumpTable == nil { + cfg.JumpTable = DefaultJumpTable(evm.chainRules) + for i, eip := range cfg.ExtraEips { + // Deep-copy jumptable to prevent modification of opcodes in other tables + copy := CopyJumpTable(cfg.JumpTable) + if err := EnableEIP(eip, copy); err != nil { + // Disable it, so caller can check if it's activated or not + cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) + log.Error("EIP activation failed", "eip", eip, "error", err) + } + cfg.JumpTable = copy + } + } + + return &EVMInterpreter{ + evm: evm, + cfg: cfg, + } +} +``` + +As we can see, a new `JumpTable` is created if it is not received from previous evm executions in the same transaction. +After that, the function iterate over the `ExtraEips` defined in the configuration. Then, it is checked if the EIP is +associated with an activator. If yes, the activator function is execute, otherwise an error is returned and the EIP is +removed from the VM configuration. At this point, all the opcodes are ready to be executed. + +## How to Use It + +In previous sections has been described required structures and files to use the EVM configurator to enable custom +EIPs. In this the general procedure is taken into considerations. Two different scenarios are described: + +- New chain. + +- Running chain. + +### New Chain + +For a new chain starting from block genesis, the procedure described in the sections above is enough. To summarize it: + +- Create the eip file with custom activators. + +- Create the config file with custom activators, default EIPs, and the configurator. + +After starting the chain, the genesis validation will perform all the required checks and the chain will be ready using +the new custom EIPs. + +### Running Chain + +The proper approach to include and enable new EIPs, with the current state of the development, is via coordinate chain +upgrade. During the chain upgrade it is important to define the custom activators since they are not stored in the +chain. To enable them there are two possibilities: + +- Write a migration to add the new enabled EIPsm during the upgrade. + +- After the upgrade, create a governance proposal to modify the `x/evm` params. diff --git a/example_chain/eips/eips.go b/example_chain/eips/eips.go new file mode 100644 index 00000000..2c309414 --- /dev/null +++ b/example_chain/eips/eips.go @@ -0,0 +1,36 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package eips + +import ( + "github.com/evmos/os/x/evm/core/vm" +) + +var ( + Multiplier = uint64(10) + SstoreConstantGas = uint64(500) +) + +// enable0000 contains the logic to modify the CREATE and CREATE2 opcodes +// constant gas value. +func Enable0000(jt *vm.JumpTable) { + currentValCreate := jt[vm.CREATE].GetConstantGas() + jt[vm.CREATE].SetConstantGas(currentValCreate * Multiplier) + + currentValCreate2 := jt[vm.CREATE2].GetConstantGas() + jt[vm.CREATE2].SetConstantGas(currentValCreate2 * Multiplier) +} + +// enable0001 contains the logic to modify the CALL opcode +// constant gas value. +func Enable0001(jt *vm.JumpTable) { + currentVal := jt[vm.CALL].GetConstantGas() + jt[vm.CALL].SetConstantGas(currentVal * Multiplier) +} + +// enable0002 contains the logic to modify the SSTORE opcode +// constant gas value. +func Enable0002(jt *vm.JumpTable) { + jt[vm.SSTORE].SetConstantGas(SstoreConstantGas) +} diff --git a/example_chain/eips/eips_test.go b/example_chain/eips/eips_test.go new file mode 100644 index 00000000..80ad7357 --- /dev/null +++ b/example_chain/eips/eips_test.go @@ -0,0 +1,441 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package eips_test + +import ( + "fmt" + "math/big" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/example_chain/eips" + "github.com/evmos/os/example_chain/eips/testdata" + "github.com/evmos/os/testutil/integration/os/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/evmos/os/testutil/integration/os/keyring" + integrationutils "github.com/evmos/os/testutil/integration/os/utils" + "github.com/realiotech/realio-network/testutil/integration/os/network" + + evmtypes "github.com/evmos/os/x/evm/types" + + "github.com/ethereum/go-ethereum/params" + + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/ginkgo/v2" + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/gomega" +) + +// Below tests are divided in 3 steps: +// 1. Deploy and interact with contracts to compute the gas used BEFORE enabling +// the IP. +// 2. Activate the IP under test. +// 3. Deploy and interact with contracts to compute the gas used AFTER enabling +// the IP. + +func TestIPs(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "EvmosIPs Suite") +} + +var _ = Describe("Improvement proposal evmos_0 - ", Ordered, func() { + var ( + in network.Network + tf factory.TxFactory + gh grpc.Handler + k keyring.Keyring + + senderPriv types.PrivKey + senderPriv2 types.PrivKey + senderAddr2 common.Address + + // Gas used before enabling the IP. + gasUsedPre int64 + ) + + // Multiplier used to modify the opcodes associated with evmos_0 IP. + ipMultiplier := uint64(5) + + // The factory counter is used because it will create a new instance of + // the counter contract, allowing to test the CREATE opcode. + counterFactoryContract, err := testdata.LoadCounterFactoryContract() + Expect(err).ToNot(HaveOccurred(), "failed to load Counter Factory contract") + + deploymentData := factory.ContractDeploymentData{ + Contract: counterFactoryContract, + ConstructorArgs: []interface{}{}, + } + + BeforeAll(func() { + k = keyring.New(2) + in = network.New( + network.WithPreFundedAccounts(k.GetAllAccAddrs()...), + ) + gh = grpc.NewIntegrationHandler(in) + tf = factory.New(in, gh) + + // Account used to deploy the contract before enabling the IP. + senderPriv = k.GetPrivKey(0) + // Account used to deploy the contract after enabling the IP. A second + // account is used to avoid possible additional gas costs due to the change + // in the Nonce. + senderPriv2 = k.GetPrivKey(1) + senderAddr2 = k.GetAddr(1) + + // Set extra IPs to empty to allow testing a single modifier. + defaultParams := evmtypes.DefaultParams() + defaultParams.ExtraEIPs = []string{} + + err := integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: defaultParams, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + Expect(in.NextBlock()).To(BeNil()) + }) + + It("should deploy the contract before enabling the IP", func() { + deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) + Expect(err).To(BeNil(), "failed to create deployment tx args") + + res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) + Expect(err).To(BeNil(), "failed during contract deployment") + gasUsedPre = res.GasUsed + }) + + It("should enable the new IP", func() { + eips.Multiplier = ipMultiplier + newIP := "evmos_0" + + qRes, err := gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) + err = integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: qRes.Params, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + + Expect(in.NextBlock()).To(BeNil()) + + qRes, err = gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have IP evmos_0 in evm params") + }) + + It("should change CREATE opcode constant gas after enabling evmos_0 IP", func() { + gasCostPre := params.CreateGas + + deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) + Expect(err).To(BeNil(), "failed to create deployment tx args") + + res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) + Expect(err).To(BeNil(), "failed during contract deployment") + // commit block to update sender nonce + Expect(in.NextBlock()).To(BeNil()) + + gasUsedPost := res.GasUsed + + // The difference in gas is the new cost of the opcode, minus the cost of the + // opcode before enabling the new eip. + gasUsedDiff := ipMultiplier*gasCostPre - gasCostPre + expectedGas := gasUsedPre + int64(gasUsedDiff) + Expect(gasUsedPost).To(Equal(expectedGas)) + }) +}) + +var _ = Describe("Improvement proposal evmos_1 - ", Ordered, func() { + var ( + in network.Network + tf factory.TxFactory + gh grpc.Handler + k keyring.Keyring + + senderPriv types.PrivKey + + // Gas used before enabling the IP. + gasUsedPre int64 + + // The address of the factory counter. + counterFactoryAddr common.Address + ) + + // Multiplier used to modify the opcodes associated with evmos_1. + eipMultiplier := uint64(5) + initialCounterValue := 1 + + // The counter factory contract is used to deploy a counter contract and + // perform state transition using the CALL opcode. + counterFactoryContract, err := testdata.LoadCounterFactoryContract() + Expect(err).ToNot(HaveOccurred(), "failed to load Counter Factory contract") + + BeforeAll(func() { + k = keyring.New(1) + in = network.New( + network.WithPreFundedAccounts(k.GetAllAccAddrs()...), + ) + gh = grpc.NewIntegrationHandler(in) + tf = factory.New(in, gh) + + senderPriv = k.GetPrivKey(0) + + // Set extra IPs to empty to allow testing a single modifier. + defaultParams := evmtypes.DefaultParams() + defaultParams.ExtraEIPs = []string{} + err = integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: defaultParams, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + + Expect(in.NextBlock()).To(BeNil()) + }) + + It("should deploy the contract before enabling the IP", func() { + counterFactoryAddr, err = tf.DeployContract( + senderPriv, + evmtypes.EvmTxArgs{}, + factory.ContractDeploymentData{ + Contract: counterFactoryContract, + ConstructorArgs: []interface{}{}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to deploy counter factory contract") + Expect(in.NextBlock()).To(BeNil()) + + res, err := tf.ExecuteContractCall( + senderPriv, + evmtypes.EvmTxArgs{To: &counterFactoryAddr}, + factory.CallArgs{ + ContractABI: counterFactoryContract.ABI, + MethodName: "incrementCounter", + Args: []interface{}{}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to increment counter value") + gasUsedPre = res.GasUsed + + Expect(in.NextBlock()).To(BeNil()) + + // Query the counter value to check proper state transition later. + res, err = tf.ExecuteContractCall( + senderPriv, + evmtypes.EvmTxArgs{To: &counterFactoryAddr}, + factory.CallArgs{ + ContractABI: counterFactoryContract.ABI, + MethodName: "getCounterValue", + Args: []interface{}{}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to get counter value") + Expect(in.NextBlock()).To(BeNil()) + + ethRes, err := evmtypes.DecodeTxResponse(res.Data) + Expect(err).ToNot(HaveOccurred(), "failed to decode tx response") + + unpacked, err := counterFactoryContract.ABI.Unpack( + "getCounterValue", + ethRes.Ret, + ) + Expect(err).ToNot(HaveOccurred(), "failed to unpack counter value") + + counter, ok := unpacked[0].(*big.Int) + Expect(ok).To(BeTrue(), "failed to convert counter to big.Int") + Expect(counter.String()).To(Equal(fmt.Sprintf("%d", initialCounterValue+1)), "counter is not correct") + }) + It("should enable the new IP", func() { + eips.Multiplier = eipMultiplier + newIP := "evmos_1" + + qRes, err := gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) + + err = integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: qRes.Params, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + + Expect(in.NextBlock()).To(BeNil()) + + qRes, err = gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have ip evmos_1 in evm params") + }) + It("should change CALL opcode constant gas after enabling IP", func() { + // Constant gas cost used before enabling the new IP. + gasCostPre := params.WarmStorageReadCostEIP2929 + + res, err := tf.ExecuteContractCall( + senderPriv, + evmtypes.EvmTxArgs{To: &counterFactoryAddr}, + factory.CallArgs{ + ContractABI: counterFactoryContract.ABI, + MethodName: "incrementCounter", + Args: []interface{}{}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to increment counter value") + gasUsedPost := res.GasUsed + Expect(in.NextBlock()).To(BeNil()) + + res, err = tf.ExecuteContractCall( + senderPriv, + evmtypes.EvmTxArgs{To: &counterFactoryAddr}, + factory.CallArgs{ + ContractABI: counterFactoryContract.ABI, + MethodName: "getCounterValue", + Args: []interface{}{}, + }, + ) + Expect(err).ToNot(HaveOccurred(), "failed to get counter value") + Expect(in.NextBlock()).To(BeNil()) + + ethRes, err := evmtypes.DecodeTxResponse(res.Data) + Expect(err).ToNot(HaveOccurred(), "failed to decode tx response") + + unpacked, err := counterFactoryContract.ABI.Unpack( + "getCounterValue", + ethRes.Ret, + ) + Expect(err).ToNot(HaveOccurred(), "failed to unpack counter value") + + counter, ok := unpacked[0].(*big.Int) + Expect(ok).To(BeTrue(), "failed to convert counter to big.Int") + Expect(counter.String()).To(Equal(fmt.Sprintf("%d", initialCounterValue+2)), "counter is not updated correctly") + + // The difference in gas is the new cost of the opcode, minus the cost of the + // opcode before enabling the new eip. + gasUsedDiff := eipMultiplier*gasCostPre - gasCostPre + expectedGas := gasUsedPre + int64(gasUsedDiff) + Expect(gasUsedPost).To(Equal(expectedGas)) + }) +}) + +var _ = Describe("Improvement proposal evmos_2 - ", Ordered, func() { + var ( + in network.Network + tf factory.TxFactory + gh grpc.Handler + k keyring.Keyring + + senderPriv types.PrivKey + senderAddr common.Address + senderPriv2 types.PrivKey + senderAddr2 common.Address + gasUsedPre int64 + ) + // Constant gas used to modify the opcodes associated with evmos_2. + constantGas := uint64(500) + + counterContract, err := testdata.LoadCounterContract() + Expect(err).ToNot(HaveOccurred(), "failed to load Counter contract") + + deploymentData := factory.ContractDeploymentData{ + Contract: counterContract, + ConstructorArgs: []interface{}{}, + } + BeforeAll(func() { + k = keyring.New(2) + in = network.New( + network.WithPreFundedAccounts(k.GetAllAccAddrs()...), + ) + gh = grpc.NewIntegrationHandler(in) + tf = factory.New(in, gh) + + // Account used to deploy the contract before enabling the IP. + senderPriv = k.GetPrivKey(0) + senderAddr = k.GetAddr(0) + // Account used to deploy the contract after enabling the IP. A second + // account is used to avoid possible additional gas costs due to the change + // in the Nonce. + senderPriv2 = k.GetPrivKey(0) + senderAddr2 = k.GetAddr(0) + + // Set extra IPs to empty to allow testing a single modifier. + defaultParams := evmtypes.DefaultParams() + defaultParams.ExtraEIPs = []string{} + + err = integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: defaultParams, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + + Expect(in.NextBlock()).To(BeNil()) + }) + + It("should deploy the contract before enabling the IP", func() { + deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr, evmtypes.EvmTxArgs{}, deploymentData) + Expect(err).To(BeNil(), "failed to create deployment tx args") + + res, err := tf.ExecuteEthTx(senderPriv, deploymentTxArgs) + Expect(err).To(BeNil(), "failed during contract deployment") + Expect(in.NextBlock()).To(BeNil()) + + gasUsedPre = res.GasUsed + }) + + It("should enable the new IP", func() { + eips.SstoreConstantGas = constantGas + newIP := "evmos_2" + + qRes, err := gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) + err = integrationutils.UpdateEvmParams( + integrationutils.UpdateParamsInput{ + Tf: tf, + Network: in, + Pk: senderPriv, + Params: qRes.Params, + }, + ) + Expect(err).To(BeNil(), "failed during update of evm params") + + Expect(in.NextBlock()).To(BeNil()) + + qRes, err = gh.GetEvmParams() + Expect(err).To(BeNil(), "failed during query to evm params") + Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have ip evmos_2 in evm params") + }) + + It("should change SSTORE opcode constant gas after enabling IP", func() { + deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) + Expect(err).To(BeNil(), "failed to create deployment tx args") + + res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) + Expect(err).To(BeNil(), "failed during contract deployment") + Expect(in.NextBlock()).To(BeNil()) + + gasUsedPost := res.GasUsed + + // The expected gas is previous gas plus the constant gas because + // previous this eip, SSTORE was using only the dynamic gas. + expectedGas := gasUsedPre + int64(constantGas) + Expect(gasUsedPost).To(Equal(expectedGas)) + }) +}) diff --git a/example_chain/eips/testdata/Counter.json b/example_chain/eips/testdata/Counter.json new file mode 100644 index 00000000..31819578 --- /dev/null +++ b/example_chain/eips/testdata/Counter.json @@ -0,0 +1,38 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "Counter", + "sourceName": "solidity/example_chain/eips/testdata/Counter.sol", + "abi": [ + { + "inputs": [], + "name": "counter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decrement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "increment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052600160005534801561001557600080fd5b506101ba806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/example_chain/eips/testdata/Counter.sol b/example_chain/eips/testdata/Counter.sol new file mode 100644 index 00000000..30ba0869 --- /dev/null +++ b/example_chain/eips/testdata/Counter.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +pragma solidity >=0.7.0 <0.9.0; + +contract Counter { + uint256 public counter = 1; + + function increment() external { + counter++; + } + + function decrement() external { + counter--; + } +} diff --git a/example_chain/eips/testdata/CounterFactory.json b/example_chain/eips/testdata/CounterFactory.json new file mode 100644 index 00000000..d3c9674d --- /dev/null +++ b/example_chain/eips/testdata/CounterFactory.json @@ -0,0 +1,56 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "Counterfactory", + "sourceName": "solidity/example_chain/eips/testdata/CounterFactory.sol", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "counterInstance", + "outputs": [ + { + "internalType": "contract Counter", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decrementCounter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCounterValue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "incrementCounter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b5060405161001d9061007e565b604051809103906000f080158015610039573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061008b565b6101df8061045c83390190565b6103c28061009a6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b9661461005157806372142b891461005b578063aef38e7214610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b610063610123565b6040516100709190610279565b60405180910390f35b6100816101ba565b60405161008e9190610313565b60405180910390f35b61009f6101de565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d09de08a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010957600080fd5b505af115801561011d573d6000803e3d6000fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166361bc221a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b5919061035f565b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632baeceb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561024657600080fd5b505af115801561025a573d6000803e3d6000fd5b50505050565b6000819050919050565b61027381610260565b82525050565b600060208201905061028e600083018461026a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102d96102d46102cf84610294565b6102b4565b610294565b9050919050565b60006102eb826102be565b9050919050565b60006102fd826102e0565b9050919050565b61030d816102f2565b82525050565b60006020820190506103286000830184610304565b92915050565b600080fd5b61033c81610260565b811461034757600080fd5b50565b60008151905061035981610333565b92915050565b6000602082840312156103755761037461032e565b5b60006103838482850161034a565b9150509291505056fea26469706673582212209247a66c2dbee615e99f0a204e17785fb9d8102833d627c3f5cc5f86d3d4793964736f6c634300081400336080604052600160005534801561001557600080fd5b506101ba806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b9661461005157806372142b891461005b578063aef38e7214610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b610063610123565b6040516100709190610279565b60405180910390f35b6100816101ba565b60405161008e9190610313565b60405180910390f35b61009f6101de565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d09de08a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010957600080fd5b505af115801561011d573d6000803e3d6000fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166361bc221a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b5919061035f565b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632baeceb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561024657600080fd5b505af115801561025a573d6000803e3d6000fd5b50505050565b6000819050919050565b61027381610260565b82525050565b600060208201905061028e600083018461026a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102d96102d46102cf84610294565b6102b4565b610294565b9050919050565b60006102eb826102be565b9050919050565b60006102fd826102e0565b9050919050565b61030d816102f2565b82525050565b60006020820190506103286000830184610304565b92915050565b600080fd5b61033c81610260565b811461034757600080fd5b50565b60008151905061035981610333565b92915050565b6000602082840312156103755761037461032e565b5b60006103838482850161034a565b9150509291505056fea26469706673582212209247a66c2dbee615e99f0a204e17785fb9d8102833d627c3f5cc5f86d3d4793964736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/example_chain/eips/testdata/CounterFactory.sol b/example_chain/eips/testdata/CounterFactory.sol new file mode 100644 index 00000000..7b64412d --- /dev/null +++ b/example_chain/eips/testdata/CounterFactory.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +pragma solidity >=0.7.0 <0.9.0; + +import "./Counter.sol"; + +contract Counterfactory { + Counter public counterInstance; + + constructor() { + counterInstance = new Counter(); + } + + function incrementCounter() public { + counterInstance.increment(); + } + + function decrementCounter() public { + counterInstance.decrement(); + } + + function getCounterValue() public view returns (uint256) { + return counterInstance.counter(); + } +} diff --git a/example_chain/eips/testdata/contracts.go b/example_chain/eips/testdata/contracts.go new file mode 100644 index 00000000..2d336b52 --- /dev/null +++ b/example_chain/eips/testdata/contracts.go @@ -0,0 +1,17 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testdata + +import ( + contractutils "github.com/evmos/os/contracts/utils" + evmtypes "github.com/evmos/os/x/evm/types" +) + +func LoadCounterContract() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("Counter.json") +} + +func LoadCounterFactoryContract() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("CounterFactory.json") +} diff --git a/example_chain/export.go b/example_chain/export.go new file mode 100644 index 00000000..c13aaf38 --- /dev/null +++ b/example_chain/export.go @@ -0,0 +1,254 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import ( + "encoding/json" + "fmt" + "log" + + storetypes "cosmossdk.io/store/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// ExportAppStateAndValidators exports the state of the application for a genesis +// file. +func (app *ExampleChain) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs []string, modulesToExport []string) (servertypes.ExportedApp, error) { + // as if they could withdraw from the start of the next block + ctx := app.NewContextLegacy(true, tmproto.Header{Height: app.LastBlockHeight()}) + + // We export at last height + 1, because that's the height at which + // Tendermint will start InitChain. + height := app.LastBlockHeight() + 1 + if forZeroHeight { + height = 0 + if err := app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs); err != nil { + return servertypes.ExportedApp{}, err + } + } + + genState, err := app.ModuleManager.ExportGenesisForModules(ctx, app.appCodec, modulesToExport) + if err != nil { + return servertypes.ExportedApp{}, err + } + + appState, err := json.MarshalIndent(genState, "", " ") + if err != nil { + return servertypes.ExportedApp{}, err + } + + validators, err := staking.WriteValidators(ctx, app.StakingKeeper) + return servertypes.ExportedApp{ + AppState: appState, + Validators: validators, + Height: height, + ConsensusParams: app.BaseApp.GetConsensusParams(ctx), + }, err +} + +// prepare for fresh start at zero height +// NOTE zero height genesis is a temporary feature which will be deprecated +// +// in favour of export at a block height +func (app *ExampleChain) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) error { + applyAllowedAddrs := false + + // check if there is a allowed address list + if len(jailAllowedAddrs) > 0 { + applyAllowedAddrs = true + } + + allowedAddrsMap := make(map[string]bool) + + for _, addr := range jailAllowedAddrs { + _, err := sdk.ValAddressFromBech32(addr) + if err != nil { + log.Fatal(err) + } + allowedAddrsMap[addr] = true + } + + /* Handle fee distribution state. */ + + // withdraw all validator commission + if err := app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, sdk.ValAddress(val.GetOperator())) + return false + }); err != nil { + return err + } + + // withdraw all delegator rewards + dels, err := app.StakingKeeper.GetAllDelegations(ctx) + if err != nil { + return err + } + + for _, delegation := range dels { + valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) + if err != nil { + panic(err) + } + + delAddr := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress) + + _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr) + } + + // clear validator slash events + app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx) + + // clear validator historical rewards + app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) + + // set context height to zero + height := ctx.BlockHeight() + ctx = ctx.WithBlockHeight(0) + + // reinitialize all validators + err = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + // donate any unwithdrawn outstanding reward fraction tokens to the community pool + scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, sdk.ValAddress(val.GetOperator())) + if err != nil { + return true + } + feePool, err := app.DistrKeeper.FeePool.Get(ctx) + if err != nil { + return true + } + feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) + err = app.DistrKeeper.FeePool.Set(ctx, feePool) + if err != nil { + return true + } + + err = app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, sdk.ValAddress(val.GetOperator())) + // this lets us stop in case there's an error + return err != nil + }) + if err != nil { + return err + } + + // reinitialize all delegations + for _, del := range dels { + valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress) + if err != nil { + panic(err) + } + delAddr := sdk.MustAccAddressFromBech32(del.DelegatorAddress) + + if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil { + // never called as BeforeDelegationCreated always returns nil + panic(fmt.Errorf("error while incrementing period: %w", err)) + } + + if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil { + // never called as AfterDelegationModified always returns nil + panic(fmt.Errorf("error while creating a new delegation period record: %w", err)) + } + } + + // reset context height + ctx = ctx.WithBlockHeight(height) + + /* Handle staking state. */ + + // iterate through redelegations, reset creation height + var iterErr error + if err := app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) { + for i := range red.Entries { + red.Entries[i].CreationHeight = 0 + } + if iterErr = app.StakingKeeper.SetRedelegation(ctx, red); iterErr != nil { + return true + } + return false + }); err != nil { + return err + } + + if iterErr != nil { + return iterErr + } + + // iterate through unbonding delegations, reset creation height + if err := app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { + for i := range ubd.Entries { + ubd.Entries[i].CreationHeight = 0 + } + if iterErr = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd); iterErr != nil { + return true + } + return false + }); err != nil { + return err + } + + if iterErr != nil { + return iterErr + } + + // Iterate through validators by power descending, reset bond heights, and + // update bond intra-tx counters. + store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey)) + iter := storetypes.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey) + counter := int16(0) + + for ; iter.Valid(); iter.Next() { + addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) + validator, err := app.StakingKeeper.GetValidator(ctx, addr) + if err != nil { + return fmt.Errorf("expected validator %s not found. Error: %w", addr, err) + } + + validator.UnbondingHeight = 0 + if applyAllowedAddrs && !allowedAddrsMap[addr.String()] { + validator.Jailed = true + } + + if err = app.StakingKeeper.SetValidator(ctx, validator); err != nil { + return err + } + counter++ + } + + if err := iter.Close(); err != nil { + app.Logger().Error("error while closing the key-value store reverse prefix iterator: ", err) + return nil + } + + _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + if err != nil { + log.Fatal(err) + } + + /* Handle slashing state. */ + + // reset start height on signing infos + if err := app.SlashingKeeper.IterateValidatorSigningInfos( + ctx, + func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + info.StartHeight = 0 + if iterErr = app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info); iterErr != nil { + return true + } + return false + }, + ); err != nil { + return err + } + + if iterErr != nil { + return iterErr + } + + return nil +} diff --git a/example_chain/genesis.go b/example_chain/genesis.go new file mode 100644 index 00000000..1e7a712c --- /dev/null +++ b/example_chain/genesis.go @@ -0,0 +1,61 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import ( + "encoding/json" + + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + assettypes "github.com/realiotech/realio-network/x/asset/types" +) + +// GenesisState of the blockchain is represented here as a map of raw json +// messages key'd by an identifier string. +// The identifier is used to determine which module genesis information belongs +// to so it may be appropriately routed during init chain. +// Within this application default genesis information is retrieved from +// the ModuleBasicManager which populates json from each BasicModule +// object provided to it during init. +type GenesisState map[string]json.RawMessage + +// NewEVMGenesisState returns the default genesis state for the EVM module. +// +// NOTE: for the example chain implementation we need to set the default EVM denomination +// and enable ALL precompiles. +func NewEVMGenesisState() *evmtypes.GenesisState { + evmGenState := evmtypes.DefaultGenesisState() + evmGenState.Params.ActiveStaticPrecompiles = evmtypes.AvailableStaticPrecompiles + + return evmGenState +} + +// NewErc20GenesisState returns the default genesis state for the ERC20 module. +// +// NOTE: for the example chain implementation we are also adding a default token pair, +// which is the base denomination of the chain (i.e. the WEVMOS contract). +func NewErc20GenesisState() *erc20types.GenesisState { + erc20GenState := erc20types.DefaultGenesisState() + erc20GenState.TokenPairs = ExampleTokenPairs + erc20GenState.Params.NativePrecompiles = append(erc20GenState.Params.NativePrecompiles, WEVMOSContractMainnet) + + return erc20GenState +} + +func NewAssetGenesisState() *assettypes.GenesisState { + erc20GenState := assettypes.DefaultGenesis() + + return erc20GenState +} + +// NewMintGenesisState returns the default genesis state for the mint module. +// +// NOTE: for the example chain implementation we are also adding a default minter. +func NewMintGenesisState() *minttypes.GenesisState { + mintGenState := minttypes.DefaultGenesisState() + mintGenState.Params.MintDenom = ExampleChainDenom + + return mintGenState +} diff --git a/example_chain/local_node.sh b/example_chain/local_node.sh new file mode 100755 index 00000000..11524b3a --- /dev/null +++ b/example_chain/local_node.sh @@ -0,0 +1,222 @@ +#!/bin/bash + +CHAINID="${CHAIN_ID:-os_9005-1}" +MONIKER="localtestnet" +# Remember to change to other types of keyring like 'file' in-case exposing to outside world, +# otherwise your balance will be wiped quickly +# The keyring test does not require private key to steal tokens from you +KEYRING="test" +KEYALGO="eth_secp256k1" + +LOGLEVEL="info" +# Set dedicated home directory for the osd instance +HOMEDIR="$HOME/.osd" + +BASEFEE=10000000 + +# Path variables +CONFIG=$HOMEDIR/config/config.toml +APP_TOML=$HOMEDIR/config/app.toml +GENESIS=$HOMEDIR/config/genesis.json +TMP_GENESIS=$HOMEDIR/config/tmp_genesis.json + +# validate dependencies are installed +command -v jq >/dev/null 2>&1 || { + echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/" + exit 1 +} + +# used to exit on first error (any non-zero exit code) +set -e + +# Parse input flags +install=true +overwrite="" +BUILD_FOR_DEBUG=false + +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -y) + echo "Flag -y passed -> Overwriting the previous chain data." + overwrite="y" + shift # Move past the flag + ;; + -n) + echo "Flag -n passed -> Not overwriting the previous chain data." + overwrite="n" + shift # Move past the argument + ;; + --no-install) + echo "Flag --no-install passed -> Skipping installation of the osd binary." + install=false + shift # Move past the flag + ;; + --remote-debugging) + echo "Flag --remote-debugging passed -> Building with remote debugging options." + BUILD_FOR_DEBUG=true + shift # Move past the flag + ;; + *) + echo "Unknown flag passed: $key -> Exiting script!" + exit 1 + ;; + esac +done + +if [[ $install == true ]]; then + if [[ $BUILD_FOR_DEBUG == true ]]; then + # for remote debugging the optimization should be disabled and the debug info should not be stripped + make install COSMOS_BUILD_OPTIONS=nooptimization,nostrip + else + make install + fi +fi + +# User prompt if neither -y nor -n was passed as a flag +# and an existing local node configuration is found. +if [[ $overwrite = "" ]]; then + if [ -d "$HOMEDIR" ]; then + printf "\nAn existing folder at '%s' was found. You can choose to delete this folder and start a new local node with new keys from genesis. When declined, the existing local node is started. \n" "$HOMEDIR" + echo "Overwrite the existing configuration and start a new local node? [y/n]" + read -r overwrite + else + overwrite="y" + fi +fi + +# Setup local node if overwrite is set to Yes, otherwise skip setup +if [[ $overwrite == "y" || $overwrite == "Y" ]]; then + # Remove the previous folder + rm -rf "$HOMEDIR" + + # Set client config + osd config set client chain-id "$CHAINID" --home "$HOMEDIR" + osd config set client keyring-backend "$KEYRING" --home "$HOMEDIR" + + # myKey address 0x7cb61d4117ae31a12e393a1cfa3bac666481d02e | os10jmp6sgh4cc6zt3e8gw05wavvejgr5pwjnpcky + VAL_KEY="mykey" + VAL_MNEMONIC="gesture inject test cycle original hollow east ridge hen combine junk child bacon zero hope comfort vacuum milk pitch cage oppose unhappy lunar seat" + + # dev0 address 0xc6fe5d33615a1c52c08018c47e8bc53646a0e101 | os1cml96vmptgw99syqrrz8az79xer2pcgp84pdun + USER1_KEY="dev0" + USER1_MNEMONIC="copper push brief egg scan entry inform record adjust fossil boss egg comic alien upon aspect dry avoid interest fury window hint race symptom" + + # dev1 address 0x963ebdf2e1f8db8707d05fc75bfeffba1b5bac17 | os1jcltmuhplrdcwp7stlr4hlhlhgd4htqh3a79sq + USER2_KEY="dev1" + USER2_MNEMONIC="maximum display century economy unlock van census kite error heart snow filter midnight usage egg venture cash kick motor survey drastic edge muffin visual" + + # dev2 address 0x40a0cb1C63e026A81B55EE1308586E21eec1eFa9 | os1gzsvk8rruqn2sx64acfsskrwy8hvrmafqkaze8 + USER3_KEY="dev2" + USER3_MNEMONIC="will wear settle write dance topic tape sea glory hotel oppose rebel client problem era video gossip glide during yard balance cancel file rose" + + # dev3 address 0x498B5AeC5D439b733dC2F58AB489783A23FB26dA | os1fx944mzagwdhx0wz7k9tfztc8g3lkfk6rrgv6l + USER4_KEY="dev3" + USER4_MNEMONIC="doll midnight silk carpet brush boring pluck office gown inquiry duck chief aim exit gain never tennis crime fragile ship cloud surface exotic patch" + + # Import keys from mnemonics + echo "$VAL_MNEMONIC" | osd keys add "$VAL_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOMEDIR" + echo "$USER1_MNEMONIC" | osd keys add "$USER1_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOMEDIR" + echo "$USER2_MNEMONIC" | osd keys add "$USER2_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOMEDIR" + echo "$USER3_MNEMONIC" | osd keys add "$USER3_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOMEDIR" + echo "$USER4_MNEMONIC" | osd keys add "$USER4_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOMEDIR" + + # Set moniker and chain-id for the example chain (Moniker can be anything, chain-id must be an integer) + osd init $MONIKER -o --chain-id "$CHAINID" --home "$HOMEDIR" + + # Change parameter token denominations to desired value + jq '.app_state["staking"]["params"]["bond_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["evm"]["params"]["evm_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state["mint"]["params"]["mint_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + + # Enable precompiles in EVM params + jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + + # Enable native denomination as a token pair for STRv2 + jq '.app_state.erc20.params.native_precompiles=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state.erc20.token_pairs=[{contract_owner:1,erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",denom:"aevmos",enabled:true}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + + # Set gas limit in genesis + jq '.consensus_params["block"]["max_gas"]="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + + if [[ $1 == "pending" ]]; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' "$CONFIG" + sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' "$CONFIG" + sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' "$CONFIG" + sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' "$CONFIG" + sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' "$CONFIG" + sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' "$CONFIG" + sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' "$CONFIG" + sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' "$CONFIG" + else + sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' "$CONFIG" + sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' "$CONFIG" + sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' "$CONFIG" + sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' "$CONFIG" + sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' "$CONFIG" + sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' "$CONFIG" + sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' "$CONFIG" + sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' "$CONFIG" + fi + fi + + # enable prometheus metrics and all APIs for dev node + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' 's/prometheus = false/prometheus = true/' "$CONFIG" + sed -i '' 's/prometheus-retention-time = 0/prometheus-retention-time = 1000000000000/g' "$APP_TOML" + sed -i '' 's/enabled = false/enabled = true/g' "$APP_TOML" + sed -i '' 's/enable = false/enable = true/g' "$APP_TOML" + else + sed -i 's/prometheus = false/prometheus = true/' "$CONFIG" + sed -i 's/prometheus-retention-time = "0"/prometheus-retention-time = "1000000000000"/g' "$APP_TOML" + sed -i 's/enabled = false/enabled = true/g' "$APP_TOML" + sed -i 's/enable = false/enable = true/g' "$APP_TOML" + fi + + # Change proposal periods to pass within a reasonable time for local testing + sed -i.bak 's/"max_deposit_period": "172800s"/"max_deposit_period": "30s"/g' "$GENESIS" + sed -i.bak 's/"voting_period": "172800s"/"voting_period": "30s"/g' "$GENESIS" + sed -i.bak 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "15s"/g' "$GENESIS" + + # set custom pruning settings + sed -i.bak 's/pruning = "default"/pruning = "custom"/g' "$APP_TOML" + sed -i.bak 's/pruning-keep-recent = "0"/pruning-keep-recent = "2"/g' "$APP_TOML" + sed -i.bak 's/pruning-interval = "0"/pruning-interval = "10"/g' "$APP_TOML" + + # Allocate genesis accounts (cosmos formatted addresses) + osd genesis add-genesis-account "$VAL_KEY" 100000000000000000000000000aevmos --keyring-backend "$KEYRING" --home "$HOMEDIR" + osd genesis add-genesis-account "$USER1_KEY" 1000000000000000000000aevmos --keyring-backend "$KEYRING" --home "$HOMEDIR" + osd genesis add-genesis-account "$USER2_KEY" 1000000000000000000000aevmos --keyring-backend "$KEYRING" --home "$HOMEDIR" + osd genesis add-genesis-account "$USER3_KEY" 1000000000000000000000aevmos --keyring-backend "$KEYRING" --home "$HOMEDIR" + osd genesis add-genesis-account "$USER4_KEY" 1000000000000000000000aevmos --keyring-backend "$KEYRING" --home "$HOMEDIR" + + # Sign genesis transaction + osd genesis gentx "$VAL_KEY" 1000000000000000000000aevmos --gas-prices ${BASEFEE}aevmos --keyring-backend "$KEYRING" --chain-id "$CHAINID" --home "$HOMEDIR" + ## In case you want to create multiple validators at genesis + ## 1. Back to `osd keys add` step, init more keys + ## 2. Back to `osd add-genesis-account` step, add balance for those + ## 3. Clone this ~/.osd home directory into some others, let's say `~/.clonedOsd` + ## 4. Run `gentx` in each of those folders + ## 5. Copy the `gentx-*` folders under `~/.clonedOsd/config/gentx/` folders into the original `~/.osd/config/gentx` + + # Collect genesis tx + osd genesis collect-gentxs --home "$HOMEDIR" + + # Run this to ensure everything worked and that the genesis file is setup correctly + osd genesis validate-genesis --home "$HOMEDIR" + + if [[ $1 == "pending" ]]; then + echo "pending mode is on, please wait for the first block committed." + fi +fi + +# Start the node +osd start "$TRACE" \ + --log_level $LOGLEVEL \ + --minimum-gas-prices=0.0001aevmos \ + --home "$HOMEDIR" \ + --json-rpc.api eth,txpool,personal,net,debug,web3 \ + --chain-id "$CHAINID" diff --git a/example_chain/osd/cmd/root.go b/example_chain/osd/cmd/root.go new file mode 100644 index 00000000..b2e34ba8 --- /dev/null +++ b/example_chain/osd/cmd/root.go @@ -0,0 +1,415 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package cmd + +import ( + "errors" + "io" + "os" + + "cosmossdk.io/log" + "cosmossdk.io/store" + snapshottypes "cosmossdk.io/store/snapshots/types" + storetypes "cosmossdk.io/store/types" + confixcmd "cosmossdk.io/tools/confix/cmd" + tmcfg "github.com/cometbft/cometbft/config" + cmtcli "github.com/cometbft/cometbft/libs/cli" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + clientcfg "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/client/debug" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/pruning" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/client/snapshot" + sdkserver "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" + sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + evmoscmd "github.com/evmos/os/client" + evmoscmdconfig "github.com/evmos/os/cmd/config" + evmoskeyring "github.com/evmos/os/crypto/keyring" + evmosserver "github.com/evmos/os/server" + evmosserverconfig "github.com/evmos/os/server/config" + srvflags "github.com/evmos/os/server/flags" + "github.com/realiotech/realio-network/example_chain" + cmdcfg "github.com/realiotech/realio-network/example_chain/osd/config" + "github.com/spf13/cast" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type emptyAppOptions struct{} + +func (ao emptyAppOptions) Get(_ string) interface{} { return nil } + +// NewRootCmd creates a new root command for osd. It is called once in the +// main function. +func NewRootCmd() *cobra.Command { + // we "pre"-instantiate the application for getting the injected/configured encoding configuration + // and the CLI options for the modules + // add keyring to autocli opts + tempApp := example_chain.NewExampleApp( + log.NewNopLogger(), + dbm.NewMemDB(), + nil, + true, + emptyAppOptions{}, + example_chain.EvmosAppOptions, + ) + + encodingConfig := sdktestutil.TestEncodingConfig{ + InterfaceRegistry: tempApp.InterfaceRegistry(), + Codec: tempApp.AppCodec(), + TxConfig: tempApp.GetTxConfig(), + Amino: tempApp.LegacyAmino(), + } + + initClientCtx := client.Context{}. + WithCodec(encodingConfig.Codec). + WithInterfaceRegistry(encodingConfig.InterfaceRegistry). + WithTxConfig(encodingConfig.TxConfig). + WithLegacyAmino(encodingConfig.Amino). + WithInput(os.Stdin). + WithAccountRetriever(authtypes.AccountRetriever{}). + WithBroadcastMode(flags.FlagBroadcastMode). + WithHomeDir(example_chain.DefaultNodeHome). + WithViper(""). // In simapp, we don't use any prefix for env variables. + // evmOS specific setup + WithKeyringOptions(evmoskeyring.Option()). + WithLedgerHasProtobuf(true) + + rootCmd := &cobra.Command{ + Use: "osd", + Short: "exemplary evmOS app", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } + + initClientCtx, err = clientcfg.ReadFromClientConfig(initClientCtx) + if err != nil { + return err + } + + // This needs to go after ReadFromClientConfig, as that function + // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode + // is only available if the client is online. + if !initClientCtx.Offline { + enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) //nolint:gocritic + txConfigOpts := tx.ConfigOptions{ + EnabledSignModes: enabledSignModes, + TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), + } + txConfig, err := tx.NewTxConfigWithOptions( + initClientCtx.Codec, + txConfigOpts, + ) + if err != nil { + return err + } + + initClientCtx = initClientCtx.WithTxConfig(txConfig) + } + + if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { + return err + } + + customAppTemplate, customAppConfig := InitAppConfig(cmdcfg.BaseDenom) + customTMConfig := initTendermintConfig() + + return sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) + }, + } + + initRootCmd(rootCmd, tempApp) + + autoCliOpts := tempApp.AutoCliOpts() + initClientCtx, _ = clientcfg.ReadFromClientConfig(initClientCtx) + autoCliOpts.ClientCtx = initClientCtx + + if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { + panic(err) + } + + return rootCmd +} + +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +// InitAppConfig helps to override default appConfig template and configs. +// return "", nil if no custom configuration is required for the application. +func InitAppConfig(denom string) (string, interface{}) { + type CustomAppConfig struct { + serverconfig.Config + + EVM evmosserverconfig.EVMConfig + JSONRPC evmosserverconfig.JSONRPCConfig + TLS evmosserverconfig.TLSConfig + } + + // Optionally allow the chain developer to overwrite the SDK's default + // server config. + srvCfg := serverconfig.DefaultConfig() + // The SDK's default minimum gas price is set to "" (empty value) inside + // app.toml. If left empty by validators, the node will halt on startup. + // However, the chain developer can set a default app.toml value for their + // validators here. + // + // In summary: + // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their + // own app.toml config, + // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their + // own app.toml to override, or use this default value. + // + // In this example application, we set the min gas prices to 0. + srvCfg.MinGasPrices = "0" + denom + + customAppConfig := CustomAppConfig{ + Config: *srvCfg, + EVM: *evmosserverconfig.DefaultEVMConfig(), + JSONRPC: *evmosserverconfig.DefaultJSONRPCConfig(), + TLS: *evmosserverconfig.DefaultTLSConfig(), + } + + customAppTemplate := serverconfig.DefaultConfigTemplate + + evmosserverconfig.DefaultEVMConfigTemplate + + return customAppTemplate, customAppConfig +} + +func initRootCmd(rootCmd *cobra.Command, osApp *example_chain.ExampleChain) { + cfg := sdk.GetConfig() + cfg.Seal() + + rootCmd.AddCommand( + genutilcli.InitCmd( + osApp.BasicModuleManager, + example_chain.DefaultNodeHome, + ), + genutilcli.Commands(osApp.TxConfig(), osApp.BasicModuleManager, example_chain.DefaultNodeHome), + cmtcli.NewCompletionCmd(rootCmd, true), + debug.Cmd(), + confixcmd.ConfigCommand(), + pruning.Cmd(newApp, example_chain.DefaultNodeHome), + snapshot.Cmd(newApp), + ) + + // add evmOS' flavored TM commands to start server, etc. + evmosserver.AddCommands( + rootCmd, + evmosserver.NewDefaultStartOptions(newApp, example_chain.DefaultNodeHome), + appExport, + addModuleInitFlags, + ) + + // add evmOS key commands + rootCmd.AddCommand( + evmoscmd.KeyCommands(example_chain.DefaultNodeHome, true), + ) + + // add keybase, auxiliary RPC, query, genesis, and tx child commands + rootCmd.AddCommand( + sdkserver.StatusCommand(), + queryCommand(), + txCommand(), + ) + + // add general tx flags to the root command + var err error + rootCmd, err = srvflags.AddTxFlags(rootCmd) + if err != nil { + panic(err) + } +} + +func addModuleInitFlags(_ *cobra.Command) {} + +func queryCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "query", + Aliases: []string{"q"}, + Short: "Querying subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + rpc.QueryEventForTxCmd(), + rpc.ValidatorCommand(), + authcmd.QueryTxsByEventsCmd(), + authcmd.QueryTxCmd(), + sdkserver.QueryBlockCmd(), + sdkserver.QueryBlockResultsCmd(), + ) + + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetSimulateCmd(), + ) + + cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") + + return cmd +} + +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + var cache storetypes.MultiStorePersistentCache + + if cast.ToBool(appOpts.Get(sdkserver.FlagInterBlockCache)) { + cache = store.NewCommitKVStoreCacheManager() + } + + pruningOpts, err := sdkserver.GetPruningOptionsFromFlags(appOpts) + if err != nil { + panic(err) + } + + homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) + chainID := cast.ToString(appOpts.Get(flags.FlagChainID)) + if chainID == "" { + chainID, err = evmoscmdconfig.GetChainIDFromHome(homeDir) + if err != nil { + panic(err) + } + } + + snapshotStore, err := sdkserver.GetSnapshotStore(appOpts) + if err != nil { + panic(err) + } + + snapshotOptions := snapshottypes.NewSnapshotOptions( + cast.ToUint64(appOpts.Get(sdkserver.FlagStateSyncSnapshotInterval)), + cast.ToUint32(appOpts.Get(sdkserver.FlagStateSyncSnapshotKeepRecent)), + ) + + baseappOptions := []func(*baseapp.BaseApp){ + baseapp.SetPruning(pruningOpts), + baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(sdkserver.FlagMinGasPrices))), + baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltHeight))), + baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltTime))), + baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(sdkserver.FlagMinRetainBlocks))), + baseapp.SetInterBlockCache(cache), + baseapp.SetTrace(cast.ToBool(appOpts.Get(sdkserver.FlagTrace))), + baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))), + baseapp.SetSnapshot(snapshotStore, snapshotOptions), + baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))), + baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))), + baseapp.SetChainID(chainID), + } + + // Set up the required mempool and ABCI proposal handlers for evmOS + baseappOptions = append(baseappOptions, func(app *baseapp.BaseApp) { + mempool := sdkmempool.NoOpMempool{} + app.SetMempool(mempool) + + handler := baseapp.NewDefaultProposalHandler(mempool, app) + app.SetPrepareProposal(handler.PrepareProposalHandler()) + app.SetProcessProposal(handler.ProcessProposalHandler()) + }) + + return example_chain.NewExampleApp( + logger, db, traceStore, true, + appOpts, + example_chain.EvmosAppOptions, + baseappOptions..., + ) +} + +// appExport creates a new application (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + var exampleApp *example_chain.ExampleChain + + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(sdkserver.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + if height != -1 { + exampleApp = example_chain.NewExampleApp(logger, db, traceStore, false, appOpts, example_chain.EvmosAppOptions) + + if err := exampleApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + exampleApp = example_chain.NewExampleApp(logger, db, traceStore, true, appOpts, example_chain.EvmosAppOptions) + } + + return exampleApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) +} diff --git a/example_chain/osd/config/config.go b/example_chain/osd/config/config.go new file mode 100644 index 00000000..9899d4c9 --- /dev/null +++ b/example_chain/osd/config/config.go @@ -0,0 +1,42 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package config + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // Bech32Prefix defines the Bech32 prefix used for accounts on the exemplary evmOS blockchain. + Bech32Prefix = "evmos" + + // Bech32PrefixAccAddr defines the Bech32 prefix of an account's address. + Bech32PrefixAccAddr = Bech32Prefix + // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key. + Bech32PrefixAccPub = Bech32Prefix + sdk.PrefixPublic + // Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address. + Bech32PrefixValAddr = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixOperator + // Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key. + Bech32PrefixValPub = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixOperator + sdk.PrefixPublic + // Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address. + Bech32PrefixConsAddr = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixConsensus + // Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key. + Bech32PrefixConsPub = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixConsensus + sdk.PrefixPublic +) + +const ( + // DisplayDenom defines the denomination displayed to users in client applications. + DisplayDenom = "evmos" + // BaseDenom defines to the default denomination used in the evmOS example chain. + BaseDenom = "aevmos" + // BaseDenomUnit defines the precision of the base denomination. + BaseDenomUnit = 18 +) + +// SetBech32Prefixes sets the global prefixes to be used when serializing addresses and public keys to Bech32 strings. +func SetBech32Prefixes(config *sdk.Config) { + config.SetBech32PrefixForAccount(Bech32PrefixAccAddr, Bech32PrefixAccPub) + config.SetBech32PrefixForValidator(Bech32PrefixValAddr, Bech32PrefixValPub) + config.SetBech32PrefixForConsensusNode(Bech32PrefixConsAddr, Bech32PrefixConsPub) +} diff --git a/example_chain/osd/main.go b/example_chain/osd/main.go new file mode 100644 index 00000000..14e1b39e --- /dev/null +++ b/example_chain/osd/main.go @@ -0,0 +1,31 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package main + +import ( + "fmt" + "os" + + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + sdk "github.com/cosmos/cosmos-sdk/types" + examplechain "github.com/realiotech/realio-network/example_chain" + "github.com/realiotech/realio-network/example_chain/osd/cmd" + chainconfig "github.com/realiotech/realio-network/example_chain/osd/config" +) + +func main() { + setupSDKConfig() + + rootCmd := cmd.NewRootCmd() + if err := svrcmd.Execute(rootCmd, "osd", examplechain.DefaultNodeHome); err != nil { + fmt.Fprintln(rootCmd.OutOrStderr(), err) + os.Exit(1) + } +} + +func setupSDKConfig() { + config := sdk.GetConfig() + chainconfig.SetBech32Prefixes(config) + config.Seal() +} diff --git a/example_chain/precompiles.go b/example_chain/precompiles.go new file mode 100644 index 00000000..8bd35aeb --- /dev/null +++ b/example_chain/precompiles.go @@ -0,0 +1,123 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import ( + "fmt" + "maps" + + evidencekeeper "cosmossdk.io/x/evidence/keeper" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" + "github.com/ethereum/go-ethereum/common" + bankprecompile "github.com/evmos/os/precompiles/bank" + "github.com/evmos/os/precompiles/bech32" + distprecompile "github.com/evmos/os/precompiles/distribution" + evidenceprecompile "github.com/evmos/os/precompiles/evidence" + govprecompile "github.com/evmos/os/precompiles/gov" + ics20precompile "github.com/evmos/os/precompiles/ics20" + "github.com/evmos/os/precompiles/p256" + slashingprecompile "github.com/evmos/os/precompiles/slashing" + stakingprecompile "github.com/evmos/os/precompiles/staking" + erc20Keeper "github.com/evmos/os/x/erc20/keeper" + "github.com/evmos/os/x/evm/core/vm" + evmkeeper "github.com/evmos/os/x/evm/keeper" + transferkeeper "github.com/evmos/os/x/ibc/transfer/keeper" +) + +const bech32PrecompileBaseGas = 6_000 + +// NewAvailableStaticPrecompiles returns the list of all available static precompiled contracts from evmOS. +// +// NOTE: this should only be used during initialization of the Keeper. +func NewAvailableStaticPrecompiles( + stakingKeeper stakingkeeper.Keeper, + distributionKeeper distributionkeeper.Keeper, + bankKeeper bankkeeper.Keeper, + erc20Keeper erc20Keeper.Keeper, + authzKeeper authzkeeper.Keeper, + transferKeeper transferkeeper.Keeper, + channelKeeper channelkeeper.Keeper, + evmKeeper *evmkeeper.Keeper, + govKeeper govkeeper.Keeper, + slashingKeeper slashingkeeper.Keeper, + evidenceKeeper evidencekeeper.Keeper, +) map[common.Address]vm.PrecompiledContract { + // Clone the mapping from the latest EVM fork. + precompiles := maps.Clone(vm.PrecompiledContractsBerlin) + + // secp256r1 precompile as per EIP-7212 + p256Precompile := &p256.Precompile{} + + bech32Precompile, err := bech32.NewPrecompile(bech32PrecompileBaseGas) + if err != nil { + panic(fmt.Errorf("failed to instantiate bech32 precompile: %w", err)) + } + + stakingPrecompile, err := stakingprecompile.NewPrecompile(stakingKeeper, authzKeeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate staking precompile: %w", err)) + } + + distributionPrecompile, err := distprecompile.NewPrecompile( + distributionKeeper, + stakingKeeper, + authzKeeper, + evmKeeper, + ) + if err != nil { + panic(fmt.Errorf("failed to instantiate distribution precompile: %w", err)) + } + + ibcTransferPrecompile, err := ics20precompile.NewPrecompile( + stakingKeeper, + transferKeeper, + channelKeeper, + authzKeeper, + evmKeeper, + ) + if err != nil { + panic(fmt.Errorf("failed to instantiate ICS20 precompile: %w", err)) + } + + bankPrecompile, err := bankprecompile.NewPrecompile(bankKeeper, erc20Keeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate bank precompile: %w", err)) + } + + govPrecompile, err := govprecompile.NewPrecompile(govKeeper, authzKeeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate gov precompile: %w", err)) + } + + slashingPrecompile, err := slashingprecompile.NewPrecompile(slashingKeeper, authzKeeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate slashing precompile: %w", err)) + } + + evidencePrecompile, err := evidenceprecompile.NewPrecompile(evidenceKeeper, authzKeeper) + if err != nil { + panic(fmt.Errorf("failed to instantiate evidence precompile: %w", err)) + } + + // Stateless precompiles + precompiles[bech32Precompile.Address()] = bech32Precompile + precompiles[p256Precompile.Address()] = p256Precompile + + // Stateful precompiles + precompiles[stakingPrecompile.Address()] = stakingPrecompile + precompiles[distributionPrecompile.Address()] = distributionPrecompile + precompiles[ibcTransferPrecompile.Address()] = ibcTransferPrecompile + precompiles[bankPrecompile.Address()] = bankPrecompile + precompiles[govPrecompile.Address()] = govPrecompile + precompiles[slashingPrecompile.Address()] = slashingPrecompile + precompiles[evidencePrecompile.Address()] = evidencePrecompile + + return precompiles +} diff --git a/example_chain/test_helpers.go b/example_chain/test_helpers.go new file mode 100644 index 00000000..768eb17e --- /dev/null +++ b/example_chain/test_helpers.go @@ -0,0 +1,138 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import ( + "encoding/json" + "fmt" + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + cmttypes "github.com/cometbft/cometbft/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/evmos/os/cmd/config" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + chainconfig "github.com/realiotech/realio-network/example_chain/osd/config" + "github.com/stretchr/testify/require" +) + +// SetupOptions defines arguments that are passed into `Simapp` constructor. +type SetupOptions struct { + Logger log.Logger + DB *dbm.MemDB + AppOpts servertypes.AppOptions +} + +func init() { + // we're setting the minimum gas price to 0 to simplify the tests + feemarkettypes.DefaultMinGasPrice = math.LegacyZeroDec() + + // Set the global SDK config for the tests + cfg := sdk.GetConfig() + chainconfig.SetBech32Prefixes(cfg) + config.SetBip44CoinType(cfg) +} + +func setup(withGenesis bool, invCheckPeriod uint, chainID string) (*ExampleChain, GenesisState) { + db := dbm.NewMemDB() + + appOptions := make(simtestutil.AppOptionsMap, 0) + appOptions[flags.FlagHome] = DefaultNodeHome + appOptions[server.FlagInvCheckPeriod] = invCheckPeriod + + app := NewExampleApp(log.NewNopLogger(), db, nil, true, appOptions, EvmosAppOptions, baseapp.SetChainID(chainID)) + if withGenesis { + return app, app.DefaultGenesis() + } + + return app, GenesisState{} +} + +// Setup initializes a new ExampleChain. A Nop logger is set in ExampleChain. +func Setup(t *testing.T, chainID string) *ExampleChain { + t.Helper() + + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + + // create validator set with single validator + validator := cmttypes.NewValidator(pubKey, 1) + valSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000000000000))), + } + + app := SetupWithGenesisValSet(t, chainID, valSet, []authtypes.GenesisAccount{acc}, balance) + + return app +} + +// SetupWithGenesisValSet initializes a new ExampleChain with a validator set and genesis accounts +// that also act as delegators. For simplicity, each validator is bonded with a delegation +// of one consensus engine unit in the default token of the simapp from first genesis +// account. A Nop logger is set in ExampleChain. +func SetupWithGenesisValSet(t *testing.T, chainID string, valSet *cmttypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *ExampleChain { + t.Helper() + + app, genesisState := setup(true, 5, chainID) + genesisState, err := simtestutil.GenesisStateWithValSet(app.AppCodec(), genesisState, valSet, genAccs, balances...) + require.NoError(t, err) + + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + require.NoError(t, err) + + // init chain will set the validator set and initialize the genesis accounts + if _, err = app.InitChain( + &abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: simtestutil.DefaultConsensusParams, + AppStateBytes: stateBytes, + ChainId: chainID, + }, + ); err != nil { + panic(fmt.Sprintf("app.InitChain failed: %v", err)) + } + + // NOTE: we are NOT committing the changes here as opposed to the function from simapp + // because that would already adjust e.g. the base fee in the params. + // We want to keep the genesis state as is for the tests unless we commit the changes manually. + + return app +} + +// SetupTestingApp initializes the IBC-go testing application +// need to keep this design to comply with the ibctesting SetupTestingApp func +// and be able to set the chainID for the tests properly +func SetupTestingApp(chainID string) func() (ibctesting.TestingApp, map[string]json.RawMessage) { + return func() (ibctesting.TestingApp, map[string]json.RawMessage) { + db := dbm.NewMemDB() + app := NewExampleApp( + log.NewNopLogger(), + db, nil, true, + simtestutil.NewAppOptionsWithFlagHome(DefaultNodeHome), + EvmosAppOptions, + baseapp.SetChainID(chainID), + ) + return app, app.DefaultGenesis() + } +} diff --git a/example_chain/testutil/abci.go b/example_chain/testutil/abci.go new file mode 100644 index 00000000..b29efc00 --- /dev/null +++ b/example_chain/testutil/abci.go @@ -0,0 +1,280 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "fmt" + "time" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttypes "github.com/cometbft/cometbft/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + + app "github.com/realiotech/realio-network/example_chain" + "github.com/realiotech/realio-network/testutil/tx" +) + +// Commit commits a block at a given time. Reminder: At the end of each +// Tendermint Consensus round the following methods are run +// 1. BeginBlock +// 2. DeliverTx +// 3. EndBlock +// 4. Commit +func Commit(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (sdk.Context, error) { + header, err := commit(ctx, app, t, vs) + if err != nil { + return ctx, err + } + + return ctx.WithBlockHeader(header), nil +} + +// CommitAndCreateNewCtx commits a block at a given time creating a ctx with the current settings +// This is useful to keep test settings that could be affected by EndBlockers, e.g. +// setting a baseFee == 0 and expecting this condition to continue after commit +func CommitAndCreateNewCtx(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (sdk.Context, error) { + header, err := commit(ctx, app, t, vs) + if err != nil { + return ctx, err + } + + // NewContext function keeps the multistore + // but resets other context fields + // GasMeter is set as InfiniteGasMeter + newCtx := app.BaseApp.NewContextLegacy(false, header) + // set the reseted fields to keep the current ctx settings + newCtx = newCtx.WithMinGasPrices(ctx.MinGasPrices()) + newCtx = newCtx.WithEventManager(ctx.EventManager()) + newCtx = newCtx.WithKVGasConfig(ctx.KVGasConfig()) + newCtx = newCtx.WithTransientKVGasConfig(ctx.TransientKVGasConfig()) + + return newCtx, nil +} + +// DeliverTx delivers a cosmos tx for a given set of msgs +func DeliverTx( + ctx sdk.Context, + exampleApp *app.ExampleChain, + priv cryptotypes.PrivKey, + gasPrice *sdkmath.Int, + msgs ...sdk.Msg, +) (abci.ExecTxResult, error) { + txConfig := exampleApp.GetTxConfig() + tx, err := tx.PrepareCosmosTx( + ctx, + exampleApp, + tx.CosmosTxArgs{ + TxCfg: txConfig, + Priv: priv, + ChainID: ctx.ChainID(), + Gas: 10_000_000, + GasPrice: gasPrice, + Msgs: msgs, + }, + ) + if err != nil { + return abci.ExecTxResult{}, err + } + return BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) +} + +// DeliverEthTx generates and broadcasts a Cosmos Tx populated with MsgEthereumTx messages. +// If a private key is provided, it will attempt to sign all messages with the given private key, +// otherwise, it will assume the messages have already been signed. +func DeliverEthTx( + exampleApp *app.ExampleChain, + priv cryptotypes.PrivKey, + msgs ...sdk.Msg, +) (abci.ExecTxResult, error) { + txConfig := exampleApp.GetTxConfig() + + tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) + if err != nil { + return abci.ExecTxResult{}, err + } + res, err := BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) + if err != nil { + return res, err + } + + codec := exampleApp.AppCodec() + if _, err := CheckEthTxResponse(res, codec); err != nil { + return res, err + } + return res, nil +} + +// DeliverEthTxWithoutCheck generates and broadcasts a Cosmos Tx populated with MsgEthereumTx messages. +// If a private key is provided, it will attempt to sign all messages with the given private key, +// otherwise, it will assume the messages have already been signed. It does not check if the Eth tx is +// successful or not. +func DeliverEthTxWithoutCheck( + exampleApp *app.ExampleChain, + priv cryptotypes.PrivKey, + msgs ...sdk.Msg, +) (abci.ExecTxResult, error) { + txConfig := exampleApp.GetTxConfig() + + tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) + if err != nil { + return abci.ExecTxResult{}, err + } + + res, err := BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) + if err != nil { + return abci.ExecTxResult{}, err + } + + return res, nil +} + +// CheckTx checks a cosmos tx for a given set of msgs +func CheckTx( + ctx sdk.Context, + exampleApp *app.ExampleChain, + priv cryptotypes.PrivKey, + gasPrice *sdkmath.Int, + msgs ...sdk.Msg, +) (abci.ResponseCheckTx, error) { + txConfig := exampleApp.GetTxConfig() + + tx, err := tx.PrepareCosmosTx( + ctx, + exampleApp, + tx.CosmosTxArgs{ + TxCfg: txConfig, + Priv: priv, + ChainID: ctx.ChainID(), + GasPrice: gasPrice, + Gas: 10_000_000, + Msgs: msgs, + }, + ) + if err != nil { + return abci.ResponseCheckTx{}, err + } + return checkTxBytes(exampleApp, txConfig.TxEncoder(), tx) +} + +// CheckEthTx checks a Ethereum tx for a given set of msgs +func CheckEthTx( + exampleApp *app.ExampleChain, + priv cryptotypes.PrivKey, + msgs ...sdk.Msg, +) (abci.ResponseCheckTx, error) { + txConfig := exampleApp.GetTxConfig() + + tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) + if err != nil { + return abci.ResponseCheckTx{}, err + } + return checkTxBytes(exampleApp, txConfig.TxEncoder(), tx) +} + +// BroadcastTxBytes encodes a transaction and calls DeliverTx on the app. +func BroadcastTxBytes(app *app.ExampleChain, txEncoder sdk.TxEncoder, tx sdk.Tx) (abci.ExecTxResult, error) { + // bz are bytes to be broadcasted over the network + bz, err := txEncoder(tx) + if err != nil { + return abci.ExecTxResult{}, err + } + + req := abci.RequestFinalizeBlock{Txs: [][]byte{bz}} + + res, err := app.BaseApp.FinalizeBlock(&req) + if err != nil { + return abci.ExecTxResult{}, err + } + if len(res.TxResults) != 1 { + return abci.ExecTxResult{}, fmt.Errorf("unexpected transaction results. Expected 1, got: %d", len(res.TxResults)) + } + txRes := res.TxResults[0] + if txRes.Code != 0 { + return abci.ExecTxResult{}, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "log: %s", txRes.Log) + } + + return *txRes, nil +} + +// commit is a private helper function that runs the EndBlocker logic, commits the changes, +// updates the header, runs the BeginBlocker function and returns the updated header +func commit(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (tmproto.Header, error) { + header := ctx.BlockHeader() + req := abci.RequestFinalizeBlock{Height: header.Height} + + if vs != nil { + res, err := app.FinalizeBlock(&req) + if err != nil { + return header, err + } + + nextVals, err := applyValSetChanges(vs, res.ValidatorUpdates) + if err != nil { + return header, err + } + header.ValidatorsHash = vs.Hash() + header.NextValidatorsHash = nextVals.Hash() + } else { + if _, err := app.EndBlocker(ctx); err != nil { + return header, err + } + } + + if _, err := app.Commit(); err != nil { + return header, err + } + + header.Height++ + header.Time = header.Time.Add(t) + header.AppHash = app.LastCommitID().Hash + + if _, err := app.BeginBlocker(ctx); err != nil { + return header, err + } + + return header, nil +} + +// checkTxBytes encodes a transaction and calls checkTx on the app. +func checkTxBytes(app *app.ExampleChain, txEncoder sdk.TxEncoder, tx sdk.Tx) (abci.ResponseCheckTx, error) { + bz, err := txEncoder(tx) + if err != nil { + return abci.ResponseCheckTx{}, err + } + + req := abci.RequestCheckTx{Tx: bz} + res, err := app.BaseApp.CheckTx(&req) + if err != nil { + return abci.ResponseCheckTx{}, err + } + + if res.Code != 0 { + return abci.ResponseCheckTx{}, errorsmod.Wrapf(errortypes.ErrInvalidRequest, res.Log) + } + + return *res, nil +} + +// applyValSetChanges takes in cmttypes.ValidatorSet and []abci.ValidatorUpdate and will return a new cmttypes.ValidatorSet which has the +// provided validator updates applied to the provided validator set. +func applyValSetChanges(valSet *cmttypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) (*cmttypes.ValidatorSet, error) { + updates, err := cmttypes.PB2TM.ValidatorUpdates(valUpdates) + if err != nil { + return nil, err + } + + // must copy since validator set will mutate with UpdateWithChangeSet + newVals := valSet.Copy() + err = newVals.UpdateWithChangeSet(updates) + if err != nil { + return nil, err + } + + return newVals, nil +} diff --git a/example_chain/testutil/contract.go b/example_chain/testutil/contract.go new file mode 100644 index 00000000..e78717c5 --- /dev/null +++ b/example_chain/testutil/contract.go @@ -0,0 +1,170 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "fmt" + "math/big" + + "github.com/cosmos/gogoproto/proto" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + evm "github.com/evmos/os/x/evm/types" + evmtypes "github.com/evmos/os/x/evm/types" + exampleapp "github.com/realiotech/realio-network/example_chain" + "github.com/realiotech/realio-network/testutil/tx" +) + +// ContractArgs are the params used for calling a smart contract. +type ContractArgs struct { + // Addr is the address of the contract to call. + Addr common.Address + // ABI is the ABI of the contract to call. + ABI abi.ABI + // MethodName is the name of the method to call. + MethodName string + // Args are the arguments to pass to the method. + Args []interface{} +} + +// ContractCallArgs is the arguments for calling a smart contract. +type ContractCallArgs struct { + // Contract are the contract-specific arguments required for the contract call. + Contract ContractArgs + // Nonce is the nonce to use for the transaction. + Nonce *big.Int + // Amount is the amount of the native denomination to send in the transaction. + Amount *big.Int + // GasLimit to use for the transaction + GasLimit uint64 + // PrivKey is the private key to be used for the transaction. + PrivKey cryptotypes.PrivKey +} + +// DeployContract deploys a contract with the provided private key, +// compiled contract data and constructor arguments +func DeployContract( + ctx sdk.Context, + app *exampleapp.ExampleChain, + priv cryptotypes.PrivKey, + queryClientEvm evm.QueryClient, + contract evm.CompiledContract, + constructorArgs ...interface{}, +) (common.Address, error) { + chainID := evmtypes.GetEthChainConfig().ChainID + from := common.BytesToAddress(priv.PubKey().Address().Bytes()) + nonce := app.EVMKeeper.GetNonce(ctx, from) + + ctorArgs, err := contract.ABI.Pack("", constructorArgs...) + if err != nil { + return common.Address{}, err + } + + data := append(contract.Bin, ctorArgs...) //nolint:gocritic + gas, err := tx.GasLimit(ctx, from, data, queryClientEvm) + if err != nil { + return common.Address{}, err + } + + baseFeeRes, err := queryClientEvm.BaseFee(ctx, &evmtypes.QueryBaseFeeRequest{}) + if err != nil { + return common.Address{}, err + } + + msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{ + ChainID: chainID, + Nonce: nonce, + GasLimit: gas, + GasFeeCap: baseFeeRes.BaseFee.BigInt(), + GasTipCap: big.NewInt(1), + Input: data, + Accesses: ðtypes.AccessList{}, + }) + msgEthereumTx.From = from.String() + + res, err := DeliverEthTx(app, priv, msgEthereumTx) + if err != nil { + return common.Address{}, err + } + + if _, err := CheckEthTxResponse(res, app.AppCodec()); err != nil { + return common.Address{}, err + } + + return crypto.CreateAddress(from, nonce), nil +} + +// DeployContractWithFactory deploys a contract using a contract factory +// with the provided factoryAddress +func DeployContractWithFactory( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + priv cryptotypes.PrivKey, + factoryAddress common.Address, +) (common.Address, abci.ExecTxResult, error) { + chainID := evmtypes.GetEthChainConfig().ChainID + from := common.BytesToAddress(priv.PubKey().Address().Bytes()) + factoryNonce := exampleApp.EVMKeeper.GetNonce(ctx, factoryAddress) + nonce := exampleApp.EVMKeeper.GetNonce(ctx, from) + + msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{ + ChainID: chainID, + Nonce: nonce, + To: &factoryAddress, + GasLimit: uint64(100000), + GasPrice: big.NewInt(1000000000), + }) + msgEthereumTx.From = from.String() + + res, err := DeliverEthTx(exampleApp, priv, msgEthereumTx) + if err != nil { + return common.Address{}, abci.ExecTxResult{}, err + } + + if _, err := CheckEthTxResponse(res, exampleApp.AppCodec()); err != nil { + return common.Address{}, abci.ExecTxResult{}, err + } + + return crypto.CreateAddress(factoryAddress, factoryNonce), res, err +} + +// CheckEthTxResponse checks that the transaction was executed successfully +func CheckEthTxResponse(r abci.ExecTxResult, cdc codec.Codec) ([]*evm.MsgEthereumTxResponse, error) { + if !r.IsOK() { + return nil, fmt.Errorf("tx failed. Code: %d, Logs: %s", r.Code, r.Log) + } + + var txData sdk.TxMsgData + if err := cdc.Unmarshal(r.Data, &txData); err != nil { + return nil, err + } + + if len(txData.MsgResponses) == 0 { + return nil, fmt.Errorf("no message responses found") + } + + responses := make([]*evm.MsgEthereumTxResponse, 0, len(txData.MsgResponses)) + for i := range txData.MsgResponses { + var res evm.MsgEthereumTxResponse + if err := proto.Unmarshal(txData.MsgResponses[i].Value, &res); err != nil { + return nil, err + } + + if res.Failed() { + return nil, fmt.Errorf("tx failed. VmError: %s", res.VmError) + } + responses = append(responses, &res) + } + + return responses, nil +} diff --git a/example_chain/testutil/eth_setup.go b/example_chain/testutil/eth_setup.go new file mode 100644 index 00000000..a8d00f15 --- /dev/null +++ b/example_chain/testutil/eth_setup.go @@ -0,0 +1,205 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "encoding/json" + "time" + + evmostypes "github.com/evmos/os/types" + + "cosmossdk.io/log" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmtypes "github.com/cometbft/cometbft/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + exampleapp "github.com/realiotech/realio-network/example_chain" +) + +// DefaultConsensusParams defines the default Tendermint consensus params used in +// Evmos testing. +var DefaultConsensusParams = &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ + MaxBytes: 200000, + MaxGas: -1, // no limit + }, + Evidence: &tmproto.EvidenceParams{ + MaxAgeNumBlocks: 302400, + MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration + MaxBytes: 10000, + }, + Validator: &tmproto.ValidatorParams{ + PubKeyTypes: []string{ + cmtypes.ABCIPubKeyTypeEd25519, + }, + }, +} + +// EthDefaultConsensusParams defines the default Tendermint consensus params used in +// evmOS app testing. +// +// TODO: currently not used +var EthDefaultConsensusParams = &cmtypes.ConsensusParams{ + Block: cmtypes.BlockParams{ + MaxBytes: 200000, + MaxGas: -1, // no limit + }, + Evidence: cmtypes.EvidenceParams{ + MaxAgeNumBlocks: 302400, + MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration + MaxBytes: 10000, + }, + Validator: cmtypes.ValidatorParams{ + PubKeyTypes: []string{ + cmtypes.ABCIPubKeyTypeEd25519, + }, + }, +} + +// EthSetup initializes a new evmOS application. A Nop logger is set in ExampleChain. +func EthSetup(isCheckTx bool, chainID string, patchGenesis func(*exampleapp.ExampleChain, evmostypes.GenesisState) evmostypes.GenesisState) *exampleapp.ExampleChain { + return EthSetupWithDB(isCheckTx, chainID, patchGenesis, dbm.NewMemDB()) +} + +// EthSetupWithDB initializes a new ExampleChain. A Nop logger is set in ExampleChain. +func EthSetupWithDB(isCheckTx bool, chainID string, patchGenesis func(*exampleapp.ExampleChain, evmostypes.GenesisState) evmostypes.GenesisState, db dbm.DB) *exampleapp.ExampleChain { + app := exampleapp.NewExampleApp(log.NewNopLogger(), + db, + nil, + true, + simtestutil.NewAppOptionsWithFlagHome(exampleapp.DefaultNodeHome), + exampleapp.EvmosAppOptions, + baseapp.SetChainID(chainID), + ) + if !isCheckTx { + // init chain must be called to stop deliverState from being nil + genesisState := NewTestGenesisState(app) + if patchGenesis != nil { + genesisState = patchGenesis(app, genesisState) + } + + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + if err != nil { + panic(err) + } + + // Initialize the chain + app.InitChain( + &abci.RequestInitChain{ + ChainId: chainID, + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + } + + return app +} + +// NewTestGenesisState generate genesis state with single validator +// +// It is also setting up the EVM parameters to use sensible defaults. +// +// TODO: are these different genesis functions necessary or can they all be refactored into one? +// there's also other genesis state functions; some like app.DefaultGenesis() or others in test helpers only. +func NewTestGenesisState(app *exampleapp.ExampleChain) evmostypes.GenesisState { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + if err != nil { + panic(err) + } + // create validator set with single validator + validator := cmtypes.NewValidator(pubKey, 1) + valSet := cmtypes.NewValidatorSet([]*cmtypes.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000000000000))), + } + + genesisState := app.DefaultGenesis() + return genesisStateWithValSet(app.AppCodec(), genesisState, valSet, []authtypes.GenesisAccount{acc}, balance) +} + +func genesisStateWithValSet(codec codec.Codec, genesisState evmostypes.GenesisState, + valSet *cmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, + balances ...banktypes.Balance, +) evmostypes.GenesisState { + // set genesis accounts + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) + + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) + delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) + + bondAmt := sdk.DefaultPowerReduction + + for _, val := range valSet.Validators { + pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) + if err != nil { + panic(err) + } + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + panic(err) + } + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(val.Address).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondAmt, + DelegatorShares: math.LegacyOneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec()), + MinSelfDelegation: math.ZeroInt(), + } + validators = append(validators, validator) + delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress().String(), val.Address.String(), math.LegacyOneDec())) + } + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) + genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis) + + totalSupply := sdk.NewCoins() + for _, b := range balances { + // add genesis acc tokens to total supply + totalSupply = totalSupply.Add(b.Coins...) + } + + for range delegations { + // add delegated tokens to total supply + totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)) + } + + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + }) + + // update total supply + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}, []banktypes.SendEnabled{}) + genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) + + return genesisState +} diff --git a/example_chain/testutil/fund.go b/example_chain/testutil/fund.go new file mode 100644 index 00000000..d0efaba9 --- /dev/null +++ b/example_chain/testutil/fund.go @@ -0,0 +1,43 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/evmos/os/testutil/constants" +) + +// FundAccount is a utility function that funds an account by minting and +// sending the coins to the address. +func FundAccount(ctx sdk.Context, bankKeeper bankkeeper.Keeper, addr sdk.AccAddress, amounts sdk.Coins) error { + if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) +} + +// FundAccountWithBaseDenom is a utility function that uses the FundAccount function +// to fund an account with the default denomination. +// +// TODO: as per Freddy these methods should be replaced with a bank transfer from a main account, not by minting in the process +func FundAccountWithBaseDenom(ctx sdk.Context, bankKeeper bankkeeper.Keeper, addr sdk.AccAddress, amount int64) error { + coins := sdk.NewCoins( + sdk.NewCoin(constants.ExampleAttoDenom, math.NewInt(amount)), + ) + return FundAccount(ctx, bankKeeper, addr, coins) +} + +// FundModuleAccount is a utility function that funds a module account by +// minting and sending the coins to the address. +func FundModuleAccount(ctx sdk.Context, bankKeeper bankkeeper.Keeper, recipientMod string, amounts sdk.Coins) error { + if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, recipientMod, amounts) +} diff --git a/example_chain/testutil/gas.go b/example_chain/testutil/gas.go new file mode 100644 index 00000000..5410c448 --- /dev/null +++ b/example_chain/testutil/gas.go @@ -0,0 +1,18 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "cosmossdk.io/math" +) + +var ( + // ExampleMinGasPrices defines 20B related to atto units as the minimum gas price value on the fee market module. + // See https://commonwealth.im/evmos/discussion/5073-global-min-gas-price-value-for-cosmos-sdk-and-evm-transaction-choosing-a-value for reference + ExampleMinGasPrices = math.LegacyNewDec(20_000_000_000) + + // ExampleMinGasMultiplier defines the min gas multiplier value on the fee market module. + // 50% of the leftover gas will be refunded + ExampleMinGasMultiplier = math.LegacyNewDecWithPrec(5, 1) +) diff --git a/example_chain/testutil/integration.go b/example_chain/testutil/integration.go new file mode 100644 index 00000000..33f2e15c --- /dev/null +++ b/example_chain/testutil/integration.go @@ -0,0 +1,81 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package testutil + +import ( + "strconv" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/evmos/os/crypto/ethsecp256k1" + exampleapp "github.com/realiotech/realio-network/example_chain" +) + +// SubmitProposal delivers a submit proposal tx for a given gov content. +// Depending on the content type, the eventNum needs to specify submit_proposal +// event. +func SubmitProposal( + ctx sdk.Context, + appEvmos *exampleapp.ExampleChain, + pk *ethsecp256k1.PrivKey, + content govv1beta1.Content, + eventNum int, +) (id uint64, err error) { + accountAddress := sdk.AccAddress(pk.PubKey().Address().Bytes()) + stakeDenom := stakingtypes.DefaultParams().BondDenom + + deposit := sdk.NewCoins(sdk.NewCoin(stakeDenom, math.NewInt(100000000))) + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, accountAddress) + if err != nil { + return id, err + } + res, err := DeliverTx(ctx, appEvmos, pk, nil, msg) + if err != nil { + return id, err + } + + submitEvent := res.GetEvents()[eventNum] + if submitEvent.Type != "submit_proposal" || submitEvent.Attributes[0].Key != "proposal_id" { + return id, errorsmod.Wrapf(errorsmod.Error{}, "eventNumber %d in SubmitProposal calls %s instead of submit_proposal", eventNum, submitEvent.Type) + } + + return strconv.ParseUint(submitEvent.Attributes[0].Value, 10, 64) +} + +// Delegate delivers a delegate tx +func Delegate( + ctx sdk.Context, + appEvmos *exampleapp.ExampleChain, + priv *ethsecp256k1.PrivKey, + delegateAmount sdk.Coin, + validator stakingtypes.Validator, +) (abci.ExecTxResult, error) { + accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes()) + + val, err := sdk.ValAddressFromBech32(validator.OperatorAddress) + if err != nil { + return abci.ExecTxResult{}, err + } + + delegateMsg := stakingtypes.NewMsgDelegate(accountAddress.String(), val.String(), delegateAmount) + return DeliverTx(ctx, appEvmos, priv, nil, delegateMsg) +} + +// Vote delivers a vote tx with the VoteOption "yes" +func Vote( + ctx sdk.Context, + appEvmos *exampleapp.ExampleChain, + priv *ethsecp256k1.PrivKey, + proposalID uint64, + voteOption govv1beta1.VoteOption, +) (abci.ExecTxResult, error) { + accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes()) + + voteMsg := govv1beta1.NewMsgVote(accountAddress, proposalID, voteOption) + return DeliverTx(ctx, appEvmos, priv, nil, voteMsg) +} diff --git a/example_chain/token_pair.go b/example_chain/token_pair.go new file mode 100644 index 00000000..f97fd76c --- /dev/null +++ b/example_chain/token_pair.go @@ -0,0 +1,20 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +import erc20types "github.com/evmos/os/x/erc20/types" + +// WEVMOSContractMainnet is the WEVMOS contract address for mainnet +const WEVMOSContractMainnet = "0xD4949664cD82660AaE99bEdc034a0deA8A0bd517" + +// ExampleTokenPairs creates a slice of token pairs, that contains a pair for the native denom of the example chain +// implementation. +var ExampleTokenPairs = []erc20types.TokenPair{ + { + Erc20Address: WEVMOSContractMainnet, + Denom: ExampleChainDenom, + Enabled: true, + ContractOwner: erc20types.OWNER_MODULE, + }, +} diff --git a/example_chain/upgrades.go b/example_chain/upgrades.go new file mode 100644 index 00000000..8d554e21 --- /dev/null +++ b/example_chain/upgrades.go @@ -0,0 +1,8 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package example_chain + +func (app ExampleChain) RegisterUpgradeHandlers() { + // No upgrades registered yet +} diff --git a/go.mod b/go.mod index 82cde197..46b7c34c 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/cosmos/rosetta v0.50.10 github.com/ethereum/go-ethereum v1.11.5 github.com/evmos/os v0.0.0-20241002122822-02a9121016ee + github.com/evmos/os/example_chain v0.0.0-20250130185216-d2cab8abc34d github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -38,6 +39,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/sync v0.10.0 google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 google.golang.org/grpc v1.69.2 @@ -113,7 +115,6 @@ require ( github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/dot v1.6.2 // indirect - github.com/evmos/os/example_chain v0.0.0-20240924163020-b2a4187dad50 // indirect github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -235,7 +236,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.29.0 // indirect @@ -262,9 +262,6 @@ replace ( github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc4 github.com/evmos/os => github.com/evmos/os v0.0.0-20250130185216-d2cab8abc34d - // use Realio sdk v0.46.11-realio-4 - // github.com/cosmos/cosmos-sdk => github.com/realiotech/cosmos-sdk v0.46.11-realio-4 - github.com/evmos/os/example_chain => github.com/evmos/os/example_chain v0.0.0-20250130185216-d2cab8abc34d // github.com/realio-tech/multi-staking-module => ../multi-staking // github.com/evmos/os => ../evmos-os diff --git a/precompiles/erc20/abi.json b/precompiles/erc20/abi.json index 68edc8d3..32ca187c 100644 --- a/precompiles/erc20/abi.json +++ b/precompiles/erc20/abi.json @@ -162,6 +162,25 @@ "name": "Transfer", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -522,7 +541,13 @@ } ], "name": "mint", - "outputs": [], + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "nonpayable", "type": "function" }, diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index 459f956c..d55491bd 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -4,6 +4,7 @@ package erc20 import ( + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -44,6 +45,8 @@ func (p Precompile) EmitTransferEvent(ctx sdk.Context, stateDB vm.StateDB, from, return err } + fmt.Println("event.Inputs", event.Inputs) + arguments := abi.Arguments{event.Inputs[2]} packed, err := arguments.Pack(value) if err != nil { @@ -74,6 +77,8 @@ func (p Precompile) EmitMintEvent(ctx sdk.Context, stateDB vm.StateDB, to common return err } + fmt.Println("event.Inputs", event.Inputs) + arguments := abi.Arguments{event.Inputs[1]} packed, err := arguments.Pack(value) if err != nil { diff --git a/precompiles/erc20/integration_test.go b/precompiles/erc20/integration_test.go deleted file mode 100644 index 27a6efaa..00000000 --- a/precompiles/erc20/integration_test.go +++ /dev/null @@ -1,2868 +0,0 @@ -package erc20 - -import ( - "fmt" - "math/big" - "slices" - "strings" - "testing" - - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/evmos/os/contracts" - auth "github.com/evmos/os/precompiles/authorization" - "github.com/evmos/os/precompiles/erc20" - "github.com/evmos/os/precompiles/erc20/testdata" - "github.com/evmos/os/precompiles/testutil" - testconstants "github.com/evmos/os/testutil/constants" - "github.com/evmos/os/testutil/integration/os/factory" - "github.com/evmos/os/testutil/integration/os/grpc" - "github.com/evmos/os/testutil/integration/os/keyring" - "github.com/evmos/os/testutil/integration/os/network" - integrationutils "github.com/evmos/os/testutil/integration/os/utils" - utiltx "github.com/evmos/os/testutil/tx" - erc20types "github.com/evmos/os/x/erc20/types" - "github.com/evmos/os/x/evm/core/vm" - evmtypes "github.com/evmos/os/x/evm/types" - - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/ginkgo/v2" - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/gomega" -) - -var is *IntegrationTestSuite - -type IntegrationTestSuite struct { - // NOTE: we have to use the Unit testing network because we access a keeper in a setup function. - // Might adjust this on a follow-up PR. - network *network.UnitTestNetwork - handler grpc.Handler - keyring keyring.Keyring - factory factory.TxFactory - - bondDenom string - tokenDenom string // erc20 precompile denom with supply - tokenDenomTwo string // erc20 precompile denom with zero supply - - precompile *erc20.Precompile // erc20 precompile with supply - precompileTwo *erc20.Precompile // erc20 precompile with zero supply -} - -func (is *IntegrationTestSuite) SetupTest() { - is.tokenDenom = "xmpl" - is.tokenDenomTwo = "xmpl2" - - keys := keyring.New(2) - genesis := integrationutils.CreateGenesisWithTokenPairs(keys, is.tokenDenom, is.tokenDenomTwo) - - nw := network.NewUnitTestNetwork( - network.WithPreFundedAccounts(keys.GetAllAccAddrs()...), - network.WithOtherDenoms([]string{is.tokenDenom}), // add balance (supply) to is.tokenDenom - network.WithCustomGenesis(genesis), - ) - gh := grpc.NewIntegrationHandler(nw) - tf := factory.New(nw, gh) - - is.network = nw - is.factory = tf - is.handler = gh - is.keyring = keys - - is.bondDenom = nw.GetBaseDenom() - - erc20Gen := genesis[erc20types.ModuleName].(*erc20types.GenesisState) - is.precompile = is.setupERC20Precompile(is.tokenDenom, erc20Gen.TokenPairs) - is.precompileTwo = is.setupERC20Precompile(is.tokenDenomTwo, erc20Gen.TokenPairs) -} - -func TestIntegrationSuite(t *testing.T) { - is = new(IntegrationTestSuite) - - // Run Ginkgo integration tests - RegisterFailHandler(Fail) - RunSpecs(t, "ERC20 Extension Suite") -} - -var ( - revertContractAddr common.Address - gasLimit = uint64(5000000) - gasPrice = big.NewInt(800_000_000) -) - -var _ = Describe("ERC20 Extension -", func() { - var ( - // contractsData holds the addresses and ABIs for the different - // contract instances that are subject to testing here. - contractsData ContractsData - - allowanceCallerContract evmtypes.CompiledContract - revertCallerContract evmtypes.CompiledContract - erc20MinterV5Contract evmtypes.CompiledContract - - execRevertedCheck testutil.LogCheckArgs - failCheck testutil.LogCheckArgs - passCheck testutil.LogCheckArgs - ) - - BeforeEach(func() { - is.SetupTest() - - var err error - allowanceCallerContract, err = testdata.LoadERC20AllowanceCaller() - Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 allowance caller contract") - - erc20MinterV5Contract, err = testdata.LoadERC20MinterV5Contract() - Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 minter contract") - - revertCallerContract, err = testdata.LoadERC20TestCaller() - Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 allowance caller contract") - - sender := is.keyring.GetKey(0) - contractAddr, err := is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: allowanceCallerContract, - // NOTE: we're passing the precompile address to the constructor because that initiates the contract - // to make calls to the correct ERC20 precompile. - ConstructorArgs: []interface{}{is.precompile.Address()}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // commit the changes to update state (account nonce mostly) - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - - contractAddrTokenTwo, err := is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: allowanceCallerContract, - // NOTE: we're passing the precompile address to the constructor because that initiates the contract - // to make calls to the correct ERC20 precompile. - ConstructorArgs: []interface{}{is.precompileTwo.Address()}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // commit the changes to update state (account nonce mostly) - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - - erc20MinterBurnerAddr, err := is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: contracts.ERC20MinterBurnerDecimalsContract, - ConstructorArgs: []interface{}{ - "Xmpl", "Xmpl", uint8(6), - }, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter burner contract") - - // commit the changes to update state (account nonce mostly) - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - - ERC20MinterV5Addr, err := is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: erc20MinterV5Contract, - ConstructorArgs: []interface{}{ - "Xmpl", "Xmpl", - }, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter contract") - - // commit the changes to update state (account nonce mostly) - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - - erc20MinterV5CallerAddr, err := is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: allowanceCallerContract, - ConstructorArgs: []interface{}{ - ERC20MinterV5Addr, - }, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy ERC20 minter caller contract") - - // commit the changes to update state (account nonce mostly) - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - - // Store the data of the deployed contracts - contractsData = ContractsData{ - ownerPriv: sender.Priv, - contractData: map[CallType]ContractData{ - directCall: { - Address: is.precompile.Address(), - ABI: is.precompile.ABI, - }, - directCallToken2: { - Address: is.precompileTwo.Address(), - ABI: is.precompileTwo.ABI, - }, - contractCall: { - Address: contractAddr, - ABI: allowanceCallerContract.ABI, - }, - contractCallToken2: { - Address: contractAddrTokenTwo, - ABI: allowanceCallerContract.ABI, - }, - erc20Call: { - Address: erc20MinterBurnerAddr, - ABI: contracts.ERC20MinterBurnerDecimalsContract.ABI, - }, - erc20V5Call: { - Address: ERC20MinterV5Addr, - ABI: erc20MinterV5Contract.ABI, - }, - erc20V5CallerCall: { - Address: erc20MinterV5CallerAddr, - ABI: allowanceCallerContract.ABI, - }, - }, - } - - failCheck = testutil.LogCheckArgs{ABIEvents: is.precompile.Events} - execRevertedCheck = failCheck.WithErrContains("execution reverted") - passCheck = failCheck.WithExpPass(true) - - erc20Params := is.network.App.Erc20Keeper.GetParams(is.network.GetContext()) - Expect(len(erc20Params.NativePrecompiles)).To(Equal(1)) - Expect(common.HexToAddress(erc20Params.NativePrecompiles[0])).To(Equal(common.HexToAddress(testconstants.WEVMOSContractMainnet))) - - revertContractAddr, err = is.factory.DeployContract( - sender.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: revertCallerContract, - // NOTE: we're passing the precompile address to the constructor because that initiates the contract - // to make calls to the correct ERC20 precompile. - ConstructorArgs: []interface{}{common.HexToAddress(erc20Params.NativePrecompiles[0])}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy reverter contract") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to advance block") - }) - - Context("basic functionality -", func() { - When("sending tokens to contract", func() { - It("it should return error", func() { - sender := is.keyring.GetKey(0) - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - - // Fund account with some tokens - is.fundWithTokens(directCall, contractsData, sender.Addr, fundCoins) - - // Taking custom args from the table entry - txArgs := evmtypes.EvmTxArgs{} - txArgs.Amount = big.NewInt(int64(1000)) - precompileAddress := is.precompile.Address() - txArgs.To = &precompileAddress - - _, err := is.factory.ExecuteEthTx(sender.Priv, txArgs) - // Currently, this check pass because the erc20 precompile does - // not expose a fallback handler. Adding a fallback handler, the - // test should pass again because of the check on the message - // value in the precompile before the setup. - Expect(err.Error()).To(ContainSubstring(vm.ErrExecutionReverted.Error()), "precompile should not accept transfers") - }, - ) - }) - When("transferring tokens", func() { - DescribeTable("it should transfer tokens to a non-existing address", func(callType CallType, expGasUsedLowerBound int64, expGasUsedUpperBound int64) { - sender := is.keyring.GetKey(0) - receiver := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) - senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoins[0].Amount.BigInt()) - - transferCheck := passCheck.WithExpEvents(erc20.EventTypeTransfer) - - res, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: sender.AccAddr, expCoins: senderInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - - Expect(res.GasUsed > expGasUsedLowerBound).To(BeTrue(), "expected different gas used") - Expect(res.GasUsed < expGasUsedUpperBound).To(BeTrue(), "expected different gas used") - }, - // FIXME: The gas used on the precompile is much higher than on the EVM - Entry(" - direct call", directCall, int64(3_021_000), int64(3_022_000)), - Entry(" - through erc20 contract", erc20Call, int64(54_000), int64(54_500)), - Entry(" - through erc20 v5 contract", erc20V5Call, int64(52_000), int64(52_200)), - ) - - DescribeTable("it should transfer tokens to an existing address", func(callType CallType) { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetKey(1) - fundCoinsSender := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - fundCoinsReceiver := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 500)} - transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) - - // Fund accounts with some tokens - receiverInitialAmt := is.fundWithTokens(callType, contractsData, receiver.Addr, fundCoinsReceiver) - receiverInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, receiverInitialAmt)} - - senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoinsSender) - senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver.Addr, transferCoin.Amount.BigInt()) - - transferCheck := passCheck.WithExpEvents(erc20.EventTypeTransfer) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: sender.AccAddr, expCoins: senderInitialBalance.Sub(transferCoin)}, - {address: receiver.AccAddr, expCoins: receiverInitialBalance.Add(transferCoin)}, - }, - ) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because transferring using a caller contract - // is only supported through transferFrom method. - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should return an error trying to call from a smart contract", func(callType CallType) { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) - - // Fund account with some tokens - is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoin.Amount.BigInt()) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - // NOTE: we are not passing the direct call here because this test is specific to the contract calls - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should return an error if the sender does not have enough tokens", func(callType CallType) { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - - // Fund account with some tokens - senderInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) - senderInitialBalance := sdk.NewCoin(is.tokenDenom, senderInitialAmt) - - transferCoin := senderInitialBalance.Add(sdk.NewInt64Coin(is.tokenDenom, 100)) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferMethod, receiver, transferCoin.Amount.BigInt()) - - insufficientBalanceCheck := failCheck.WithErrContains( - erc20.ErrTransferAmountExceedsBalance.Error(), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientBalanceCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because this test is for direct calls only - - Entry(" - through erc20 contract", erc20Call), - // // TODO: The ERC20 V5 contract is raising the ERC-6093 standardized error which we are not as of yet - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - When("calling reverter contract", func() { - Context("in a direct call to the WEVMOS contract", func() { - var ( - args factory.CallArgs - txArgs evmtypes.EvmTxArgs - ) - BeforeEach(func() { - args = factory.CallArgs{ - ContractABI: revertCallerContract.ABI, - } - - txArgs = evmtypes.EvmTxArgs{ - To: &revertContractAddr, - GasLimit: gasLimit, - GasPrice: gasPrice, - } - }) - It("should transfer tokens", func() { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetKey(1) - amountToSend := big.NewInt(100) - - balRes, err := is.handler.GetBalanceFromBank(receiver.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - denomInitialBalance := balRes.Balance - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderInitialBalance := balRes.Balance - - args.MethodName = "transferWithRevert" - args.Args = []interface{}{ - receiver.Addr, - amountToSend, - false, - false, - } - txArgs.Amount = amountToSend - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - ) - res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) - Expect(err).To(BeNil()) - Expect(is.network.NextBlock()).To(BeNil()) - fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) - - Expect(is.network.NextBlock()).ToNot(HaveOccurred(), "failed to advance block") - - balRes, err = is.handler.GetBalanceFromBank(receiver.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - denomFinalBalance := balRes.Balance - Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(amountToSend.Int64())))) - - balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - contractBalance := balRes.Balance - Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) - - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderFinalBalance := balRes.Balance - denomSpent := fees.Add(math.NewIntFromBigInt(amountToSend)) - Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) - }, - ) - DescribeTable("it should revert token transfer from the WEVMOS contract", func(before bool, after bool) { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - amountToSend := big.NewInt(100) - balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomInitialBalance := balRes.Balance - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderInitialBalance := balRes.Balance - - args.MethodName = "transferWithRevert" - args.Args = []interface{}{ - receiver, - amountToSend, - before, - after, - } - txArgs.Amount = amountToSend - - res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, execRevertedCheck) - Expect(err).To(BeNil()) - Expect(is.network.NextBlock()).To(BeNil()) - - fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) - - // contract balance should remain unchanged - balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomFinalBalance := balRes.Balance - Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount)) - - balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - contractBalance := balRes.Balance - Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) - - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderFinalBalance := balRes.Balance - Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(fees))) - }, - Entry("revert before", true, false), - Entry("revert after", false, true), - ) - It("it should send token transfer and send from WEVMOS contract", func() { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - totalToSend := int64(350) - balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomInitialBalance := balRes.Balance - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderInitialBalance := balRes.Balance - - args.MethodName = "testTransferAndSend" - args.Args = []interface{}{ - receiver, - big.NewInt(100), - big.NewInt(100), - big.NewInt(150), - false, - false, - } - txArgs.Amount = big.NewInt(totalToSend) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - ) - res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) - Expect(err).To(BeNil()) - Expect(is.network.NextBlock()).To(BeNil()) - fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) - - // contract balance should remain unchanged - balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomFinalBalance := balRes.Balance - Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(totalToSend)))) - - balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - contractBalance := balRes.Balance - Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) - - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderFinalBalance := balRes.Balance - denomSpent := fees.AddRaw(totalToSend) - Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) - }, - ) - DescribeTable("it should revert token transfer and send from WEVMOS contract", func(before bool, after bool) { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomInitialBalance := balRes.Balance - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderInitialBalance := balRes.Balance - - args.MethodName = "testTransferAndSend" - args.Args = []interface{}{ - receiver, - big.NewInt(100), - big.NewInt(100), - big.NewInt(100), - before, - after, - } - txArgs.Amount = big.NewInt(300) - - res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, execRevertedCheck) - Expect(err).To(BeNil()) - Expect(is.network.NextBlock()).To(BeNil()) - fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) - - // contract balance should remain unchanged - balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomFinalBalance := balRes.Balance - Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount)) - - balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - contractBalance := balRes.Balance - Expect(contractBalance.Amount).To(Equal(math.ZeroInt())) - - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderFinalBalance := balRes.Balance - Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(fees))) - }, - Entry("revert before", true, false), - Entry("revert after", false, true), - ) - It("revert when transfer with try", func() { - sender := is.keyring.GetKey(0) - receiver := is.keyring.GetAddr(1) - amountToSend := big.NewInt(100) - balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomInitialBalance := balRes.Balance - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderInitialBalance := balRes.Balance - - args.MethodName = "transfersWithTry" - args.Args = []interface{}{ - receiver, - amountToSend, - amountToSend, - } - txArgs.Amount = big.NewInt(200) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - ) - res, _, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, args, transferCheck) - Expect(err).To(BeNil()) - Expect(is.network.NextBlock()).To(BeNil()) - fees := math.NewIntFromBigInt(gasPrice).MulRaw(res.GasUsed) - - balRes, err = is.handler.GetBalanceFromBank(receiver.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - denomFinalBalance := balRes.Balance - Expect(denomFinalBalance.Amount).To(Equal(denomInitialBalance.Amount.Add(math.NewInt(amountToSend.Int64())))) - - balRes, err = is.handler.GetBalanceFromBank(revertContractAddr.Bytes(), is.bondDenom) - Expect(err).To(BeNil()) - contractBalance := balRes.Balance - Expect(contractBalance.Amount.Int64()).To(Equal(amountToSend.Int64())) - - balRes, err = is.handler.GetBalanceFromBank(sender.AccAddr, is.bondDenom) - Expect(err).To(BeNil()) - senderFinalBalance := balRes.Balance - denomSpent := fees.AddRaw(amountToSend.Int64() + amountToSend.Int64()) - Expect(senderFinalBalance.Amount).To(Equal(senderInitialBalance.Amount.Sub(denomSpent))) - }) - }) - }) - - When("transferring tokens from another account", func() { - Context("in a direct call to the token contract", func() { - DescribeTable("it should transfer tokens from another account with a sufficient approval set", func(callType CallType) { - owner := is.keyring.GetKey(0) - spender := is.keyring.GetKey(1) - receiver := utiltx.GenerateAddress() - - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) - ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} - - // Set allowance - is.setupSendAuthzForContract(callType, contractsData, spender.Addr, owner.Priv, transferCoins) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoins[0].Amount.BigInt(), - ) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - auth.EventTypeApproval, - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to the chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - - // Check that the allowance was removed since we authorized only the transferred amount - is.ExpectNoSendAuthzForContract( - callType, contractsData, - spender.Addr, owner.Addr, - ) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because this test is for direct calls only - - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - When("the spender is the same as the sender", func() { - It("should transfer funds without the need for an approval when calling the EVM extension", func() { - owner := is.keyring.GetKey(0) - spender := owner - receiver := utiltx.GenerateAddress() - - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(directCall, contractsData, owner.Addr, fundCoins) - ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - directCall, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoins[0].Amount.BigInt(), - ) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, auth.EventTypeApproval, - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferMethod) - is.ExpectBalancesForContract( - directCall, contractsData, - []ExpectedBalance{ - {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - }) - - DescribeTable("it should transfer funds from the own account in case sufficient approval is set", func(callType CallType) { - owner := is.keyring.GetKey(0) - receiver := utiltx.GenerateAddress() - - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) - ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} - - // NOTE: Here we set up the allowance using the contract calls instead of the helper utils, - // because the `MsgGrant` used there doesn't allow the sender to be the same as the spender, - // but the ERC20 contracts do. - txArgs, approveArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.ApproveMethod, - owner.Addr, transferCoins[0].Amount.BigInt(), - ) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, _, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // create new block to commit the changes in the state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectSendAuthzForContract( - callType, contractsData, - owner.Addr, owner.Addr, transferCoins, - ) - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoins[0].Amount.BigInt(), - ) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - auth.EventTypeApproval, - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - - // Check that the allowance was removed since we authorized only the transferred amount - // FIXME: This is not working for the case where we transfer from the own account - // because the allowance is not removed on the SDK side. - is.ExpectNoSendAuthzForContract( - callType, contractsData, - owner.Addr, owner.Addr, - ) - }, - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - DescribeTable("it should return an error when the spender does not have enough allowance", func(callType CallType) { - owner := is.keyring.GetKey(0) - spender := is.keyring.GetKey(1) - receiver := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - transferCoin := sdk.NewInt64Coin(is.tokenDenom, 200) - - // Fund account with some tokens - is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) - // Set allowance - is.setupSendAuthzForContract( - callType, contractsData, - spender.Addr, owner.Priv, authzCoins, - ) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoin.Amount.BigInt(), - ) - - insufficientAllowanceCheck := failCheck.WithErrContains(erc20.ErrInsufficientAllowance.Error()) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(spender.Priv, txArgs, transferArgs, insufficientAllowanceCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because this test case only covers direct calls - - Entry(" - through erc20 contract", erc20Call), - - // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should return an error if there is no allowance set", func(callType CallType) { - sender := is.keyring.GetKey(0) - from := is.keyring.GetKey(1) - receiver := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoin := sdk.NewInt64Coin(is.tokenDenom, 100) - - // Fund account with some tokens - is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - from.Addr, receiver, transferCoin.Amount.BigInt(), - ) - - insufficientAllowanceCheck := failCheck.WithErrContains( - erc20.ErrInsufficientAllowance.Error(), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientAllowanceCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because this test case only covers direct calls - - Entry(" - through erc20 contract", erc20Call), - - // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should return an error if the sender does not have enough tokens", func(callType CallType) { - sender := is.keyring.GetKey(0) - from := is.keyring.GetKey(1) - receiver := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - - // Fund account with some tokens - senderInitialAmt := is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) - senderInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, senderInitialAmt)} - transferCoins := senderInitialBalance.Add(sdk.NewInt64Coin(is.tokenDenom, 100)) - - // Set allowance - is.setupSendAuthzForContract( - callType, contractsData, - sender.Addr, from.Priv, transferCoins, - ) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TransferFromMethod, from.Addr, receiver, transferCoins[0].Amount.BigInt()) - - insufficientBalanceCheck := failCheck.WithErrContains( - erc20.ErrTransferAmountExceedsBalance.Error(), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, transferArgs, insufficientBalanceCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the contract call here because this test case only covers direct calls - - Entry(" - through erc20 contract", erc20Call), - - // TODO: the ERC20 V5 contract is raising the ERC-6093 standardized error which we are not using as of yet - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - Context("in a call from another smart contract to the token contract", func() { - DescribeTable("it should transfer tokens with a sufficient approval set", func(callType CallType) { - owner := is.keyring.GetKey(0) - receiver := utiltx.GenerateAddress() - fundCoin := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // NOTE: the spender will be the contract address - spender := contractsData.GetContractData(callType).Address - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoin) - ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} - - // Set allowance - is.setupSendAuthzForContract( - callType, contractsData, - spender, owner.Priv, transferCoins, - ) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoins[0].Amount.BigInt(), - ) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - auth.EventTypeApproval, - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(owner.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - - // Check that the allowance was removed since we authorized only the transferred amount - is.ExpectNoSendAuthzForContract( - callType, contractsData, - spender, owner.Addr, - ) - }, - // Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - // NOTE: we are not passing the erc20 contract call here because this is supposed to - // test external contract calls - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should transfer funds with a sufficient allowance and triggered from another account", func(callType CallType) { - msgSender := is.keyring.GetKey(0) - owner := is.keyring.GetKey(1) - receiver := utiltx.GenerateAddress() - - // NOTE: the spender will be the contract address - spender := contractsData.GetContractData(callType).Address - - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 300)} - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(callType, contractsData, owner.Addr, fundCoins) - ownerInitialBalance := sdk.Coins{sdk.NewCoin(is.tokenDenom, ownerInitialAmt)} - - // Set allowance - is.setupSendAuthzForContract( - callType, contractsData, - spender, owner.Priv, transferCoins, - ) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - owner.Addr, receiver, transferCoins[0].Amount.BigInt(), - ) - - transferCheck := passCheck.WithExpEvents( - erc20.EventTypeTransfer, - auth.EventTypeApproval, - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(msgSender.Priv, txArgs, transferArgs, transferCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, erc20.TransferFromMethod) - is.ExpectBalancesForContract( - callType, contractsData, - []ExpectedBalance{ - {address: owner.AccAddr, expCoins: ownerInitialBalance.Sub(transferCoins...)}, - {address: receiver.Bytes(), expCoins: transferCoins}, - }, - ) - - // Check that the allowance was removed since we authorized only the transferred amount - is.ExpectNoSendAuthzForContract( - callType, contractsData, - spender, owner.Addr, - ) - }, - // NOTE: we are not passing the direct call here because this test is specific to the contract calls - - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should return an error when the spender does not have enough allowance", func(callType CallType) { - from := is.keyring.GetKey(0) - receiver := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 400)} - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - transferCoin := sdk.NewInt64Coin(is.tokenDenom, 300) - - // NOTE: the spender will be the contract address - spender := contractsData.GetContractData(callType).Address - - // Fund account with some tokens - is.fundWithTokens(callType, contractsData, from.Addr, fundCoins) - - // Set allowance - is.setupSendAuthzForContract(callType, contractsData, spender, from.Priv, authzCoins) - - // Transfer tokens - txArgs, transferArgs := is.getTxAndCallArgs( - callType, contractsData, - erc20.TransferFromMethod, - from.Addr, receiver, transferCoin.Amount.BigInt(), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(from.Priv, txArgs, transferArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - // NOTE: we are not passing the direct call here because this test is for contract calls only - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - }) - }) - - When("querying balance", func() { - DescribeTable("it should return an existing balance", func(callType CallType) { - sender := is.keyring.GetKey(0) - addedAmt := big.NewInt(100) - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, addedAmt.Int64())} - - // Fund account with some tokens - ownerInitialAmt := is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) - - // Query the balance - txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, sender.Addr) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var balance *big.Int - err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(math.NewIntFromBigInt(balance)).To(Equal(ownerInitialAmt), "expected different balance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should return zero if balance only exists for other tokens", func(callType CallType) { - sender := is.keyring.GetKey(0) - address := utiltx.GenerateAddress() - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 100)} - - // Fund account with some tokens - err := is.factory.FundAccount(is.keyring.GetKey(0), sender.AccAddr, fundCoins) - Expect(err).ToNot(HaveOccurred(), "failed to fund account") - Expect(is.network.NextBlock()).To(BeNil()) - - // Query the balance - txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, address) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var balance *big.Int - err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(balance.Int64()).To(BeZero(), "expected zero balance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contracts - // only support the actual token denomination and don't know of other balances. - ) - - DescribeTable("it should return zero if the account does not exist", func(callType CallType) { - sender := is.keyring.GetKey(0) - address := utiltx.GenerateAddress() - - // Query the balance - txArgs, balancesArgs := is.getTxAndCallArgs(callType, contractsData, erc20.BalanceOfMethod, address) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, balancesArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var balance *big.Int - err = is.precompile.UnpackIntoInterface(&balance, erc20.BalanceOfMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(balance.Int64()).To(BeZero(), "expected zero balance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - }) - - When("querying allowance", func() { - DescribeTable("it should return an existing allowance", func(callType CallType) { - grantee := utiltx.GenerateAddress() - granter := is.keyring.GetKey(0) - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - is.setupSendAuthzForContract(callType, contractsData, grantee, granter.Priv, authzCoins) - - txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance).To(Equal(authzCoins[0].Amount.BigInt()), "expected different allowance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - When("querying the allowance for the own address", func() { - // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, - // querying allowance and reducing allowance on a transferFrom transaction is not possible without - // changes to the Cosmos SDK. - // - // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 - It("should return the maxUint256 value when calling the EVM extension", func() { - grantee := is.keyring.GetAddr(0) - granter := is.keyring.GetKey(0) - - txArgs, allowanceArgs := is.getTxAndCallArgs(directCall, contractsData, auth.AllowanceMethod, grantee, grantee) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance).To(Equal(abi.MaxUint256), "expected different allowance") - }) - - // NOTE: Since it's possible to set an allowance for the own address with the Solidity ERC20 contracts, - // we describe this case here for completion purposes, to describe the difference in behavior. - DescribeTable("should return the actual allowance value when calling the ERC20 contract", func(callType CallType) { - granter := is.keyring.GetKey(0) - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - is.setupSendAuthzForContract(callType, contractsData, granter.Addr, granter.Priv, authzCoins) - - txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, granter.Addr) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance).To(Equal(authzCoins.AmountOf(is.tokenDenom).BigInt()), "expected different allowance") - }, - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - DescribeTable("it should return zero if no allowance exists", func(callType CallType) { - grantee := is.keyring.GetAddr(1) - granter := is.keyring.GetKey(0) - - txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should return zero if an allowance exists for other tokens", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 100)} - - is.setupSendAuthz(grantee.AccAddr, granter.Priv, authzCoins) - - txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee.Addr) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("it should return zero if the account does not exist", func(callType CallType) { - grantee := utiltx.GenerateAddress() - granter := is.keyring.GetKey(0) - - txArgs, allowanceArgs := is.getTxAndCallArgs(callType, contractsData, auth.AllowanceMethod, granter.Addr, grantee) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, allowanceArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var allowance *big.Int - err = is.precompile.UnpackIntoInterface(&allowance, auth.AllowanceMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(allowance.Int64()).To(BeZero(), "expected zero allowance") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - }) - - When("querying total supply", func() { - DescribeTable("it should return the total supply", func(callType CallType) { - sender := is.keyring.GetKey(0) - expSupply := big.NewInt(100) - fundCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, expSupply.Int64())} - - // Fund account with some tokens - is.fundWithTokens(callType, contractsData, sender.Addr, fundCoins) - - // if is native coin, get expSupply from the bank mod - if slices.Contains(nativeCallTypes, callType) { - qc := is.network.GetBankClient() - qRes, err := qc.SupplyOf(is.network.GetContext(), &banktypes.QuerySupplyOfRequest{Denom: is.tokenDenom}) - Expect(err).To(BeNil()) - Expect(qRes).NotTo(BeNil()) - expSupply = qRes.Amount.Amount.BigInt() - } - - // Query the balance - txArgs, supplyArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TotalSupplyMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, supplyArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var supply *big.Int - err = is.precompile.UnpackIntoInterface(&supply, erc20.TotalSupplyMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(supply).To(Equal(expSupply), "expected different supply") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should return zero if no tokens exist", func(callType CallType) { - sender := is.keyring.GetKey(0) - txArgs, supplyArgs := is.getTxAndCallArgs(callType, contractsData, erc20.TotalSupplyMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, supplyArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var supply *big.Int - err = is.precompile.UnpackIntoInterface(&supply, erc20.TotalSupplyMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(supply.Int64()).To(BeZero(), "expected zero supply") - }, - Entry(" - direct call", directCallToken2), - Entry(" - through contract", contractCallToken2), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - }) - - When("approving an allowance", func() { - Context("in a call to the token contract", func() { - DescribeTable("it should approve an allowance", func(callType CallType) { - grantee := is.keyring.GetKey(0) - granter := is.keyring.GetKey(1) - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, transferCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter.Addr, transferCoins, - ) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should add a new spend limit to an existing allowance with a different token", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} - tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // set up a previous authorization - is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check allowance contains both spend limits - is.expectSendAuthz(grantee.AccAddr, granter.AccAddr, bondCoins.Add(tokenCoins...)) - }, - Entry(" - direct call", directCall), - - // NOTE 2: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("it should set the new spend limit for an existing allowance with the same token", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} - tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - doubleTokenCoin := sdk.NewInt64Coin(is.tokenDenom, 200) - - // set up a previous authorization - is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins.Add(doubleTokenCoin)) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check allowance contains both spend limits - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, bondCoins.Add(tokenCoins...)) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should remove the token from the spend limit of an existing authorization when approving zero", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} - tokenCoin := sdk.NewInt64Coin(is.tokenDenom, 100) - - // set up a previous authorization - is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins.Add(tokenCoin)) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - // Check allowance contains only the spend limit in network denomination - is.expectSendAuthz(grantee.AccAddr, granter.AccAddr, bondCoins) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("it should delete the authorization when approving zero with no other spend limits", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // set up a previous authorization - is.setupSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Priv, tokenCoins) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check allowance was deleted - is.expectNoSendAuthz(grantee.AccAddr, granter.AccAddr) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("it should no-op if approving 0 and no allowance exists", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - - // We are expecting an approval to be made, but no authorization stored since it's 0 - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check still no authorization exists - is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - When("the grantee is the same as the granter", func() { - // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, - // querying allowance and reducing allowance on a transferFrom transaction is not possible without - // changes to the Cosmos SDK. - // - // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 - It("should return an error when calling the EVM extension", func() { - grantee := is.keyring.GetKey(0) - granter := is.keyring.GetKey(0) - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs( - directCall, contractsData, - auth.ApproveMethod, - grantee.Addr, authzCoins[0].Amount.BigInt(), - ) - - spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, spenderIsOwnerCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectNoSendAuthzForContract( - directCall, contractsData, - grantee.Addr, granter.Addr, - ) - }) - - DescribeTable("it should create an allowance", func(callType CallType) { - grantee := is.keyring.GetKey(0) - granter := is.keyring.GetKey(0) - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.ApproveMethod, - grantee.Addr, authzCoins[0].Amount.BigInt(), - ) - - approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approvalCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter.Addr, authzCoins, - ) - }, - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - DescribeTable("it should return an error if approving 0 and allowance only exists for other tokens", func(callType CallType) { - grantee := is.keyring.GetKey(1) - granter := is.keyring.GetKey(0) - bondCoins := sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} - - // set up a previous authorization - is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - - notFoundCheck := failCheck.WithErrContains( - fmt.Sprintf(erc20.ErrNoAllowanceForToken, is.tokenDenom), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, notFoundCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - }) - - // NOTE: We have to split the tests for contract calls into a separate context because - // when approving through a smart contract, the approval is created between the contract address and the - // grantee, instead of the sender address and the grantee. - Context("in a contract call", func() { - DescribeTable("it should approve an allowance", func(callType CallType) { - sender := is.keyring.GetKey(0) - grantee := is.keyring.GetKey(1) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - transferCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, transferCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check allowance - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter, transferCoins, - ) - }, - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should set the new spend limit for an existing allowance with the same token", func(callType CallType) { - sender := is.keyring.GetKey(0) - grantee := is.keyring.GetKey(1) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - initialAmount := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - newAmount := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - - // Set up a first approval - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, initialAmount[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - - // Set up a second approval which should overwrite the initial one - txArgs, approveArgs = is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, newAmount[0].Amount.BigInt()) - approveCheck = passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err = is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // Check allowance has been updated - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter, newAmount, - ) - }, - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should delete the authorization when approving zero with no other spend limits", func(callType CallType) { - sender := is.keyring.GetKey(0) - grantee := is.keyring.GetKey(1) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - tokenCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // set up a previous authorization - // - // TODO: refactor using helper - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, tokenCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - - // Approve allowance - txArgs, approveArgs = is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - _, ethRes, err = is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - - // Check allowance was deleted from the keeper / is returning 0 for smart contracts - is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter) - }, - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - DescribeTable("it should no-op if approving 0 and no allowance exists", func(callType CallType) { - sender := is.keyring.GetKey(0) - grantee := is.keyring.GetKey(1) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs(callType, contractsData, auth.ApproveMethod, grantee.Addr, common.Big0) - - // We are expecting an approval event to be emitted, but no authorization to be stored - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - // Check still no authorization exists - is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter) - }, - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - - When("the grantee is the same as the granter", func() { - // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, - // querying allowance and reducing allowance on a transferFrom transaction is not possible without - // changes to the Cosmos SDK. - // - // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 - It("should return an error when calling the EVM extension", func() { - callType := contractCall - sender := is.keyring.GetKey(0) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - grantee := granter - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.ApproveMethod, - grantee, authzCoins[0].Amount.BigInt(), - ) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectNoSendAuthzForContract( - callType, contractsData, - grantee, granter, - ) - }) - - DescribeTable("it should create an allowance when calling an ERC20 Solidity contract", func(callType CallType) { - sender := is.keyring.GetKey(0) - granter := contractsData.GetContractData(callType).Address // the granter will be the contract address - grantee := granter - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // Approve allowance - txArgs, approveArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.ApproveMethod, - grantee, authzCoins[0].Amount.BigInt(), - ) - - approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(sender.Priv, txArgs, approveArgs, approvalCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee, granter, authzCoins, - ) - }, - Entry(" - through erc20 v5 caller contract", erc20V5CallerCall), - ) - }) - }) - }) - }) - - Context("metadata query -", func() { - Context("for a token without registered metadata", func() { - BeforeEach(func() { - // Deploy ERC20NoMetadata contract for this test - erc20NoMetadataContract, err := testdata.LoadERC20NoMetadataContract() - Expect(err).ToNot(HaveOccurred(), "failed to load contract") - - erc20NoMetadataAddr, err := is.factory.DeployContract( - is.keyring.GetPrivKey(0), - evmtypes.EvmTxArgs{}, - factory.ContractDeploymentData{ - Contract: erc20NoMetadataContract, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // NOTE: update the address but leave the ABI as it is, so that the ABI includes - // the metadata methods but the contract doesn't have them. - contractsData.contractData[erc20Call] = ContractData{ - Address: erc20NoMetadataAddr, - ABI: contracts.ERC20MinterBurnerDecimalsContract.ABI, - } - }) - - DescribeTable("querying the name should return an error", func(callType CallType) { - txArgs, nameArgs := is.getTxAndCallArgs(callType, contractsData, erc20.NameMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, nameArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors - ) - - DescribeTable("querying the symbol should return an error", func(callType CallType) { - txArgs, symbolArgs := is.getTxAndCallArgs(callType, contractsData, erc20.SymbolMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, symbolArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors - ) - - DescribeTable("querying the decimals should return an error", func(callType CallType) { - txArgs, decimalsArgs := is.getTxAndCallArgs(callType, contractsData, erc20.DecimalsMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, decimalsArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 contract", erc20Call), // NOTE: we're passing the ERC20 contract call here which was adjusted to point to a contract without metadata to expect the same errors - ) - }) - - Context("for a token with available metadata", func() { - const ( - expSymbol = "Xmpl" - expDecimals = uint8(18) - ) - - var ( - erc20Addr common.Address - expName string - ) - - BeforeEach(func() { - erc20Addr = contractsData.GetContractData(erc20V5Call).Address - expName = erc20types.CreateDenom(erc20Addr.String()) - - // Register ERC20 token pair for this test - tokenPairs, err := integrationutils.RegisterERC20(is.factory, is.network, integrationutils.ERC20RegistrationData{ - Addresses: []string{erc20Addr.Hex()}, - ProposerPriv: is.keyring.GetPrivKey(0), - }) - Expect(err).ToNot(HaveOccurred(), "failed to register ERC20 token") - Expect(tokenPairs).To(HaveLen(1)) - - // overwrite the other precompile with this one, so that the test utils like is.getTxAndCallArgs still work. - is.precompile, err = setupNewERC20PrecompileForTokenPair(is.keyring.GetPrivKey(0), is.network, is.factory, tokenPairs[0]) - Expect(err).ToNot(HaveOccurred(), "failed to set up erc20 precompile") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // update this in the global contractsData - contractsData.contractData[directCall] = ContractData{ - Address: is.precompile.Address(), - ABI: is.precompile.ABI, - } - - // Deploy contract calling the ERC20 precompile - callerAddr, err := is.factory.DeployContract( - is.keyring.GetPrivKey(0), - evmtypes.EvmTxArgs{}, - factory.ContractDeploymentData{ - Contract: allowanceCallerContract, - ConstructorArgs: []interface{}{ - is.precompile.Address(), - }, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - contractsData.contractData[contractCall] = ContractData{ - Address: callerAddr, - ABI: allowanceCallerContract.ABI, - } - }) - - DescribeTable("querying the name should return the name", func(callType CallType) { - txArgs, nameArgs := is.getTxAndCallArgs(callType, contractsData, erc20.NameMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, nameArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var name string - err = is.precompile.UnpackIntoInterface(&name, erc20.NameMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(name).To(Equal(expName), "expected different name") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("querying the symbol should return the symbol", func(callType CallType) { - txArgs, symbolArgs := is.getTxAndCallArgs(callType, contractsData, erc20.SymbolMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, symbolArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var symbol string - err = is.precompile.UnpackIntoInterface(&symbol, erc20.SymbolMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(symbol).To(Equal(expSymbol), "expected different symbol") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("querying the decimals should return the decimals", func(callType CallType) { - txArgs, decimalsArgs := is.getTxAndCallArgs(callType, contractsData, erc20.DecimalsMethod) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(is.keyring.GetPrivKey(0), txArgs, decimalsArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - var decimals uint8 - err = is.precompile.UnpackIntoInterface(&decimals, erc20.DecimalsMethod, ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "failed to unpack result") - Expect(decimals).To(Equal(expDecimals), "expected different decimals") - }, - Entry(" - direct call", directCall), - Entry(" - through contract", contractCall), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - }) - - Context("allowance adjustments -", func() { - var ( - grantee keyring.Key - granter keyring.Key - ) - - BeforeEach(func() { - // Deploying the contract which has the increase / decrease allowance methods - contractAddr, err := is.factory.DeployContract( - is.keyring.GetPrivKey(0), - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: allowanceCallerContract, - ConstructorArgs: []interface{}{is.precompile.Address()}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - contractsData.contractData[erc20CallerCall] = ContractData{ - Address: contractAddr, - ABI: allowanceCallerContract.ABI, - } - - grantee = is.keyring.GetKey(0) - granter = is.keyring.GetKey(1) - }) - - When("the grantee is the same as the granter", func() { - // NOTE: We differ in behavior from the ERC20 calls here, because the full logic for approving, - // querying allowance and reducing allowance on a transferFrom transaction is not possible without - // changes to the Cosmos SDK. - // - // For reference see this comment: https://github.com/evmos/evmos/pull/2088#discussion_r1407646217 - Context("increasing allowance", func() { - It("should return an error when calling the EVM extension", func() { - granter := is.keyring.GetKey(0) - grantee := granter - - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs( - directCall, contractsData, - auth.IncreaseAllowanceMethod, - grantee.Addr, authzCoins[0].Amount.BigInt(), - ) - - spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, spenderIsOwnerCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectNoSendAuthzForContract( - directCall, contractsData, - grantee.Addr, granter.Addr, - ) - }) - - DescribeTable("it should create an allowance if none existed before", func(callType CallType) { - granter := is.keyring.GetKey(0) - grantee := granter - - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.IncreaseAllowanceMethod, - grantee.Addr, authzCoins[0].Amount.BigInt(), - ) - - approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approvalCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter.Addr, authzCoins, - ) - }, - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - Context("decreasing allowance", func() { - It("should return an error when calling the EVM extension", func() { - granter := is.keyring.GetKey(0) - grantee := granter - - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, decreaseArgs := is.getTxAndCallArgs( - directCall, contractsData, - auth.DecreaseAllowanceMethod, - grantee.Addr, authzCoins[0].Amount.BigInt(), - ) - - spenderIsOwnerCheck := failCheck.WithErrContains(erc20.ErrSpenderIsOwner.Error()) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, spenderIsOwnerCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - is.ExpectNoSendAuthzForContract( - directCall, contractsData, - grantee.Addr, granter.Addr, - ) - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - }) - - DescribeTable("it should decrease an existing allowance", func(callType CallType) { - granter := is.keyring.GetKey(0) - grantee := granter - - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 200)} - decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - is.setupSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter.Priv, authzCoins, - ) - - txArgs, decreaseArgs := is.getTxAndCallArgs( - callType, contractsData, - auth.DecreaseAllowanceMethod, - grantee.Addr, decreaseCoins[0].Amount.BigInt(), - ) - - approvalCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approvalCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract( - callType, contractsData, - grantee.Addr, granter.Addr, decreaseCoins, - ) - }, - Entry(" - through erc20 contract", erc20Call), - Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - }) - - When("no allowance exists", func() { - DescribeTable("decreasing the allowance should return an error", func(callType CallType) { - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) - - notFoundCheck := execRevertedCheck - if callType == directCall { - notFoundCheck = failCheck.WithErrContains( - fmt.Sprintf(auth.ErrAuthzDoesNotExistOrExpired, erc20.SendMsgURL, grantee.Addr.String()), - ) - } - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, notFoundCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - - // NOTE: We have to split between direct and contract calls here because the ERC20 behavior - // for approvals is different, so we expect different authorizations here - Context("in direct calls", func() { - DescribeTable("increasing the allowance should create a new authorization", func(callType CallType) { - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.ApproveMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - Context("in contract calls", func() { - DescribeTable("increasing the allowance should create a new authorization", func(callType CallType) { - contractAddr := contractsData.GetContractData(callType).Address - authzCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, contractAddr, authzCoins) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - }) - }) - - When("an allowance exists for other tokens", func() { - var bondCoins sdk.Coins - - BeforeEach(func() { - bondCoins = sdk.Coins{sdk.NewInt64Coin(is.network.GetBaseDenom(), 200)} - is.setupSendAuthz(grantee.AccAddr, granter.Priv, bondCoins) - }) - - DescribeTable("increasing the allowance should add the token to the spend limit", func(callType CallType) { - increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, bondCoins.Add(increaseCoins...)) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("decreasing the allowance should return an error", func(callType CallType) { - decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - - notFoundCheck := execRevertedCheck - if callType == directCall { - notFoundCheck = failCheck.WithErrContains( - fmt.Sprintf(erc20.ErrNoAllowanceForToken, is.tokenDenom), - ) - } - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, notFoundCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - }) - - When("an allowance exists for the same token", func() { - var authzCoins sdk.Coins - - BeforeEach(func() { - authzCoins = sdk.NewCoins( - sdk.NewInt64Coin(is.network.GetBaseDenom(), 100), - sdk.NewInt64Coin(is.tokenDenom, 200), - ) - - is.setupSendAuthz(grantee.AccAddr, granter.Priv, authzCoins) - }) - - DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { - increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Add(increaseCoins...)) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { - decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Sub(decreaseCoins...)) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { - maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("decreasing the allowance to zero should remove the token from the spend limit", func(callType CallType) { - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) - - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // Check that only the spend limit in the network denomination remains - bondDenom := is.network.GetBaseDenom() - expCoins := sdk.Coins{sdk.NewCoin(bondDenom, authzCoins.AmountOf(bondDenom))} - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, expCoins) - }, - Entry(" - direct call", directCall), - // NOTE: we are not passing the erc20 contract call here because the ERC20 contract - // only supports the actual token denomination and doesn't know of other allowances. - ) - - DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { - decreaseCoins := sdk.Coins{sdk.NewCoin(is.tokenDenom, authzCoins.AmountOf(is.tokenDenom).AddRaw(100))} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - belowZeroCheck := failCheck.WithErrContains(erc20.ErrDecreasedAllowanceBelowZero.Error()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, belowZeroCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - // Check that the allowance was not changed - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) - }, - Entry(" - direct call", directCall), - ) - }) - - When("an allowance exists for only the same token", func() { - // NOTE: we have to split between direct and contract calls here because the ERC20 contract - // handles the allowance differently by creating an approval between the contract and the grantee, instead - // of the message sender and the grantee, so we expect different authorizations. - Context("in direct calls", func() { - var authzCoins sdk.Coins - - BeforeEach(func() { - authzCoins = sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - // NOTE: We set up the standard authorization here for the authz keeper and then also - // set up the authorization for the ERC20 contract, so that we can test both. - is.setupSendAuthzForContract(directCall, contractsData, grantee.Addr, granter.Priv, authzCoins) - is.setupSendAuthzForContract(erc20Call, contractsData, grantee.Addr, granter.Priv, authzCoins) - }) - - DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { - increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Add(increaseCoins...)) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { - decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 50)} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins.Sub(decreaseCoins...)) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("decreasing the allowance to zero should delete the authorization", func(callType CallType) { - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { - decreaseAmount := authzCoins.AmountOf(is.tokenDenom).AddRaw(100) - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseAmount.BigInt()) - - belowZeroCheck := failCheck.WithErrContains(erc20.ErrDecreasedAllowanceBelowZero.Error()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, decreaseArgs, belowZeroCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - // Check that the allowance was not changed - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - - DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { - maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, increaseArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - // Check that the allowance was not changed - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granter.Addr, authzCoins) - }, - Entry(" - direct call", directCall), - Entry(" - through erc20 contract", erc20Call), - // NOTE: The ERC20 V5 contract does not contain these methods - // Entry(" - through erc20 v5 contract", erc20V5Call), - ) - }) - - Context("in contract calls", func() { - var ( - authzCoins sdk.Coins - grantee keyring.Key - ) - - BeforeEach(func() { - authzCoins = sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - grantee = is.keyring.GetKey(1) - callerContractAddr := contractsData.GetContractData(contractCall).Address - erc20CallerContractAddr := contractsData.GetContractData(erc20CallerCall).Address - - // NOTE: Here we create an authorization between the contract and the grantee for both contracts. - // This is different from the direct calls, where the authorization is created between the - // message sender and the grantee. - txArgs, approveArgs := is.getTxAndCallArgs(contractCall, contractsData, auth.ApproveMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, _, err := is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectSendAuthzForContract(contractCall, contractsData, grantee.Addr, callerContractAddr, authzCoins) - - // Create the authorization for the ERC20 caller contract - txArgs, approveArgs = is.getTxAndCallArgs(erc20CallerCall, contractsData, auth.ApproveMethod, grantee.Addr, authzCoins[0].Amount.BigInt()) - _, _, err = is.factory.CallContractAndCheckLogs(granter.Priv, txArgs, approveArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectSendAuthzForContract(erc20CallerCall, contractsData, grantee.Addr, erc20CallerContractAddr, authzCoins) - }) - - DescribeTable("increasing the allowance should increase the spend limit", func(callType CallType) { //nolint:dupl - senderPriv := is.keyring.GetPrivKey(0) - granterAddr := contractsData.GetContractData(callType).Address - increaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 100)} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, increaseCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, increaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.IncreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins.Add(increaseCoins...)) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - - DescribeTable("increasing the allowance beyond the max uint256 value should return an error", func(callType CallType) { - senderPriv := is.keyring.GetPrivKey(0) - granterAddr := contractsData.GetContractData(callType).Address - maxUint256Coins := sdk.Coins{sdk.NewCoin(is.tokenDenom, math.NewIntFromBigInt(abi.MaxUint256))} - - txArgs, increaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.IncreaseAllowanceMethod, grantee.Addr, maxUint256Coins[0].Amount.BigInt()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, increaseArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - // Check that the allowance was not changed - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - - DescribeTable("decreasing the allowance should decrease the spend limit", func(callType CallType) { //nolint:dupl - senderPriv := is.keyring.GetPrivKey(0) - granterAddr := contractsData.GetContractData(callType).Address - decreaseCoins := sdk.Coins{sdk.NewInt64Coin(is.tokenDenom, 50)} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins.Sub(decreaseCoins...)) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - - DescribeTable("decreasing the allowance to zero should delete the authorization", func(callType CallType) { - senderPriv := is.keyring.GetPrivKey(0) - granterAddr := contractsData.GetContractData(callType).Address - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, authzCoins.AmountOf(is.tokenDenom).BigInt()) - approveCheck := passCheck.WithExpEvents(auth.EventTypeApproval) - _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - - // commit the changes to state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - is.ExpectTrueToBeReturned(ethRes, auth.DecreaseAllowanceMethod) - is.ExpectNoSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - - DescribeTable("decreasing the allowance below zero should return an error", func(callType CallType) { - senderPriv := is.keyring.GetPrivKey(0) - granterAddr := contractsData.GetContractData(callType).Address - decreaseCoins := sdk.Coins{sdk.NewCoin(is.tokenDenom, authzCoins.AmountOf(is.tokenDenom).AddRaw(100))} - - txArgs, decreaseArgs := is.getTxAndCallArgs(callType, contractsData, auth.DecreaseAllowanceMethod, grantee.Addr, decreaseCoins[0].Amount.BigInt()) - _, ethRes, err := is.factory.CallContractAndCheckLogs(senderPriv, txArgs, decreaseArgs, execRevertedCheck) - Expect(err).ToNot(HaveOccurred(), "unexpected result calling contract") - Expect(ethRes).To(BeNil(), "expected empty result") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") - - // Check that the allowance was not changed - is.ExpectSendAuthzForContract(callType, contractsData, grantee.Addr, granterAddr, authzCoins) - }, - Entry(" - contract call", contractCall), - Entry(" - through erc20 caller contract", erc20CallerCall), - ) - }) - }) - }) -}) - -var _ = Describe("ERC20 Extension migration Flows -", func() { - When("migrating an existing ERC20 token", func() { - var ( - contractData ContractsData - erc20MinterV5Contract evmtypes.CompiledContract - - tokenDenom = "xmpl" - tokenName = "Xmpl" - tokenSymbol = strings.ToUpper(tokenDenom) - - supply = sdk.NewInt64Coin(tokenDenom, 1000000000000000000) - ) - - BeforeEach(func() { - is.SetupTest() - - var err error - erc20MinterV5Contract, err = testdata.LoadERC20MinterV5Contract() - Expect(err).ToNot(HaveOccurred(), "failed to load ERC20 minter contract") - - contractOwner := is.keyring.GetKey(0) - - // Deploy an ERC20 contract - erc20Addr, err := is.factory.DeployContract( - contractOwner.Priv, - evmtypes.EvmTxArgs{}, // NOTE: passing empty struct to use default values - factory.ContractDeploymentData{ - Contract: erc20MinterV5Contract, - ConstructorArgs: []interface{}{ - tokenName, tokenSymbol, - }, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy contract") - - // NOTE: We need to overwrite the information in the contractData here for this specific - // deployed contract. - contractData = ContractsData{ - ownerPriv: contractOwner.Priv, - contractData: map[CallType]ContractData{ - erc20V5Call: { - Address: erc20Addr, - ABI: erc20MinterV5Contract.ABI, - }, - }, - } - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to commit block") - - // Register the deployed erc20 contract as a token pair - _, err = integrationutils.RegisterERC20(is.factory, is.network, integrationutils.ERC20RegistrationData{ - Addresses: []string{erc20Addr.Hex()}, - ProposerPriv: contractOwner.Priv, - }) - Expect(err).ToNot(HaveOccurred(), "failed to register ERC20 token") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "failed to commit block") - - // Mint the supply of tokens - err = is.MintERC20(erc20V5Call, contractData, contractOwner.Addr, supply.Amount.BigInt()) - Expect(err).ToNot(HaveOccurred(), "failed to mint tokens") - - // Check that the supply was minted - is.ExpectBalancesForERC20(erc20V5Call, contractData, []ExpectedBalance{{ - address: contractOwner.AccAddr, - expCoins: sdk.Coins{supply}, - }}) - }) - - It("should migrate the full token balance to the bank module", func() { - // TODO: implement test on follow-up PR - Skip("will be addressed on follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - }) - - When("migrating an extended ERC20 token (e.g. ERC20Votes)", func() { - It("should migrate the full token balance to the bank module", func() { - // TODO: make sure that extended tokens are compatible with the ERC20 extensions - Skip("not included in first tranche") - - Expect(true).To(BeFalse(), "not implemented") - }) - }) - - When("running the migration logic for a set of existing ERC20 tokens", func() { - BeforeEach(func() { - // TODO: Add some ERC20 tokens and then run migration logic - // TODO: check here that the balance cannot be queried from the bank keeper before migrating the token - }) - - It("should add and enable the corresponding EVM extensions", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - - It("should be possible to query the balances through the bank module", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - - It("should return all tokens when querying all balances for an account", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - }) - - When("registering a native IBC coin", func() { - BeforeEach(func() { - // TODO: Add some IBC coins, register the token pair and then run migration logic - }) - - It("should add the corresponding EVM extensions", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - - It("should be possible to query the balances using an EVM transaction", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - }) - - When("using Evmos (not wEvmos) in smart contracts", func() { - It("should be using straight Evmos for sending funds in smart contracts", func() { - Skip("will be addressed in follow-up PR") - - Expect(true).To(BeFalse(), "not implemented") - }) - }) -}) diff --git a/precompiles/erc20/setup_test.go b/precompiles/erc20/setup_test.go index c6db9cc4..50650d6c 100644 --- a/precompiles/erc20/setup_test.go +++ b/precompiles/erc20/setup_test.go @@ -3,11 +3,10 @@ package erc20 import ( "testing" - erc20precompile "github.com/evmos/os/precompiles/erc20" "github.com/evmos/os/testutil/integration/os/factory" "github.com/evmos/os/testutil/integration/os/grpc" testkeyring "github.com/evmos/os/testutil/integration/os/keyring" - "github.com/evmos/os/testutil/integration/os/network" + "github.com/realiotech/realio-network/testutil/integration/os/network" "github.com/stretchr/testify/suite" ) @@ -27,7 +26,7 @@ type PrecompileTestSuite struct { grpcHandler grpc.Handler keyring testkeyring.Keyring - precompile *erc20precompile.Precompile + precompile *Precompile } func TestPrecompileTestSuite(t *testing.T) { diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index de68b4a3..2bb7f882 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -177,8 +177,9 @@ func (p *Precompile) mint( minter := contract.CallerAddress havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) + fmt.Println("have perm", havePerm, err) if err != nil || !havePerm { - return nil, err + return nil, fmt.Errorf("Sender is not token manager") } mintToAddr := sdk.AccAddress(to.Bytes()) diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go index 3ac8ec89..a2f21cb9 100644 --- a/precompiles/erc20/tx_test.go +++ b/precompiles/erc20/tx_test.go @@ -1,6 +1,7 @@ package erc20 import ( + "fmt" "math/big" "time" @@ -8,10 +9,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/evmos/os/precompiles/testutil" - utiltx "github.com/evmos/os/testutil/tx" + "github.com/evmos/os/testutil/integration/os/keyring" erc20types "github.com/evmos/os/x/erc20/types" "github.com/evmos/os/x/evm/core/vm" "github.com/evmos/os/x/evm/statedb" + utiltx "github.com/realiotech/realio-network/testutil/tx" + assettypes "github.com/realiotech/realio-network/x/asset/types" ) var ( @@ -260,3 +263,115 @@ func (s *PrecompileTestSuite) TestTransferFrom() { }) } } + +func (s *PrecompileTestSuite) TestMint() { + method := s.precompile.Methods[MintMethod] + // fromAddr is the address of the keyring account used for testing. + sender := s.keyring.GetKey(0) + invalidSender := s.keyring.GetKey(1) + maxSupply := math.NewInt(200) + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + sender keyring.Key + }{ + { + "fail - negative amount", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(-1)} + }, + func() {}, + true, + "coin -1xmpl amount is not positive", + sender, + }, + { + "fail - invalid to address", + func() []interface{} { + return []interface{}{"", big.NewInt(100)} + }, + func() {}, + true, + "invalid to address", + sender, + }, + { + "fail - invalid amount", + func() []interface{} { + return []interface{}{toAddr, ""} + }, + func() {}, + true, + "invalid amount", + sender, + }, + { + "fail - sender is not manager", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(2e18)} + }, + func() {}, + true, + ErrTransferAmountExceedsBalance.Error(), + invalidSender, + }, + { + "fail - exceed max supply", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(300)} + }, + func() {}, + true, + "Exceed max supply", + invalidSender, + }, + { + "pass", + func() []interface{} { + return []interface{}{toAddr, big.NewInt(100)} + }, + func() { + toAddrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + sender, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), tc.sender.Addr, s.precompile, 0) + + // Set up manager role for valid sender + err := s.precompile.assetKeep.TokenManagement.Set( + ctx, + s.tokenDenom, + assettypes.TokenManagement{ + Managers: []string{sender.AccAddr.String()}, + ExtensionsList: []string{"mint"}, + MaxSupply: maxSupply, + }, + ) + s.Require().NoError(err) + + _, err = s.precompile.Mint(ctx, contract, stateDB, &method, tc.malleate()) + fmt.Println("errrrr", err) + if tc.expErr { + s.Require().Error(err, "expected mint transaction to fail") + // s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/precompiles/erc20/utils_test.go b/precompiles/erc20/utils_test.go index 3d7da72f..ba265ef5 100644 --- a/precompiles/erc20/utils_test.go +++ b/precompiles/erc20/utils_test.go @@ -7,27 +7,20 @@ import ( "time" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/math" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - auth "github.com/evmos/os/precompiles/authorization" "github.com/evmos/os/precompiles/erc20" - "github.com/evmos/os/precompiles/testutil" commonfactory "github.com/evmos/os/testutil/integration/common/factory" commonnetwork "github.com/evmos/os/testutil/integration/common/network" "github.com/evmos/os/testutil/integration/os/factory" - network "github.com/evmos/os/testutil/integration/os/network" testutils "github.com/evmos/os/testutil/integration/os/utils" - utiltx "github.com/evmos/os/testutil/tx" erc20types "github.com/evmos/os/x/erc20/types" - evmtypes "github.com/evmos/os/x/evm/types" - - //nolint:revive // dot imports are fine for Gomega - . "github.com/onsi/gomega" + network "github.com/realiotech/realio-network/testutil/integration/os/network" + utiltx "github.com/realiotech/realio-network/testutil/tx" ) // setupSendAuthz is a helper function to set up a SendAuthorization for @@ -47,23 +40,6 @@ func (s *PrecompileTestSuite) setupSendAuthz( s.Require().NoError(err, "failed to set up send authorization") } -func (is *IntegrationTestSuite) setupSendAuthz( - grantee sdk.AccAddress, granterPriv cryptotypes.PrivKey, amount sdk.Coins, -) { - err := setupSendAuthz( - is.network, - is.factory, - grantee, - granterPriv, - amount, - ) - Expect(err).ToNot(HaveOccurred(), "failed to set up send authorization") - - // commit changes to chain state - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") -} - func setupSendAuthz( network commonnetwork.Network, factory commonfactory.BaseTxFactory, @@ -98,58 +74,6 @@ func setupSendAuthz( return nil } -// setupSendAuthzForContract is a helper function which executes an approval -// for the given contract data. -// -// If: -// - the classic ERC20 contract is used, it calls the `approve` method on the contract. -// - in other cases, it sends a `MsgGrant` to set up the authorization. -func (is *IntegrationTestSuite) setupSendAuthzForContract( - callType CallType, contractData ContractsData, grantee common.Address, granterPriv cryptotypes.PrivKey, amount sdk.Coins, -) { - Expect(amount).To(HaveLen(1), "expected only one coin") - Expect(amount[0].Denom).To(Equal(is.tokenDenom), - "this test utility only works with the token denom in the context of these integration tests", - ) - - switch { - case slices.Contains(nativeCallTypes, callType): - is.setupSendAuthz(grantee.Bytes(), granterPriv, amount) - case slices.Contains(erc20CallTypes, callType): - is.setupSendAuthzForERC20(callType, contractData, grantee, granterPriv, amount) - default: - panic("unknown contract call type") - } - - // commit changes to the chain state - err := is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error while calling NextBlock") -} - -// setupSendAuthzForERC20 is a helper function to set up a SendAuthorization for -// a given grantee and granter combination for a given amount. -func (is *IntegrationTestSuite) setupSendAuthzForERC20( - callType CallType, contractData ContractsData, grantee common.Address, granterPriv cryptotypes.PrivKey, amount sdk.Coins, -) { - if callType == erc20V5CallerCall { - // NOTE: When using the ERC20 caller contract, we must still approve from the actual ERC20 v5 contract. - callType = erc20V5Call - } - - abiEvents := contractData.GetContractData(callType).ABI.Events - - txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, auth.ApproveMethod, grantee, amount.AmountOf(is.tokenDenom).BigInt()) - - approveCheck := testutil.LogCheckArgs{ - ABIEvents: abiEvents, - ExpEvents: []string{auth.EventTypeApproval}, - ExpPass: true, - } - - _, _, err := is.factory.CallContractAndCheckLogs(granterPriv, txArgs, callArgs, approveCheck) - Expect(err).ToNot(HaveOccurred(), "failed to execute approve") -} - // requireOut is a helper utility to reduce the amount of boilerplate code in the query tests. // // It requires the output bytes and error to match the expected values. Additionally, the method outputs @@ -218,7 +142,7 @@ func (s *PrecompileTestSuite) requireSendAuthz(grantee, granter sdk.AccAddress, // setupERC20Precompile is a helper function to set up an instance of the ERC20 precompile for // a given token denomination, set the token pair in the ERC20 keeper and adds the precompile // to the available and active precompiles. -func (s *PrecompileTestSuite) setupERC20Precompile(denom string) *erc20.Precompile { +func (s *PrecompileTestSuite) setupERC20Precompile(denom string) *Precompile { tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), denom, erc20types.OWNER_MODULE) s.network.App.Erc20Keeper.SetTokenPair(s.network.GetContext(), tokenPair) @@ -228,40 +152,19 @@ func (s *PrecompileTestSuite) setupERC20Precompile(denom string) *erc20.Precompi return precompile } -// setupERC20Precompile is a helper function to set up an instance of the ERC20 precompile for -// a given token denomination, set the token pair in the ERC20 keeper and adds the precompile -// to the available and active precompiles. -func (is *IntegrationTestSuite) setupERC20Precompile(denom string, tokenPairs []erc20types.TokenPair) *erc20.Precompile { - var tokenPair erc20types.TokenPair - for _, tp := range tokenPairs { - if tp.Denom != denom { - continue - } - tokenPair = tp - } - - precompile, err := erc20.NewPrecompile( - tokenPair, - is.network.App.BankKeeper, - is.network.App.AuthzKeeper, - is.network.App.TransferKeeper, - ) - Expect(err).ToNot(HaveOccurred(), "failed to set up %q erc20 precompile", tokenPair.Denom) - - return precompile -} - // setupERC20PrecompileForTokenPair is a helper function to set up an instance of the ERC20 precompile for // a given token pair and adds the precompile to the available and active precompiles. // Do not use this function for integration tests. func setupERC20PrecompileForTokenPair( unitNetwork network.UnitTestNetwork, tokenPair erc20types.TokenPair, -) (*erc20.Precompile, error) { - precompile, err := erc20.NewPrecompile( - tokenPair, +) (*Precompile, error) { + precompile, err := NewPrecompile( + tokenPair.Denom, + tokenPair.GetERC20Contract(), unitNetwork.App.BankKeeper, unitNetwork.App.AuthzKeeper, unitNetwork.App.TransferKeeper, + unitNetwork.App.AssetKeeper, ) if err != nil { return nil, errorsmod.Wrapf(err, "failed to create %q erc20 precompile", tokenPair.Denom) @@ -337,178 +240,12 @@ var ( erc20CallTypes = []CallType{erc20Call, erc20CallerCall, erc20V5Call, erc20V5CallerCall} ) -// getTxAndCallArgs is a helper function to return the correct call arguments for a given call type. -// -// In case of a direct call to the precompile, the precompile's ABI is used. Otherwise, the -// ERC20CallerContract's ABI is used and the given contract address. -func (is *IntegrationTestSuite) getTxAndCallArgs( - callType CallType, - contractData ContractsData, - methodName string, - args ...interface{}, -) (evmtypes.EvmTxArgs, factory.CallArgs) { - cd := contractData.GetContractData(callType) - - txArgs := evmtypes.EvmTxArgs{ - To: &cd.Address, - GasPrice: gasPrice, - } - - callArgs := factory.CallArgs{ - ContractABI: cd.ABI, - MethodName: methodName, - Args: args, - } - - return txArgs, callArgs -} - // ExpectedBalance is a helper struct to check the balances of accounts. type ExpectedBalance struct { address sdk.AccAddress expCoins sdk.Coins } -// ExpectBalances is a helper function to check if the balances of the given accounts are as expected. -func (is *IntegrationTestSuite) ExpectBalances(expBalances []ExpectedBalance) { - for _, expBalance := range expBalances { - for _, expCoin := range expBalance.expCoins { - coinBalance, err := is.handler.GetBalanceFromBank(expBalance.address, expCoin.Denom) - Expect(err).ToNot(HaveOccurred(), "expected no error getting balance") - Expect(coinBalance.Balance.Amount).To(Equal(expCoin.Amount), "expected different balance") - } - } -} - -// ExpectBalancesForContract is a helper function to check expected balances for given accounts depending -// on the call type. -func (is *IntegrationTestSuite) ExpectBalancesForContract(callType CallType, contractData ContractsData, expBalances []ExpectedBalance) { - switch { - case slices.Contains(nativeCallTypes, callType): - is.ExpectBalances(expBalances) - case slices.Contains(erc20CallTypes, callType): - is.ExpectBalancesForERC20(callType, contractData, expBalances) - default: - panic("unknown contract call type") - } -} - -// ExpectBalancesForERC20 is a helper function to check expected balances for given accounts -// when using the ERC20 contract. -func (is *IntegrationTestSuite) ExpectBalancesForERC20(callType CallType, contractData ContractsData, expBalances []ExpectedBalance) { - contractABI := contractData.GetContractData(callType).ABI - - for _, expBalance := range expBalances { - addr := common.BytesToAddress(expBalance.address.Bytes()) - txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, "balanceOf", addr) - - passCheck := testutil.LogCheckArgs{ExpPass: true} - - _, ethRes, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "expected no error getting balance") - - err = is.network.NextBlock() - Expect(err).ToNot(HaveOccurred(), "error on NextBlock call") - - var balance *big.Int - err = contractABI.UnpackIntoInterface(&balance, "balanceOf", ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "expected no error unpacking balance") - Expect(math.NewIntFromBigInt(balance)).To(Equal(expBalance.expCoins.AmountOf(is.tokenDenom)), "expected different balance") - } -} - -// expectSendAuthz is a helper function to check that a SendAuthorization -// exists for a given grantee and granter combination for a given amount and optionally an access list. -// -// NOTE: This helper expects only one authorization to exist. -// -// NOTE 2: This mirrors the requireSendAuthz method but adapted to Ginkgo. -func (is *IntegrationTestSuite) expectSendAuthz(grantee, granter sdk.AccAddress, expAmount sdk.Coins) { - authzs, err := is.handler.GetAuthorizations(grantee.String(), granter.String()) - Expect(err).ToNot(HaveOccurred(), "expected no error unpacking the authorization") - Expect(authzs).To(HaveLen(1), "expected one authorization") - - sendAuthz, ok := authzs[0].(*banktypes.SendAuthorization) - Expect(ok).To(BeTrue(), "expected send authorization") - - Expect(sendAuthz.SpendLimit).To(Equal(expAmount), "expected different spend limit amount") -} - -// expectSendAuthzForERC20 is a helper function to check that a SendAuthorization -// exists for a given grantee and granter combination for a given amount. -func (is *IntegrationTestSuite) expectSendAuthzForERC20(callType CallType, contractData ContractsData, grantee, granter common.Address, expAmount sdk.Coins) { - contractABI := contractData.GetContractData(callType).ABI - - txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, auth.AllowanceMethod, granter, grantee) - - passCheck := testutil.LogCheckArgs{ExpPass: true} - - _, ethRes, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, passCheck) - Expect(err).ToNot(HaveOccurred(), "expected no error getting allowance") - // Increase block to update nonce - Expect(is.network.NextBlock()).To(BeNil()) - - var allowance *big.Int - err = contractABI.UnpackIntoInterface(&allowance, "allowance", ethRes.Ret) - Expect(err).ToNot(HaveOccurred(), "expected no error unpacking allowance") - Expect(math.NewIntFromBigInt(allowance)).To(Equal(expAmount.AmountOf(is.tokenDenom)), "expected different allowance") -} - -// ExpectSendAuthzForContract is a helper function to check that a SendAuthorization -// exists for a given grantee and granter combination for a given amount and optionally an access list. -// -// NOTE: This helper expects only one authorization to exist. -func (is *IntegrationTestSuite) ExpectSendAuthzForContract( - callType CallType, contractData ContractsData, grantee, granter common.Address, expAmount sdk.Coins, -) { - switch { - case slices.Contains(nativeCallTypes, callType): - is.expectSendAuthz(grantee.Bytes(), granter.Bytes(), expAmount) - case slices.Contains(erc20CallTypes, callType): - is.expectSendAuthzForERC20(callType, contractData, grantee, granter, expAmount) - default: - panic("unknown contract call type") - } -} - -// expectNoSendAuthz is a helper function to check that no SendAuthorization -// exists for a given grantee and granter combination. -func (is *IntegrationTestSuite) expectNoSendAuthz(grantee, granter sdk.AccAddress) { - authzs, err := is.handler.GetAuthorizations(grantee.String(), granter.String()) - Expect(err).ToNot(HaveOccurred(), "expected no error unpacking the authorizations") - Expect(authzs).To(HaveLen(0), "expected no authorizations") -} - -// expectNoSendAuthzForERC20 is a helper function to check that no SendAuthorization -// exists for a given grantee and granter combination. -func (is *IntegrationTestSuite) expectNoSendAuthzForERC20(callType CallType, contractData ContractsData, grantee, granter common.Address) { - is.expectSendAuthzForERC20(callType, contractData, grantee, granter, sdk.Coins{}) -} - -// ExpectNoSendAuthzForContract is a helper function to check that no SendAuthorization -// exists for a given grantee and granter combination. -func (is *IntegrationTestSuite) ExpectNoSendAuthzForContract( - callType CallType, contractData ContractsData, grantee, granter common.Address, -) { - switch { - case slices.Contains(nativeCallTypes, callType): - is.expectNoSendAuthz(grantee.Bytes(), granter.Bytes()) - case slices.Contains(erc20CallTypes, callType): - is.expectNoSendAuthzForERC20(callType, contractData, grantee, granter) - default: - panic("unknown contract call type") - } -} - -// ExpectTrueToBeReturned is a helper function to check that the precompile returns true -// in the ethereum transaction response. -func (is *IntegrationTestSuite) ExpectTrueToBeReturned(res *evmtypes.MsgEthereumTxResponse, methodName string) { - var ret bool - err := is.precompile.UnpackIntoInterface(&ret, methodName, res.Ret) - Expect(err).ToNot(HaveOccurred(), "expected no error unpacking") - Expect(ret).To(BeTrue(), "expected true to be returned") -} - // ContractsData is a helper struct to hold the addresses and ABIs for the // different contract instances that are subject to testing here. type ContractsData struct { @@ -530,69 +267,3 @@ func (cd ContractsData) GetContractData(callType CallType) ContractData { } return data } - -// fundWithTokens is a helper function for the scope of the ERC20 integration tests. -// Depending on the passed call type, it funds the given address with tokens either -// using the Bank module or by minting straight on the ERC20 contract. -// Returns the updated balance amount of the receiver address -func (is *IntegrationTestSuite) fundWithTokens( - callType CallType, - contractData ContractsData, - receiver common.Address, - fundCoins sdk.Coins, -) math.Int { - Expect(fundCoins).To(HaveLen(1), "expected only one coin") - Expect(fundCoins[0].Denom).To(Equal(is.tokenDenom), - "this helper function only supports funding with the token denom in the context of these integration tests", - ) - - var err error - receiverBalance := fundCoins.AmountOf(is.tokenDenom) - balanceInBankMod := slices.Contains(nativeCallTypes, callType) - - switch { - case balanceInBankMod: - err = is.factory.FundAccount(is.keyring.GetKey(0), receiver.Bytes(), fundCoins) - case slices.Contains(erc20CallTypes, callType): - err = is.MintERC20(callType, contractData, receiver, fundCoins.AmountOf(is.tokenDenom).BigInt()) - default: - panic("unknown contract call type") - } - - Expect(err).ToNot(HaveOccurred(), "failed to fund account") - Expect(is.network.NextBlock()).To(BeNil()) - - if balanceInBankMod { - balRes, err := is.handler.GetBalanceFromBank(receiver.Bytes(), fundCoins.Denoms()[0]) - Expect(err).To(BeNil()) - receiverBalance = balRes.Balance.Amount - } - - return receiverBalance -} - -// MintERC20 is a helper function to mint tokens on the ERC20 contract. -// -// NOTE: we are checking that there was a Transfer event emitted (which happens on minting). -func (is *IntegrationTestSuite) MintERC20(callType CallType, contractData ContractsData, receiver common.Address, amount *big.Int) error { - if callType == erc20V5CallerCall { - // NOTE: When using the ERC20 caller contract, we must still mint from the actual ERC20 v5 contract. - callType = erc20V5Call - } - abiEvents := contractData.GetContractData(callType).ABI.Events - - txArgs, callArgs := is.getTxAndCallArgs(callType, contractData, "mint", receiver, amount) - - mintCheck := testutil.LogCheckArgs{ - ABIEvents: abiEvents, - ExpEvents: []string{erc20.EventTypeTransfer}, // NOTE: this event occurs when calling "mint" on ERC20s - ExpPass: true, - } - - if _, _, err := is.factory.CallContractAndCheckLogs(contractData.ownerPriv, txArgs, callArgs, mintCheck); err != nil { - return err - } - - // commit changes to chain state - return is.network.NextBlock() -} diff --git a/testutil/integration/common/factory/base.go b/testutil/integration/common/factory/base.go new file mode 100644 index 00000000..7a716bbf --- /dev/null +++ b/testutil/integration/common/factory/base.go @@ -0,0 +1,119 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + abcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + testutiltypes "github.com/cosmos/cosmos-sdk/types/module/testutil" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// BaseTxFactory is the interface that wraps the common methods to build and broadcast transactions +// within cosmos chains +type BaseTxFactory interface { + // BuildCosmosTx builds a Cosmos tx with the provided private key and txArgs + BuildCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (authsigning.Tx, error) + // SignCosmosTx signs a Cosmos transaction with the provided + // private key and tx builder + SignCosmosTx(privKey cryptotypes.PrivKey, txBuilder client.TxBuilder) error + // ExecuteCosmosTx builds, signs and broadcasts a Cosmos tx with the provided private key and txArgs + ExecuteCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (abcitypes.ExecTxResult, error) + // EncodeTx encodes the provided transaction + EncodeTx(tx sdktypes.Tx) ([]byte, error) + // CommitCosmosTx creates, signs and commits a cosmos tx + // (produces a block with the specified transaction) + CommitCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (abcitypes.ExecTxResult, error) +} + +// baseTxFactory is the struct of the basic tx factory +// to build and broadcast transactions. +// This is to simulate the behavior of a real user. +type baseTxFactory struct { + grpcHandler grpc.Handler + network network.Network + ec testutiltypes.TestEncodingConfig +} + +// newBaseTxFactory instantiates a new baseTxFactory +func newBaseTxFactory( + network network.Network, + grpcHandler grpc.Handler, +) BaseTxFactory { + return &baseTxFactory{ + grpcHandler: grpcHandler, + network: network, + ec: network.GetEncodingConfig(), + } +} + +func (tf *baseTxFactory) BuildCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (authsigning.Tx, error) { + txBuilder, err := tf.buildTx(privKey, txArgs) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to build tx") + } + return txBuilder.GetTx(), nil +} + +// ExecuteCosmosTx creates, signs and broadcasts a Cosmos transaction +func (tf *baseTxFactory) ExecuteCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (abcitypes.ExecTxResult, error) { + signedTx, err := tf.BuildCosmosTx(privKey, txArgs) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to build tx") + } + + txBytes, err := tf.EncodeTx(signedTx) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to encode tx") + } + + return tf.network.BroadcastTxSync(txBytes) +} + +// CommitCosmosTx creates and signs a Cosmos transaction, and then includes it in +// a block and commits the state changes on the chain +func (tf *baseTxFactory) CommitCosmosTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (abcitypes.ExecTxResult, error) { + signedTx, err := tf.BuildCosmosTx(privKey, txArgs) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to build tx") + } + + txBytes, err := tf.EncodeTx(signedTx) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to encode tx") + } + + blockRes, err := tf.network.NextBlockWithTxs(txBytes) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to include the tx in a block") + } + txResCount := len(blockRes.TxResults) + if txResCount != 1 { + return abcitypes.ExecTxResult{}, fmt.Errorf("expected to receive only one tx result, but got %d", txResCount) + } + return *blockRes.TxResults[0], nil +} + +// SignCosmosTx is a helper function that signs a Cosmos transaction +// with the provided private key and transaction builder +func (tf *baseTxFactory) SignCosmosTx(privKey cryptotypes.PrivKey, txBuilder client.TxBuilder) error { + txConfig := tf.ec.TxConfig + signMode, err := authsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode()) + if err != nil { + return errorsmod.Wrap(err, "invalid sign mode") + } + signerData, err := tf.setSignatures(privKey, txBuilder, signMode) + if err != nil { + return errorsmod.Wrap(err, "failed to set tx signatures") + } + + return tf.signWithPrivKey(privKey, txBuilder, signerData, signMode) +} diff --git a/testutil/integration/common/factory/distribution.go b/testutil/integration/common/factory/distribution.go new file mode 100644 index 00000000..392a2418 --- /dev/null +++ b/testutil/integration/common/factory/distribution.go @@ -0,0 +1,88 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +type DistributionTxFactory interface { + // SetWithdrawAddress is a method to create and broadcast a MsgSetWithdrawAddress + SetWithdrawAddress(delegatorPriv cryptotypes.PrivKey, withdrawerAddr sdk.AccAddress) error + // WithdrawDelegationRewards is a method to create and broadcast a MsgWithdrawDelegationRewards + WithdrawDelegationRewards(delegatorPriv cryptotypes.PrivKey, validatorAddr string) error + // WithdrawValidatorCommission is a method to create and broadcast a MsgWithdrawValidatorCommission + WithdrawValidatorCommission(validatorPriv cryptotypes.PrivKey) error +} + +type distributionTxFactory struct { + BaseTxFactory +} + +func newDistrTxFactory(bf BaseTxFactory) DistributionTxFactory { + return &distributionTxFactory{bf} +} + +func (tf *distributionTxFactory) SetWithdrawAddress(delegatorPriv cryptotypes.PrivKey, withdrawerAddr sdk.AccAddress) error { + delegatorAccAddr := sdk.AccAddress(delegatorPriv.PubKey().Address()) + + msg := distrtypes.NewMsgSetWithdrawAddress( + delegatorAccAddr, + withdrawerAddr, + ) + + resp, err := tf.ExecuteCosmosTx(delegatorPriv, CosmosTxArgs{ + Msgs: []sdk.Msg{msg}, + }) + + if resp.Code != 0 { + err = fmt.Errorf("received error code %d on SetWithdrawAddress transaction. Logs: %s", resp.Code, resp.Log) + } + + return err +} + +// WithdrawDelegationRewards will withdraw any unclaimed staking rewards for the delegator associated with +// the given private key from the validator. +// The validator address should be in the format `evmosvaloper1...`. +func (tf *distributionTxFactory) WithdrawDelegationRewards(delegatorPriv cryptotypes.PrivKey, validatorAddr string) error { + delegatorAccAddr := sdk.AccAddress(delegatorPriv.PubKey().Address()) + + msg := distrtypes.NewMsgWithdrawDelegatorReward( + delegatorAccAddr.String(), + validatorAddr, + ) + + resp, err := tf.ExecuteCosmosTx(delegatorPriv, CosmosTxArgs{ + Msgs: []sdk.Msg{msg}, + }) + + if resp.Code != 0 { + err = fmt.Errorf("received error code %d on WithdrawDelegationRewards transaction. Logs: %s", resp.Code, resp.Log) + } + + return err +} + +func (tf *distributionTxFactory) WithdrawValidatorCommission(validatorPriv cryptotypes.PrivKey) error { + validatorAddr := sdk.ValAddress(validatorPriv.PubKey().Address()) + + msg := distrtypes.NewMsgWithdrawValidatorCommission( + validatorAddr.String(), + ) + + resp, err := tf.ExecuteCosmosTx(validatorPriv, CosmosTxArgs{ + Msgs: []sdk.Msg{msg}, + }) + + if resp.Code != 0 { + err = fmt.Errorf("received error code %d on WithdrawValidatorCommission transaction. Logs: %s", resp.Code, resp.Log) + } + + return err +} diff --git a/testutil/integration/common/factory/factory.go b/testutil/integration/common/factory/factory.go new file mode 100644 index 00000000..eb05d853 --- /dev/null +++ b/testutil/integration/common/factory/factory.go @@ -0,0 +1,48 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +const ( + GasAdjustment = float64(1.7) +) + +// CoreTxFactory is the interface that wraps the methods +// to build and broadcast cosmos transactions, and also +// includes module-specific transactions +type CoreTxFactory interface { + BaseTxFactory + DistributionTxFactory + StakingTxFactory + FundTxFactory +} + +var _ CoreTxFactory = (*IntegrationTxFactory)(nil) + +// IntegrationTxFactory is a helper struct to build and broadcast transactions +// to the network on integration tests. This is to simulate the behavior of a real user. +type IntegrationTxFactory struct { + BaseTxFactory + DistributionTxFactory + StakingTxFactory + FundTxFactory +} + +// New creates a new IntegrationTxFactory instance +func New( + network network.Network, + grpcHandler grpc.Handler, +) CoreTxFactory { + bf := newBaseTxFactory(network, grpcHandler) + return &IntegrationTxFactory{ + bf, + newDistrTxFactory(bf), + newStakingTxFactory(bf), + newFundTxFactory(bf), + } +} diff --git a/testutil/integration/common/factory/fund.go b/testutil/integration/common/factory/fund.go new file mode 100644 index 00000000..0a2b56fa --- /dev/null +++ b/testutil/integration/common/factory/fund.go @@ -0,0 +1,51 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "fmt" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/evmos/os/testutil/integration/os/keyring" +) + +// FundTxFactory is the interface that wraps the common methods to fund accounts +// via a bank send transaction +type FundTxFactory interface { + // FundAccount funds the given account with the given amount. + FundAccount(sender keyring.Key, receiver sdktypes.AccAddress, amount sdktypes.Coins) error +} + +// baseTxFactory is the struct of the basic tx factory +// to build and broadcast transactions. +// This is to simulate the behavior of a real user. +type fundTxFactory struct { + BaseTxFactory +} + +// newBaseTxFactory instantiates a new baseTxFactory +func newFundTxFactory(bf BaseTxFactory) FundTxFactory { + return &fundTxFactory{bf} +} + +// FundAccount funds the given account with the given amount of coins. +func (tf *fundTxFactory) FundAccount(sender keyring.Key, receiver sdktypes.AccAddress, coins sdktypes.Coins) error { + bankmsg := banktypes.NewMsgSend( + sender.AccAddr, + receiver, + coins, + ) + txArgs := CosmosTxArgs{Msgs: []sdktypes.Msg{bankmsg}} + txRes, err := tf.ExecuteCosmosTx(sender.Priv, txArgs) + if err != nil { + return err + } + + if txRes.Code != 0 { + return fmt.Errorf("transaction returned non-zero code %d", txRes.Code) + } + + return nil +} diff --git a/testutil/integration/common/factory/helper.go b/testutil/integration/common/factory/helper.go new file mode 100644 index 00000000..70e2bf53 --- /dev/null +++ b/testutil/integration/common/factory/helper.go @@ -0,0 +1,119 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "math/big" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +// EncodeTx encodes the tx using the txConfig's encoder. +func (tf *baseTxFactory) EncodeTx(tx sdktypes.Tx) ([]byte, error) { + txConfig := tf.ec.TxConfig + txBytes, err := txConfig.TxEncoder()(tx) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to encode tx") + } + return txBytes, nil +} + +// buildTx builds a tx with the provided private key and txArgs +func (tf *baseTxFactory) buildTx(privKey cryptotypes.PrivKey, txArgs CosmosTxArgs) (client.TxBuilder, error) { + txConfig := tf.ec.TxConfig + txBuilder := txConfig.NewTxBuilder() + + if err := txBuilder.SetMsgs(txArgs.Msgs...); err != nil { + return nil, errorsmod.Wrap(err, "failed to set tx msgs") + } + + if txArgs.FeeGranter != nil { + txBuilder.SetFeeGranter(txArgs.FeeGranter) + } + + senderAddress := sdktypes.AccAddress(privKey.PubKey().Address().Bytes()) + + if txArgs.FeeGranter != nil { + txBuilder.SetFeeGranter(txArgs.FeeGranter) + } + + txBuilder.SetFeePayer(senderAddress) + + // need to sign the tx to simulate the tx to get the gas estimation + signMode, err := authsigning.APISignModeToInternal(txConfig.SignModeHandler().DefaultMode()) + if err != nil { + return nil, errorsmod.Wrap(err, "invalid sign mode") + } + signerData, err := tf.setSignatures(privKey, txBuilder, signMode) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to set tx signatures") + } + + gasLimit, err := tf.estimateGas(txArgs, txBuilder) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to estimate gas") + } + txBuilder.SetGasLimit(gasLimit) + + fees := txArgs.Fees + if fees.IsZero() { + fees, err = tf.calculateFees(txArgs.GasPrice, gasLimit) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to calculate fees") + } + } + txBuilder.SetFeeAmount(fees) + + if err := tf.signWithPrivKey(privKey, txBuilder, signerData, signMode); err != nil { + return nil, errorsmod.Wrap(err, "failed to sign Cosmos Tx") + } + + return txBuilder, nil +} + +// calculateFees calculates the fees for the transaction. +func (tf *baseTxFactory) calculateFees(gasPrice *sdkmath.Int, gasLimit uint64) (sdktypes.Coins, error) { + denom := tf.network.GetBaseDenom() + var fees sdktypes.Coins + if gasPrice != nil { + fees = sdktypes.Coins{{Denom: denom, Amount: gasPrice.MulRaw(int64(gasLimit))}} //#nosec G115 + } else { + resp, err := tf.grpcHandler.GetBaseFee() + if err != nil { + return sdktypes.Coins{}, errorsmod.Wrap(err, "failed to get base fee") + } + price := resp.BaseFee + fees = sdktypes.Coins{{Denom: denom, Amount: price.MulInt64(int64(gasLimit)).TruncateInt()}} //#nosec G115 + } + return fees, nil +} + +// estimateGas estimates the gas needed for the transaction. +func (tf *baseTxFactory) estimateGas(txArgs CosmosTxArgs, txBuilder client.TxBuilder) (uint64, error) { + txConfig := tf.ec.TxConfig + simulateBytes, err := txConfig.TxEncoder()(txBuilder.GetTx()) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to encode tx") + } + + var gasLimit uint64 + if txArgs.Gas == nil { + simulateRes, err := tf.network.Simulate(simulateBytes) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to simulate tx") + } + + gasAdj := new(big.Float).SetFloat64(GasAdjustment) + gasUsed := new(big.Float).SetUint64(simulateRes.GasInfo.GasUsed) + gasLimit, _ = gasAdj.Mul(gasAdj, gasUsed).Uint64() + } else { + gasLimit = *txArgs.Gas + } + return gasLimit, nil +} diff --git a/testutil/integration/common/factory/sign.go b/testutil/integration/common/factory/sign.go new file mode 100644 index 00000000..6686dfe0 --- /dev/null +++ b/testutil/integration/common/factory/sign.go @@ -0,0 +1,58 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/client" + cosmostx "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +// setSignatures is a helper function that sets the signature for +// the transaction in the tx builder. It returns the signerData to be used +// when signing the transaction (e.g. when calling signWithPrivKey) +func (tf *baseTxFactory) setSignatures(privKey cryptotypes.PrivKey, txBuilder client.TxBuilder, signMode signing.SignMode) (signerData authsigning.SignerData, err error) { + senderAddress := sdktypes.AccAddress(privKey.PubKey().Address().Bytes()) + account, err := tf.grpcHandler.GetAccount(senderAddress.String()) + if err != nil { + return signerData, err + } + sequence := account.GetSequence() + signerData = authsigning.SignerData{ + ChainID: tf.network.GetChainID(), + AccountNumber: account.GetAccountNumber(), + Sequence: sequence, + Address: senderAddress.String(), + PubKey: privKey.PubKey(), + } + + sigsV2 := signing.SignatureV2{ + PubKey: privKey.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + Signature: nil, + }, + Sequence: sequence, + } + + return signerData, txBuilder.SetSignatures(sigsV2) +} + +// signWithPrivKey is a helper function that signs a transaction +// with the provided private key +func (tf *baseTxFactory) signWithPrivKey(privKey cryptotypes.PrivKey, txBuilder client.TxBuilder, signerData authsigning.SignerData, signMode signing.SignMode) error { + txConfig := tf.ec.TxConfig + signature, err := cosmostx.SignWithPrivKey(context.TODO(), signMode, signerData, txBuilder, privKey, txConfig, signerData.Sequence) + if err != nil { + return errorsmod.Wrap(err, "failed to sign tx") + } + + return txBuilder.SetSignatures(signature) +} diff --git a/testutil/integration/common/factory/staking.go b/testutil/integration/common/factory/staking.go new file mode 100644 index 00000000..72799a4d --- /dev/null +++ b/testutil/integration/common/factory/staking.go @@ -0,0 +1,88 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "fmt" + + "cosmossdk.io/math" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type StakingTxFactory interface { + // Delegate is a method to create and execute a MsgDelegate paying always the same fee amount + // The tx is included in a block and committed in the chain state + Delegate(delegatorPriv cryptotypes.PrivKey, validatorAddr string, amount sdk.Coin) error + // CreateValidator is a method to create and broadcast a MsgCreateValidator + CreateValidator(operatorPriv cryptotypes.PrivKey, pubKey cryptotypes.PubKey, selfDelegation sdk.Coin, description stakingtypes.Description, commission stakingtypes.CommissionRates, minSelfDelegation math.Int) error +} + +type stakingTxFactory struct { + BaseTxFactory +} + +func newStakingTxFactory(bf BaseTxFactory) StakingTxFactory { + return &stakingTxFactory{bf} +} + +// Delegate on behalf of the account associated with the given private key. +// The defined amount will delegated to the specified validator. +// The validator address should be in the format `evmosvaloper1...`. +func (tf *stakingTxFactory) Delegate(delegatorPriv cryptotypes.PrivKey, validatorAddr string, amount sdk.Coin) error { + delegatorAccAddr := sdk.AccAddress(delegatorPriv.PubKey().Address()) + + msgDelegate := stakingtypes.NewMsgDelegate( + delegatorAccAddr.String(), + validatorAddr, + amount, + ) + + // set gas and gas prices to pay the same fees + // every time this function is called + feesToPay := math.NewInt(1e16) + gas := uint64(400_000) + gasPrice := feesToPay.QuoRaw(int64(gas)) //#nosec G115 -- gas will not exceed int64 + + res, err := tf.CommitCosmosTx(delegatorPriv, CosmosTxArgs{ + Msgs: []sdk.Msg{msgDelegate}, + Gas: &gas, + GasPrice: &gasPrice, + }) + + if res.IsErr() { + return fmt.Errorf("tx result with code %d. Logs: %s", res.Code, res.Log) + } + + return err +} + +// CreateValidator executes the transaction to create a validator +// with the parameters specified +func (tf *stakingTxFactory) CreateValidator(operatorPriv cryptotypes.PrivKey, pubKey cryptotypes.PubKey, selfDelegation sdk.Coin, description stakingtypes.Description, commission stakingtypes.CommissionRates, minSelfDelegation math.Int) error { + operatorAccAddr := sdk.ValAddress(operatorPriv.PubKey().Address()) + + msgCreateValidator, err := stakingtypes.NewMsgCreateValidator( + operatorAccAddr.String(), + pubKey, + selfDelegation, + description, + commission, + minSelfDelegation, + ) + if err != nil { + return err + } + + resp, err := tf.ExecuteCosmosTx(operatorPriv, CosmosTxArgs{ + Msgs: []sdk.Msg{msgCreateValidator}, + }) + + if resp.Code != 0 { + err = fmt.Errorf("received error code %d on CreateValidator transaction. Logs: %s", resp.Code, resp.Log) + } + + return err +} diff --git a/testutil/integration/common/factory/types.go b/testutil/integration/common/factory/types.go new file mode 100644 index 00000000..abd35161 --- /dev/null +++ b/testutil/integration/common/factory/types.go @@ -0,0 +1,25 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + sdkmath "cosmossdk.io/math" + sdktypes "github.com/cosmos/cosmos-sdk/types" +) + +// CosmosTxArgs contains the params to create a cosmos tx +type CosmosTxArgs struct { + // ChainID is the chain's id in cosmos format, e.g. 'evmos_9000-1' + ChainID string + // Gas to be used on the tx + Gas *uint64 + // GasPrice to use on tx + GasPrice *sdkmath.Int + // Fees is the fee to be used on the tx (amount and denom) + Fees sdktypes.Coins + // FeeGranter is the account address of the fee granter + FeeGranter sdktypes.AccAddress + // Msgs slice of messages to include on the tx + Msgs []sdktypes.Msg +} diff --git a/testutil/integration/common/grpc/account.go b/testutil/integration/common/grpc/account.go new file mode 100644 index 00000000..38777290 --- /dev/null +++ b/testutil/integration/common/grpc/account.go @@ -0,0 +1,29 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// GetAccount returns the account for the given address. +func (gqh *IntegrationHandler) GetAccount(address string) (sdk.AccountI, error) { + authClient := gqh.network.GetAuthClient() + res, err := authClient.Account(context.Background(), &authtypes.QueryAccountRequest{ + Address: address, + }) + if err != nil { + return nil, err + } + + encodingCgf := gqh.network.GetEncodingConfig() + var acc sdk.AccountI + if err = encodingCgf.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { + return nil, err + } + return acc, nil +} diff --git a/testutil/integration/common/grpc/authz.go b/testutil/integration/common/grpc/authz.go new file mode 100644 index 00000000..bd60044e --- /dev/null +++ b/testutil/integration/common/grpc/authz.go @@ -0,0 +1,117 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/x/authz" +) + +// GetGrants returns the grants for the given grantee and granter combination. +// +// NOTE: To extract the concrete authorizations, use the GetAuthorizations method. +func (gqh *IntegrationHandler) GetGrants(grantee, granter string) ([]*authz.Grant, error) { + authzClient := gqh.network.GetAuthzClient() + res, err := authzClient.Grants(context.Background(), &authz.QueryGrantsRequest{ + Grantee: grantee, + Granter: granter, + }) + if err != nil { + return nil, err + } + + return res.Grants, nil +} + +// GetGrantsByGrantee returns the grants for the given grantee. +// +// NOTE: To extract the concrete authorizations, use the GetAuthorizationsByGrantee method. +func (gqh *IntegrationHandler) GetGrantsByGrantee(grantee string) ([]*authz.GrantAuthorization, error) { + authzClient := gqh.network.GetAuthzClient() + res, err := authzClient.GranteeGrants(context.Background(), &authz.QueryGranteeGrantsRequest{ + Grantee: grantee, + }) + if err != nil { + return nil, err + } + + return res.Grants, nil +} + +// GetGrantsByGranter returns the grants for the given granter. +// +// NOTE: To extract the concrete authorizations, use the GetAuthorizationsByGranter method. +func (gqh *IntegrationHandler) GetGrantsByGranter(granter string) ([]*authz.GrantAuthorization, error) { + authzClient := gqh.network.GetAuthzClient() + res, err := authzClient.GranterGrants(context.Background(), &authz.QueryGranterGrantsRequest{ + Granter: granter, + }) + if err != nil { + return nil, err + } + + return res.Grants, nil +} + +// GetAuthorizations returns the concrete authorizations for the given grantee and granter combination. +func (gqh *IntegrationHandler) GetAuthorizations(grantee, granter string) ([]authz.Authorization, error) { + encodingCfg := gqh.network.GetEncodingConfig() + + grants, err := gqh.GetGrants(grantee, granter) + if err != nil { + return nil, err + } + + auths := make([]authz.Authorization, 0, len(grants)) + for _, grant := range grants { + var auth authz.Authorization + err := encodingCfg.InterfaceRegistry.UnpackAny(grant.Authorization, &auth) + if err != nil { + return nil, err + } + + auths = append(auths, auth) + } + + return auths, nil +} + +// GetAuthorizationsByGrantee returns the concrete authorizations for the given grantee. +func (gqh *IntegrationHandler) GetAuthorizationsByGrantee(grantee string) ([]authz.Authorization, error) { + grants, err := gqh.GetGrantsByGrantee(grantee) + if err != nil { + return nil, err + } + + return gqh.unpackGrantAuthzs(grants) +} + +// GetAuthorizationsByGranter returns the concrete authorizations for the given granter. +func (gqh *IntegrationHandler) GetAuthorizationsByGranter(granter string) ([]authz.Authorization, error) { + grants, err := gqh.GetGrantsByGranter(granter) + if err != nil { + return nil, err + } + + return gqh.unpackGrantAuthzs(grants) +} + +// unpackGrantAuthzs unpacks the given grant authorization. +func (gqh *IntegrationHandler) unpackGrantAuthzs(grantAuthzs []*authz.GrantAuthorization) ([]authz.Authorization, error) { + encodingCfg := gqh.network.GetEncodingConfig() + + auths := make([]authz.Authorization, 0, len(grantAuthzs)) + for _, grantAuthz := range grantAuthzs { + var auth authz.Authorization + err := encodingCfg.InterfaceRegistry.UnpackAny(grantAuthz.Authorization, &auth) + if err != nil { + return nil, err + } + + auths = append(auths, auth) + } + + return auths, nil +} diff --git a/testutil/integration/common/grpc/bank.go b/testutil/integration/common/grpc/bank.go new file mode 100644 index 00000000..c82f114e --- /dev/null +++ b/testutil/integration/common/grpc/bank.go @@ -0,0 +1,40 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "context" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// GetBalanceFromBank returns the balance for the given address and denom. +func (gqh *IntegrationHandler) GetBalanceFromBank(address sdktypes.AccAddress, denom string) (*banktypes.QueryBalanceResponse, error) { + bankClient := gqh.network.GetBankClient() + return bankClient.Balance(context.Background(), &banktypes.QueryBalanceRequest{ + Address: address.String(), + Denom: denom, + }) +} + +// GetAllBalances returns all the balances for the given address. +func (gqh *IntegrationHandler) GetAllBalances(address sdktypes.AccAddress) (*banktypes.QueryAllBalancesResponse, error) { + bankClient := gqh.network.GetBankClient() + return bankClient.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{ + Address: address.String(), + }) +} + +// GetTotalSupply returns all the balances for the given address. +func (gqh *IntegrationHandler) GetTotalSupply() (*banktypes.QueryTotalSupplyResponse, error) { + bankClient := gqh.network.GetBankClient() + return bankClient.TotalSupply(context.Background(), &banktypes.QueryTotalSupplyRequest{}) +} + +// GetSpendableBalance returns the spendable balance for the given denomination. +func (gqh *IntegrationHandler) GetSpendableBalance(address sdktypes.AccAddress, denom string) (*banktypes.QuerySpendableBalanceByDenomResponse, error) { + bankClient := gqh.network.GetBankClient() + return bankClient.SpendableBalanceByDenom(context.Background(), &banktypes.QuerySpendableBalanceByDenomRequest{Address: address.String(), Denom: denom}) +} diff --git a/testutil/integration/common/grpc/distribution.go b/testutil/integration/common/grpc/distribution.go new file mode 100644 index 00000000..6b67be85 --- /dev/null +++ b/testutil/integration/common/grpc/distribution.go @@ -0,0 +1,57 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "context" + + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +// GetDelegationTotalRewards returns the total delegation rewards for the given delegator. +func (gqh *IntegrationHandler) GetDelegationTotalRewards(delegatorAddress string) (*distrtypes.QueryDelegationTotalRewardsResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.DelegationTotalRewards(context.Background(), &distrtypes.QueryDelegationTotalRewardsRequest{ + DelegatorAddress: delegatorAddress, + }) +} + +// GetDelegationRewards returns the delegation rewards for the given delegator and validator. +func (gqh *IntegrationHandler) GetDelegationRewards(delegatorAddress string, validatorAddress string) (*distrtypes.QueryDelegationRewardsResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.DelegationRewards(context.Background(), &distrtypes.QueryDelegationRewardsRequest{ + DelegatorAddress: delegatorAddress, + ValidatorAddress: validatorAddress, + }) +} + +// GetDelegatorWithdrawAddr returns the withdraw address the given delegator. +func (gqh *IntegrationHandler) GetDelegatorWithdrawAddr(delegatorAddress string) (*distrtypes.QueryDelegatorWithdrawAddressResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.DelegatorWithdrawAddress(context.Background(), &distrtypes.QueryDelegatorWithdrawAddressRequest{ + DelegatorAddress: delegatorAddress, + }) +} + +// GetValidatorCommission returns the commission for the given validator. +func (gqh *IntegrationHandler) GetValidatorCommission(validatorAddress string) (*distrtypes.QueryValidatorCommissionResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.ValidatorCommission(context.Background(), &distrtypes.QueryValidatorCommissionRequest{ + ValidatorAddress: validatorAddress, + }) +} + +// GetValidatorOutstandingRewards returns the delegation rewards for the given delegator and validator. +func (gqh *IntegrationHandler) GetValidatorOutstandingRewards(validatorAddress string) (*distrtypes.QueryValidatorOutstandingRewardsResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.ValidatorOutstandingRewards(context.Background(), &distrtypes.QueryValidatorOutstandingRewardsRequest{ + ValidatorAddress: validatorAddress, + }) +} + +// GetCommunityPool queries the community pool coins. +func (gqh *IntegrationHandler) GetCommunityPool() (*distrtypes.QueryCommunityPoolResponse, error) { + distrClient := gqh.network.GetDistrClient() + return distrClient.CommunityPool(context.Background(), &distrtypes.QueryCommunityPoolRequest{}) +} diff --git a/testutil/integration/common/grpc/grpc.go b/testutil/integration/common/grpc/grpc.go new file mode 100644 index 00000000..a0a9736a --- /dev/null +++ b/testutil/integration/common/grpc/grpc.go @@ -0,0 +1,67 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/evmos/os/testutil/integration/common/network" +) + +// Handler is an interface that defines the common methods that are used to query +// the network's modules via gRPC. +type Handler interface { + // Account methods + GetAccount(address string) (sdk.AccountI, error) + + // Authz methods + GetAuthorizations(grantee, granter string) ([]authz.Authorization, error) + GetAuthorizationsByGrantee(grantee string) ([]authz.Authorization, error) + GetAuthorizationsByGranter(granter string) ([]authz.Authorization, error) + GetGrants(grantee, granter string) ([]*authz.Grant, error) + GetGrantsByGrantee(grantee string) ([]*authz.GrantAuthorization, error) + GetGrantsByGranter(granter string) ([]*authz.GrantAuthorization, error) + + // Bank methods + GetBalanceFromBank(address sdk.AccAddress, denom string) (*banktypes.QueryBalanceResponse, error) + GetSpendableBalance(address sdk.AccAddress, denom string) (*banktypes.QuerySpendableBalanceByDenomResponse, error) + GetAllBalances(address sdk.AccAddress) (*banktypes.QueryAllBalancesResponse, error) + GetTotalSupply() (*banktypes.QueryTotalSupplyResponse, error) + + // Staking methods + GetDelegation(delegatorAddress string, validatorAddress string) (*stakingtypes.QueryDelegationResponse, error) + GetDelegatorDelegations(delegatorAddress string) (*stakingtypes.QueryDelegatorDelegationsResponse, error) + GetValidatorDelegations(validatorAddress string) (*stakingtypes.QueryValidatorDelegationsResponse, error) + GetRedelegations(delegatorAddress, srcValidator, dstValidator string) (*stakingtypes.QueryRedelegationsResponse, error) + GetValidatorUnbondingDelegations(validatorAddress string) (*stakingtypes.QueryValidatorUnbondingDelegationsResponse, error) + GetDelegatorUnbondingDelegations(delegatorAddress string) (*stakingtypes.QueryDelegatorUnbondingDelegationsResponse, error) + + // Distribution methods + GetDelegationTotalRewards(delegatorAddress string) (*distrtypes.QueryDelegationTotalRewardsResponse, error) + GetDelegationRewards(delegatorAddress string, validatorAddress string) (*distrtypes.QueryDelegationRewardsResponse, error) + GetDelegatorWithdrawAddr(delegatorAddress string) (*distrtypes.QueryDelegatorWithdrawAddressResponse, error) + GetValidatorCommission(validatorAddress string) (*distrtypes.QueryValidatorCommissionResponse, error) + GetValidatorOutstandingRewards(validatorAddress string) (*distrtypes.QueryValidatorOutstandingRewardsResponse, error) + GetCommunityPool() (*distrtypes.QueryCommunityPoolResponse, error) + GetBondedValidators() (*stakingtypes.QueryValidatorsResponse, error) +} + +var _ Handler = (*IntegrationHandler)(nil) + +// IntegrationHandler is a helper struct to query the network's modules +// via gRPC. This is to simulate the behavior of a real user and avoid querying +// the modules directly. +type IntegrationHandler struct { + network network.Network +} + +// NewIntegrationHandler creates a new IntegrationHandler instance. +func NewIntegrationHandler(network network.Network) *IntegrationHandler { + return &IntegrationHandler{ + network: network, + } +} diff --git a/testutil/integration/common/grpc/staking.go b/testutil/integration/common/grpc/staking.go new file mode 100644 index 00000000..0d959346 --- /dev/null +++ b/testutil/integration/common/grpc/staking.go @@ -0,0 +1,69 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "context" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// GetDelegation returns the delegation for the given delegator and validator addresses. +func (gqh *IntegrationHandler) GetDelegation(delegatorAddress string, validatorAddress string) (*stakingtypes.QueryDelegationResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.Delegation(context.Background(), &stakingtypes.QueryDelegationRequest{ + DelegatorAddr: delegatorAddress, + ValidatorAddr: validatorAddress, + }) +} + +// GetValidatorDelegations returns the delegations to a given validator. +func (gqh *IntegrationHandler) GetValidatorDelegations(validatorAddress string) (*stakingtypes.QueryValidatorDelegationsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.ValidatorDelegations(context.Background(), &stakingtypes.QueryValidatorDelegationsRequest{ + ValidatorAddr: validatorAddress, + }) +} + +// GetDelegatorDelegations returns the delegations to a given delegator. +func (gqh *IntegrationHandler) GetDelegatorDelegations(delegatorAddress string) (*stakingtypes.QueryDelegatorDelegationsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.DelegatorDelegations(context.Background(), &stakingtypes.QueryDelegatorDelegationsRequest{ + DelegatorAddr: delegatorAddress, + }) +} + +// GetRedelegations returns the redelegations to a given delegator and validators. +func (gqh *IntegrationHandler) GetRedelegations(delegatorAddress, srcValidator, dstValidator string) (*stakingtypes.QueryRedelegationsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.Redelegations(context.Background(), &stakingtypes.QueryRedelegationsRequest{ + DelegatorAddr: delegatorAddress, + SrcValidatorAddr: srcValidator, + DstValidatorAddr: dstValidator, + }) +} + +// GetValidatorUnbondingDelegations returns the unbonding delegations to a given validator. +func (gqh *IntegrationHandler) GetValidatorUnbondingDelegations(validatorAddress string) (*stakingtypes.QueryValidatorUnbondingDelegationsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.ValidatorUnbondingDelegations(context.Background(), &stakingtypes.QueryValidatorUnbondingDelegationsRequest{ + ValidatorAddr: validatorAddress, + }) +} + +// GetDelegatorUnbondingDelegations returns all the unbonding delegations for given delegator. +func (gqh *IntegrationHandler) GetDelegatorUnbondingDelegations(delegatorAddress string) (*stakingtypes.QueryDelegatorUnbondingDelegationsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.DelegatorUnbondingDelegations(context.Background(), &stakingtypes.QueryDelegatorUnbondingDelegationsRequest{ + DelegatorAddr: delegatorAddress, + }) +} + +// GetValidators returns the list of all bonded validators. +func (gqh *IntegrationHandler) GetBondedValidators() (*stakingtypes.QueryValidatorsResponse, error) { + stakingClient := gqh.network.GetStakingClient() + return stakingClient.Validators(context.Background(), &stakingtypes.QueryValidatorsRequest{ + Status: stakingtypes.BondStatusBonded, + }) +} diff --git a/testutil/integration/common/network/network.go b/testutil/integration/common/network/network.go new file mode 100644 index 00000000..26d4c5b0 --- /dev/null +++ b/testutil/integration/common/network/network.go @@ -0,0 +1,53 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "testing" + "time" + + abcitypes "github.com/cometbft/cometbft/abci/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +// Network is the interface that wraps the common methods to interact with integration test network. +// +// It was designed to avoid users to access module's keepers directly and force integration tests +// to be closer to the real user's behavior. +type Network interface { + GetContext() sdktypes.Context + GetChainID() string + GetBaseDenom() string + GetOtherDenoms() []string + GetValidators() []stakingtypes.Validator + + NextBlock() error + NextBlockAfter(duration time.Duration) error + NextBlockWithTxs(txBytes ...[]byte) (*abcitypes.ResponseFinalizeBlock, error) + + // Clients + GetAuthClient() authtypes.QueryClient + GetAuthzClient() authz.QueryClient + GetBankClient() banktypes.QueryClient + GetStakingClient() stakingtypes.QueryClient + GetDistrClient() distrtypes.QueryClient + + BroadcastTxSync(txBytes []byte) (abcitypes.ExecTxResult, error) + Simulate(txBytes []byte) (*txtypes.SimulateResponse, error) + CheckTx(txBytes []byte) (*abcitypes.ResponseCheckTx, error) + + // GetIBCChain returns the IBC test chain. + // NOTE: this is only used for testing IBC related functionality. + // The idea is to deprecate this eventually. + GetIBCChain(t *testing.T, coord *ibctesting.Coordinator) *ibctesting.TestChain + GetEncodingConfig() sdktestutil.TestEncodingConfig +} diff --git a/testutil/integration/ibc/chain/chain.go b/testutil/integration/ibc/chain/chain.go new file mode 100644 index 00000000..1c88773d --- /dev/null +++ b/testutil/integration/ibc/chain/chain.go @@ -0,0 +1,82 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package chain + +import ( + "time" + + cmttypes "github.com/cometbft/cometbft/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + // For now, we'll keep this. Pending to review if we can remove it. + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/simapp" +) + +// Chain defines the required methods needed for a testing IBC chain that complies +// with the ibctesting chain struct. +type Chain interface { + // GetContext returns the current context for the application. + GetContext() sdktypes.Context + // GetSimApp returns the SimApp to allow usage of non-interface fields. + GetSimApp() *simapp.SimApp + // QueryProof performs an abci query with the given key and returns the proto encoded merkle proof + // for the query and the height at which the proof will succeed on a tendermint verifier. + QueryProof(key []byte) ([]byte, clienttypes.Height) + // QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof + // for the query and the height at which the proof will succeed on a tendermint verifier. Only the IBC + // store is supported + QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) + // QueryProofForStore performs an abci query with the given key and returns the proto encoded merkle proof + // for the query and the height at which the proof will succeed on a tendermint verifier. + QueryProofForStore(storeKey string, key []byte, height int64) ([]byte, clienttypes.Height) + // QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof + // for the query and the height at which the proof will succeed on a tendermint verifier. + QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) + // QueryConsensusStateProof performs an abci query for a consensus state + // stored on the given clientID. The proof and consensusHeight are returned. + QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) + // NextBlock sets the last header to the current header and increments the current header to be + // at the next block height. It does not update the time as that is handled by the Coordinator. + // It will call Endblock and Commit and apply the validator set changes to the next validators + // of the next block being created. This follows the Tendermint protocol of applying valset changes + // returned on block `n` to the validators of block `n+2`. + // It calls BeginBlock with the new block created before returning. + NextBlock() + // GetClientState retrieves the client state for the provided clientID. The client is + // expected to exist otherwise testing will fail. + GetClientState(clientID string) exported.ClientState + // GetConsensusState retrieves the consensus state for the provided clientID and height. + // It will return a success boolean depending on if consensus state exists or not. + GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) + // GetValsAtHeight will return the trusted validator set of the chain for the given trusted height. It will return + // a success boolean depending on if the validator set exists or not at that height. + GetValsAtHeight(trustedHeight int64) (*cmttypes.ValidatorSet, bool) + // GetAcknowledgement retrieves an acknowledgement for the provided packet. If the + // acknowledgement does not exist then testing will fail. + GetAcknowledgement(packet exported.PacketI) []byte + // GetPrefix returns the prefix for used by a chain in connection creation + GetPrefix() commitmenttypes.MerklePrefix + // ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the + // light client on the source chain. + ConstructUpdateTMClientHeader(counterparty *ibctesting.TestChain, clientID string) (*ibctm.Header, error) + // ConstructUpdateTMClientHeaderWithTrustedHeight will construct a valid 07-tendermint Header to update the + ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *ibctesting.TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctm.Header, error) // light client on the source chain. + // ExpireClient fast forwards the chain's block time by the provided amount of time which will + // expire any clients with a trusting period less than or equal to this amount of time. + ExpireClient(amount time.Duration) + // CurrentTMClientHeader creates a TM header using the current header parameters + // on the chain. The trusted fields in the header are set to nil. + CurrentTMClientHeader() *ibctm.Header + // GetChannelCapability returns the channel capability for the given portID and channelID. + // The capability must exist, otherwise testing will fail. + GetChannelCapability(portID, channelID string) *capabilitytypes.Capability + // GetTimeoutHeight is a convenience function which returns an IBC packet timeout height + // to be used for testing. It returns the current IBC height + 100 blocks + GetTimeoutHeight() clienttypes.Height +} diff --git a/testutil/integration/ibc/coordinator/coordinator.go b/testutil/integration/ibc/coordinator/coordinator.go new file mode 100644 index 00000000..7ea68b6d --- /dev/null +++ b/testutil/integration/ibc/coordinator/coordinator.go @@ -0,0 +1,169 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package coordinator + +import ( + "testing" + "time" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + evmosibc "github.com/evmos/os/ibc/testing" + "github.com/evmos/os/testutil/integration/common/network" + ibcchain "github.com/evmos/os/testutil/integration/ibc/chain" +) + +// Coordinator is the interface that defines the methods that are used to +// coordinate the execution of the IBC relayer. +type Coordinator interface { + // IncrementTime iterates through all the TestChain's and increments their current header time + // by 5 seconds. + IncrementTime() + // UpdateTime updates all clocks for the TestChains to the current global time. + UpdateTime() + // UpdateTimeForChain updates the clock for a specific chain. + UpdateTimeForChain(chainID string) + // GetChain returns the TestChain for a given chainID. + GetChain(chainID string) ibcchain.Chain + // GetDummyChainsIDs returns the chainIDs for all dummy chains. + GetDummyChainsIDs() []string + // GetPath returns the transfer path for the chain ids 'a' and 'b' + GetPath(a, b string) *evmosibc.Path + // GetChainSenderAcc returns the sender account for the specified chain + GetChainSenderAcc(chainID string) sdk.AccountI + // SetDefaultSignerForChain sets the default signer for the chain with the given chainID. + SetDefaultSignerForChain(chainID string, priv cryptotypes.PrivKey, acc sdk.AccountI) + // Setup constructs a TM client, connection, and channel on both chains provided. It will + // fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned + // for both chains. The channels created are connected to the ibc-transfer application. + Setup(src, dst string) IBCConnection + // CommitNBlocks commits n blocks on the chain with the given chainID. + CommitNBlocks(chainID string, n uint64) error + // CommitAll commits 1 blocks on all chains within the coordinator. + CommitAll() error +} + +var AmountOfDummyChains = 2 + +var _ Coordinator = (*IntegrationCoordinator)(nil) + +// IntegrationCoordinator is a testing struct which contains N TestChain's. It handles keeping all chains +// in sync with regards to time. +// NOTE: When using the coordinator, it is important to commit blocks through the coordinator and not +// through the network interface directly. This is because the coordinator does not keep the context in +// sync with the network interface. +type IntegrationCoordinator struct { + coord *ibctesting.Coordinator + dummyChainsIDs []string +} + +// NewIntegrationCoordinator returns a new IntegrationCoordinator with N TestChain's. +func NewIntegrationCoordinator(t *testing.T, preConfiguredChains []network.Network) *IntegrationCoordinator { + coord := &ibctesting.Coordinator{ + T: t, + CurrentTime: time.Now(), + } + ibcChains := getIBCChains(t, coord, preConfiguredChains) + dummyChains, dummyChainsIDs := generateDummyChains(t, coord, AmountOfDummyChains) + totalChains := mergeMaps(ibcChains, dummyChains) + coord.Chains = totalChains + return &IntegrationCoordinator{ + coord: coord, + dummyChainsIDs: dummyChainsIDs, + } +} + +// GetChain returns the TestChain for a given chainID but abstracted to our internal chain interface. +func (c *IntegrationCoordinator) GetChain(chainID string) ibcchain.Chain { + return c.coord.Chains[chainID] +} + +// GetTestChain returns the TestChain for a given chainID. +func (c *IntegrationCoordinator) GetTestChain(chainID string) *ibctesting.TestChain { + return c.coord.GetChain(chainID) +} + +// GetDummyChainsIDs returns the chainIDs for all dummy chains. +func (c *IntegrationCoordinator) GetDummyChainsIDs() []string { + return c.dummyChainsIDs +} + +// GetPath returns the transfer path for the chain ids 'a' and 'b' +func (c *IntegrationCoordinator) GetPath(a, b string) *evmosibc.Path { + chainA := c.coord.GetChain(a) + chainB := c.coord.GetChain(b) + + return evmosibc.NewTransferPath(chainA, chainB) +} + +// GetChain returns the TestChain for a given chainID. +func (c *IntegrationCoordinator) GetChainSenderAcc(chainID string) sdk.AccountI { + return c.coord.Chains[chainID].SenderAccount +} + +// IncrementTime iterates through all the TestChain's and increments their current header time +// by 5 seconds. +func (c *IntegrationCoordinator) IncrementTime() { + c.coord.IncrementTime() +} + +// UpdateTime updates all clocks for the TestChains to the current global time. +func (c *IntegrationCoordinator) UpdateTime() { + c.coord.UpdateTime() +} + +// UpdateTimeForChain updates the clock for a specific chain. +func (c *IntegrationCoordinator) UpdateTimeForChain(chainID string) { + chain := c.coord.GetChain(chainID) + c.coord.UpdateTimeForChain(chain) +} + +// SetDefaultSignerForChain sets the default signer for the chain with the given chainID. +func (c *IntegrationCoordinator) SetDefaultSignerForChain(chainID string, priv cryptotypes.PrivKey, acc sdk.AccountI) { + chain := c.coord.GetChain(chainID) + chain.SenderPrivKey = priv + chain.SenderAccount = acc + chain.SenderAccounts = []ibctesting.SenderAccount{{SenderPrivKey: priv, SenderAccount: acc}} +} + +// Setup constructs a TM client, connection, and channel on both chains provided. It will +// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned +// for both chains. The channels created are connected to the ibc-transfer application. +func (c *IntegrationCoordinator) Setup(a, b string) IBCConnection { + path := c.GetPath(a, b) + evmosibc.SetupPath(c.coord, path) + + return IBCConnection{ + EndpointA: Endpoint{ + ChainID: a, + ClientID: path.EndpointA.ClientID, + ConnectionID: path.EndpointA.ConnectionID, + ChannelID: path.EndpointA.ChannelID, + PortID: path.EndpointA.ChannelConfig.PortID, + }, + EndpointB: Endpoint{ + ChainID: b, + ClientID: path.EndpointB.ClientID, + ConnectionID: path.EndpointB.ConnectionID, + ChannelID: path.EndpointB.ChannelID, + PortID: path.EndpointB.ChannelConfig.PortID, + }, + } +} + +// CommitNBlocks commits n blocks on the chain with the given chainID. +func (c *IntegrationCoordinator) CommitNBlocks(chainID string, n uint64) error { + chain := c.coord.GetChain(chainID) + c.coord.CommitNBlocks(chain, n) + return nil +} + +// CommitAll commits n blocks on the chain with the given chainID. +func (c *IntegrationCoordinator) CommitAll() error { + for _, chain := range c.coord.Chains { + c.coord.CommitNBlocks(chain, 1) + } + return nil +} diff --git a/testutil/integration/ibc/coordinator/types.go b/testutil/integration/ibc/coordinator/types.go new file mode 100644 index 00000000..dd54ad17 --- /dev/null +++ b/testutil/integration/ibc/coordinator/types.go @@ -0,0 +1,18 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package coordinator + +// Endpoint defines the identifiers for a chain's client, connection, and channel. +type Endpoint struct { + ChainID string + ClientID string + ConnectionID string + ChannelID string + PortID string +} + +// IBCConnection defines the connection between two chains. +type IBCConnection struct { + EndpointA Endpoint + EndpointB Endpoint +} diff --git a/testutil/integration/ibc/coordinator/utils.go b/testutil/integration/ibc/coordinator/utils.go new file mode 100644 index 00000000..e828bf31 --- /dev/null +++ b/testutil/integration/ibc/coordinator/utils.go @@ -0,0 +1,53 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package coordinator + +import ( + "strconv" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/evmos/os/testutil/integration/common/network" +) + +// getIBCChains returns a map of TestChain's for the given network interface. +func getIBCChains(t *testing.T, coord *ibctesting.Coordinator, chains []network.Network) map[string]*ibctesting.TestChain { + ibcChains := make(map[string]*ibctesting.TestChain) + for _, chain := range chains { + ibcChains[chain.GetChainID()] = chain.GetIBCChain(t, coord) + } + return ibcChains +} + +// generateDummyChains returns a map of dummy chains to complement IBC connections for integration tests. +func generateDummyChains(t *testing.T, coord *ibctesting.Coordinator, numberOfChains int) (map[string]*ibctesting.TestChain, []string) { + ibcChains := make(map[string]*ibctesting.TestChain) + ids := make([]string, numberOfChains) + // dummy chains use the ibc testing chain setup + // that uses the default sdk address prefix ('cosmos') + // Update the prefix configs to use that prefix + cfg := sdk.GetConfig() + cfg.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub) + cfg.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub) + cfg.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub) + // Also need to disable address cache to avoid using modules + // accounts with 'evmos' addresses (because Evmos chain setup is first) + sdk.SetAddrCacheEnabled(false) + for i := 1; i <= numberOfChains; i++ { + chainID := "dummychain-" + strconv.Itoa(i) + ids[i-1] = chainID + ibcChains[chainID] = ibctesting.NewTestChain(t, coord, chainID) + } + + return ibcChains, ids +} + +// mergeMaps merges two maps of TestChain's. +func mergeMaps(m1, m2 map[string]*ibctesting.TestChain) map[string]*ibctesting.TestChain { + for k, v := range m2 { + m1[k] = v + } + return m1 +} diff --git a/testutil/integration/os/factory/broadcast.go b/testutil/integration/os/factory/broadcast.go new file mode 100644 index 00000000..81531ea4 --- /dev/null +++ b/testutil/integration/os/factory/broadcast.go @@ -0,0 +1,100 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + errorsmod "cosmossdk.io/errors" + abcitypes "github.com/cometbft/cometbft/abci/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/os/precompiles/testutil" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// ExecuteEthTx executes an Ethereum transaction - contract call with the provided private key and txArgs +// It first builds a MsgEthereumTx and then broadcasts it to the network. +func (tf *IntegrationTxFactory) ExecuteEthTx( + priv cryptotypes.PrivKey, + txArgs evmtypes.EvmTxArgs, +) (abcitypes.ExecTxResult, error) { + signedMsg, err := tf.GenerateSignedEthTx(priv, txArgs) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to generate signed ethereum tx") + } + + txBytes, err := tf.encodeTx(signedMsg) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to encode ethereum tx") + } + + res, err := tf.network.BroadcastTxSync(txBytes) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to broadcast ethereum tx") + } + + if err := tf.checkEthTxResponse(&res); err != nil { + return res, errorsmod.Wrap(err, "failed ETH tx") + } + return res, nil +} + +// ExecuteContractCall executes a contract call with the provided private key. +func (tf *IntegrationTxFactory) ExecuteContractCall(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs, callArgs CallArgs) (abcitypes.ExecTxResult, error) { + completeTxArgs, err := tf.GenerateContractCallArgs(txArgs, callArgs) + if err != nil { + return abcitypes.ExecTxResult{}, errorsmod.Wrap(err, "failed to generate contract call args") + } + + return tf.ExecuteEthTx(privKey, completeTxArgs) +} + +// DeployContract deploys a contract with the provided private key, +// compiled contract data and constructor arguments. +// TxArgs Input and Nonce fields are overwritten. +func (tf *IntegrationTxFactory) DeployContract( + priv cryptotypes.PrivKey, + txArgs evmtypes.EvmTxArgs, + deploymentData ContractDeploymentData, +) (common.Address, error) { + // Get account's nonce to create contract hash + from := common.BytesToAddress(priv.PubKey().Address().Bytes()) + completeTxArgs, err := tf.GenerateDeployContractArgs(from, txArgs, deploymentData) + if err != nil { + return common.Address{}, errorsmod.Wrap(err, "failed to generate contract call args") + } + + res, err := tf.ExecuteEthTx(priv, completeTxArgs) + if err != nil || !res.IsOK() { + return common.Address{}, errorsmod.Wrap(err, "failed to execute eth tx") + } + return crypto.CreateAddress(from, completeTxArgs.Nonce), nil +} + +// CallContractAndCheckLogs is a helper function to call a contract and check the logs using +// the integration test utilities. +// +// It returns the Cosmos Tx response, the decoded Ethereum Tx response and an error. This error value +// is nil, if the expected logs are found and the VM error is the expected one, should one be expected. +func (tf *IntegrationTxFactory) CallContractAndCheckLogs( + priv cryptotypes.PrivKey, + txArgs evmtypes.EvmTxArgs, + callArgs CallArgs, + logCheckArgs testutil.LogCheckArgs, +) (abcitypes.ExecTxResult, *evmtypes.MsgEthereumTxResponse, error) { + res, err := tf.ExecuteContractCall(priv, txArgs, callArgs) + logCheckArgs.Res = res + if err != nil { + // NOTE: here we are still passing the response to the log check function, + // because we want to check the logs and expected error in case of a VM error. + return res, nil, CheckError(err, logCheckArgs) + } + + ethRes, err := evmtypes.DecodeTxResponse(res.Data) + if err != nil { + return res, nil, err + } + + return res, ethRes, testutil.CheckLogs(logCheckArgs) +} diff --git a/testutil/integration/os/factory/build.go b/testutil/integration/os/factory/build.go new file mode 100644 index 00000000..7f9fc8e7 --- /dev/null +++ b/testutil/integration/os/factory/build.go @@ -0,0 +1,163 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package factory + +import ( + "encoding/json" + "errors" + "math/big" + + errorsmod "cosmossdk.io/errors" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/os/server/config" + evmtypes "github.com/evmos/os/x/evm/types" +) + +func (tf *IntegrationTxFactory) GenerateDefaultTxTypeArgs(sender common.Address, txType int) (evmtypes.EvmTxArgs, error) { + defaultArgs := evmtypes.EvmTxArgs{} + switch txType { + case gethtypes.DynamicFeeTxType: + return tf.populateEvmTxArgsWithDefault(sender, defaultArgs) + case gethtypes.AccessListTxType: + defaultArgs.Accesses = &gethtypes.AccessList{{ + Address: sender, + StorageKeys: []common.Hash{{0}}, + }} + defaultArgs.GasPrice = big.NewInt(1e9) + return tf.populateEvmTxArgsWithDefault(sender, defaultArgs) + case gethtypes.LegacyTxType: + defaultArgs.GasPrice = big.NewInt(1e9) + return tf.populateEvmTxArgsWithDefault(sender, defaultArgs) + default: + return evmtypes.EvmTxArgs{}, errors.New("tx type not supported") + } +} + +// EstimateGasLimit estimates the gas limit for a tx with the provided address and txArgs +func (tf *IntegrationTxFactory) EstimateGasLimit(from *common.Address, txArgs *evmtypes.EvmTxArgs) (uint64, error) { + args, err := json.Marshal(evmtypes.TransactionArgs{ + Data: (*hexutil.Bytes)(&txArgs.Input), + From: from, + To: txArgs.To, + AccessList: txArgs.Accesses, + }) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to marshal tx args") + } + + res, err := tf.grpcHandler.EstimateGas(args, config.DefaultGasCap) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to estimate gas") + } + gas := res.Gas + + return gas, nil +} + +// GenerateSignedEthTx generates an Ethereum tx with the provided private key and txArgs but does not broadcast it. +func (tf *IntegrationTxFactory) GenerateSignedEthTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (signing.Tx, error) { + signedMsg, err := tf.GenerateSignedMsgEthereumTx(privKey, txArgs) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to generate signed MsgEthereumTx") + } + + // Validate the transaction to avoid unrealistic behavior + if err = signedMsg.ValidateBasic(); err != nil { + return nil, errorsmod.Wrap(err, "failed to validate transaction") + } + + return tf.buildSignedTx(signedMsg) +} + +// GenerateSignedMsgEthereumTx generates an MsgEthereumTx signed with the provided private key and txArgs. +func (tf *IntegrationTxFactory) GenerateSignedMsgEthereumTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (evmtypes.MsgEthereumTx, error) { + msgEthereumTx, err := tf.GenerateMsgEthereumTx(privKey, txArgs) + if err != nil { + return evmtypes.MsgEthereumTx{}, errorsmod.Wrap(err, "failed to create ethereum tx") + } + + return tf.SignMsgEthereumTx(privKey, msgEthereumTx) +} + +// GenerateMsgEthereumTx creates a new MsgEthereumTx with the provided arguments. +// If any of the arguments are not provided, they will be populated with default values. +func (tf *IntegrationTxFactory) GenerateMsgEthereumTx( + privKey cryptotypes.PrivKey, + txArgs evmtypes.EvmTxArgs, +) (evmtypes.MsgEthereumTx, error) { + fromAddr := common.BytesToAddress(privKey.PubKey().Address().Bytes()) + // Fill TxArgs with default values + txArgs, err := tf.populateEvmTxArgsWithDefault(fromAddr, txArgs) + if err != nil { + return evmtypes.MsgEthereumTx{}, errorsmod.Wrap(err, "failed to populate tx args") + } + msg := buildMsgEthereumTx(txArgs, fromAddr) + + return msg, nil +} + +// GenerateGethCoreMsg creates a new GethCoreMsg with the provided arguments. +func (tf *IntegrationTxFactory) GenerateGethCoreMsg( + privKey cryptotypes.PrivKey, + txArgs evmtypes.EvmTxArgs, +) (core.Message, error) { + msg, err := tf.GenerateMsgEthereumTx(privKey, txArgs) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to generate ethereum tx") + } + + signedMsg, err := tf.SignMsgEthereumTx(privKey, msg) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to sign ethereum tx") + } + + baseFeeResp, err := tf.grpcHandler.GetBaseFee() + if err != nil { + return nil, errorsmod.Wrap(err, "failed to get base fee") + } + signer := gethtypes.LatestSignerForChainID( + tf.network.GetEIP155ChainID(), + ) + return signedMsg.AsMessage(signer, baseFeeResp.BaseFee.BigInt()) +} + +// GenerateContractCallArgs generates the txArgs for a contract call. +func (tf *IntegrationTxFactory) GenerateContractCallArgs( + txArgs evmtypes.EvmTxArgs, + callArgs CallArgs, +) (evmtypes.EvmTxArgs, error) { + input, err := callArgs.ContractABI.Pack(callArgs.MethodName, callArgs.Args...) + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrap(err, "failed to pack contract arguments") + } + txArgs.Input = input + return txArgs, nil +} + +// GenerateDeployContractArgs generates the txArgs for a contract deployment. +func (tf *IntegrationTxFactory) GenerateDeployContractArgs( + from common.Address, + txArgs evmtypes.EvmTxArgs, + deploymentData ContractDeploymentData, +) (evmtypes.EvmTxArgs, error) { + account, err := tf.grpcHandler.GetEvmAccount(from) + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrapf(err, "failed to get evm account: %s", from.String()) + } + txArgs.Nonce = account.GetNonce() + + ctorArgs, err := deploymentData.Contract.ABI.Pack("", deploymentData.ConstructorArgs...) + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrap(err, "failed to pack constructor arguments") + } + data := deploymentData.Contract.Bin + data = append(data, ctorArgs...) + + txArgs.Input = data + return txArgs, nil +} diff --git a/testutil/integration/os/factory/factory.go b/testutil/integration/os/factory/factory.go new file mode 100644 index 00000000..9aedad78 --- /dev/null +++ b/testutil/integration/os/factory/factory.go @@ -0,0 +1,209 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "fmt" + "math/big" + "strings" + + errorsmod "cosmossdk.io/errors" + abcitypes "github.com/cometbft/cometbft/abci/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + testutiltypes "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/gogoproto/proto" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/evmos/os/precompiles/testutil" + commonfactory "github.com/evmos/os/testutil/integration/common/factory" + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/evmos/os/x/evm/core/vm" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// TxFactory defines a struct that can build and broadcast transactions for the Evmos +// network. +// Methods are organized by build sign and broadcast type methods. +type TxFactory interface { + commonfactory.CoreTxFactory + + // GenerateDefaultTxTypeArgs generates a default ETH tx args for the desired tx type + GenerateDefaultTxTypeArgs(sender common.Address, txType int) (evmtypes.EvmTxArgs, error) + // GenerateSignedEthTx generates an Ethereum tx with the provided private key and txArgs but does not broadcast it. + GenerateSignedEthTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (signing.Tx, error) + // GenerateSignedMsgEthereumTx generates an MsgEthereumTx signed with the provided private key and txArgs. + GenerateSignedMsgEthereumTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (evmtypes.MsgEthereumTx, error) + + // SignMsgEthereumTx signs a MsgEthereumTx with the provided private key. + SignMsgEthereumTx(privKey cryptotypes.PrivKey, msgEthereumTx evmtypes.MsgEthereumTx) (evmtypes.MsgEthereumTx, error) + + // ExecuteEthTx builds, signs and broadcasts an Ethereum tx with the provided private key and txArgs. + // If the txArgs are not provided, they will be populated with default values or gas estimations. + ExecuteEthTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (abcitypes.ExecTxResult, error) + // ExecuteContractCall executes a contract call with the provided private key + ExecuteContractCall(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs, callArgs CallArgs) (abcitypes.ExecTxResult, error) + // DeployContract deploys a contract with the provided private key, + // compiled contract data and constructor arguments + DeployContract(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs, deploymentData ContractDeploymentData) (common.Address, error) + // CallContractAndCheckLogs is a helper function to call a contract and check the logs using + // the integration test utilities. + // + // It returns the Cosmos Tx response, the decoded Ethereum Tx response and an error. This error value + // is nil, if the expected logs are found and the VM error is the expected one, should one be expected. + CallContractAndCheckLogs(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs, callArgs CallArgs, logCheckArgs testutil.LogCheckArgs) (abcitypes.ExecTxResult, *evmtypes.MsgEthereumTxResponse, error) + // GenerateDeployContractArgs generates the txArgs for a contract deployment. + GenerateDeployContractArgs(from common.Address, txArgs evmtypes.EvmTxArgs, deploymentData ContractDeploymentData) (evmtypes.EvmTxArgs, error) + // GenerateContractCallArgs generates the txArgs for a contract call. + GenerateContractCallArgs(txArgs evmtypes.EvmTxArgs, callArgs CallArgs) (evmtypes.EvmTxArgs, error) + // GenerateMsgEthereumTx creates a new MsgEthereumTx with the provided arguments. + GenerateMsgEthereumTx(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (evmtypes.MsgEthereumTx, error) + // GenerateGethCoreMsg creates a new GethCoreMsg with the provided arguments. + GenerateGethCoreMsg(privKey cryptotypes.PrivKey, txArgs evmtypes.EvmTxArgs) (core.Message, error) + // EstimateGasLimit estimates the gas limit for a tx with the provided address and txArgs + EstimateGasLimit(from *common.Address, txArgs *evmtypes.EvmTxArgs) (uint64, error) + // GetEvmTransactionResponseFromTxResult returns the MsgEthereumTxResponse from the provided txResult + GetEvmTransactionResponseFromTxResult(txResult abcitypes.ExecTxResult) (*evmtypes.MsgEthereumTxResponse, error) +} + +var _ TxFactory = (*IntegrationTxFactory)(nil) + +// IntegrationTxFactory is a helper struct to build and broadcast transactions +// to the network on integration tests. This is to simulate the behavior of a real user. +type IntegrationTxFactory struct { + commonfactory.CoreTxFactory + + grpcHandler grpc.Handler + network network.Network + ec testutiltypes.TestEncodingConfig +} + +// New creates a new IntegrationTxFactory instance +func New( + network network.Network, + grpcHandler grpc.Handler, +) TxFactory { + cf := commonfactory.New(network, grpcHandler) + return &IntegrationTxFactory{ + CoreTxFactory: cf, + grpcHandler: grpcHandler, + network: network, + ec: network.GetEncodingConfig(), + } +} + +// GetEvmTransactionResponseFromTxResult returns the MsgEthereumTxResponse from the provided txResult. +func (tf *IntegrationTxFactory) GetEvmTransactionResponseFromTxResult( + txResult abcitypes.ExecTxResult, +) (*evmtypes.MsgEthereumTxResponse, error) { + var txData sdktypes.TxMsgData + if err := tf.ec.Codec.Unmarshal(txResult.Data, &txData); err != nil { + return nil, errorsmod.Wrap(err, "failed to unmarshal tx data") + } + + if len(txData.MsgResponses) != 1 { + return nil, fmt.Errorf("expected 1 message response, got %d", len(txData.MsgResponses)) + } + + var evmRes evmtypes.MsgEthereumTxResponse + if err := proto.Unmarshal(txData.MsgResponses[0].Value, &evmRes); err != nil { + return nil, errorsmod.Wrap(err, "failed to unmarshal evm tx response") + } + + return &evmRes, nil +} + +// populateEvmTxArgsWithDefault populates the missing fields in the provided EvmTxArgs with default values. +// If no GasLimit is present it will estimate the gas needed for the transaction. +func (tf *IntegrationTxFactory) populateEvmTxArgsWithDefault( + fromAddr common.Address, + txArgs evmtypes.EvmTxArgs, +) (evmtypes.EvmTxArgs, error) { + if txArgs.ChainID == nil { + txArgs.ChainID = tf.network.GetEIP155ChainID() + } + + if txArgs.Nonce == 0 { + accountResp, err := tf.grpcHandler.GetEvmAccount(fromAddr) + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrapf(err, "failed to get evm account: %s", fromAddr.String()) + } + txArgs.Nonce = accountResp.GetNonce() + } + + // If there is no GasPrice it is assumed this is a DynamicFeeTx. + // If fields are empty they are populated with current dynamic values. + if txArgs.GasPrice == nil { + if txArgs.GasTipCap == nil { + txArgs.GasTipCap = big.NewInt(1) + } + if txArgs.GasFeeCap == nil { + baseFeeResp, err := tf.grpcHandler.GetEvmBaseFee() + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrap(err, "failed to get base fee") + } + txArgs.GasFeeCap = baseFeeResp.BaseFee.BigInt() + } + } + + // If the gas limit is not set, estimate it + // through the /simulate endpoint. + if txArgs.GasLimit == 0 { + gasLimit, err := tf.EstimateGasLimit(&fromAddr, &txArgs) + if err != nil { + return evmtypes.EvmTxArgs{}, errorsmod.Wrap(err, "failed to estimate gas limit") + } + txArgs.GasLimit = gasLimit + } + + return txArgs, nil +} + +func (tf *IntegrationTxFactory) encodeTx(tx sdktypes.Tx) ([]byte, error) { + txConfig := tf.ec.TxConfig + txBytes, err := txConfig.TxEncoder()(tx) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to encode tx") + } + return txBytes, nil +} + +func (tf *IntegrationTxFactory) buildSignedTx(msg evmtypes.MsgEthereumTx) (signing.Tx, error) { + txConfig := tf.ec.TxConfig + txBuilder := txConfig.NewTxBuilder() + return msg.BuildTx(txBuilder, tf.network.GetBaseDenom()) +} + +// checkEthTxResponse checks if the response is valid and returns the MsgEthereumTxResponse +func (tf *IntegrationTxFactory) checkEthTxResponse(res *abcitypes.ExecTxResult) error { + var txData sdktypes.TxMsgData + if !res.IsOK() { + return fmt.Errorf("tx failed with Code: %d, Logs: %s", res.Code, res.Log) + } + + cdc := tf.ec.Codec + if err := cdc.Unmarshal(res.Data, &txData); err != nil { + return errorsmod.Wrap(err, "failed to unmarshal tx data") + } + + if len(txData.MsgResponses) != 1 { + return fmt.Errorf("expected 1 message response, got %d", len(txData.MsgResponses)) + } + + var evmRes evmtypes.MsgEthereumTxResponse + if err := proto.Unmarshal(txData.MsgResponses[0].Value, &evmRes); err != nil { + return errorsmod.Wrap(err, "failed to unmarshal evm tx response") + } + + if strings.Contains(evmRes.VmError, vm.ErrOutOfGas.Error()) { + return fmt.Errorf("eth tx ran out of gas; gas used: %d", evmRes.GasUsed) + } + + if evmRes.Failed() { + return fmt.Errorf("tx failed with VmError: %v, Logs: %s", evmRes.VmError, res.GetLog()) + } + return nil +} diff --git a/testutil/integration/os/factory/helpers.go b/testutil/integration/os/factory/helpers.go new file mode 100644 index 00000000..7ff4ad35 --- /dev/null +++ b/testutil/integration/os/factory/helpers.go @@ -0,0 +1,41 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package factory + +import ( + "strings" + + errorsmod "cosmossdk.io/errors" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/precompiles/testutil" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// buildMsgEthereumTx builds an Ethereum transaction from the given arguments and populates the From field. +func buildMsgEthereumTx(txArgs evmtypes.EvmTxArgs, fromAddr common.Address) evmtypes.MsgEthereumTx { + msgEthereumTx := evmtypes.NewTx(&txArgs) + msgEthereumTx.From = fromAddr.String() + return *msgEthereumTx +} + +// CheckError is a helper function to check if the error is the expected one. +func CheckError(err error, logCheckArgs testutil.LogCheckArgs) error { + switch { + case logCheckArgs.ExpPass && err == nil: + return nil + case !logCheckArgs.ExpPass && err == nil: + return errorsmod.Wrap(err, "expected error but got none") + case logCheckArgs.ExpPass && err != nil: + return errorsmod.Wrap(err, "expected no error but got one") + case logCheckArgs.ErrContains == "": + // NOTE: if err contains is empty, we return the error as it is + return errorsmod.Wrap(err, "ErrContains needs to be filled") + case err == nil: + panic("unexpected state: err is nil; this should not happen") + case !strings.Contains(err.Error(), logCheckArgs.ErrContains): + return errorsmod.Wrapf(err, "expected different error; wanted %q", logCheckArgs.ErrContains) + } + + return nil +} diff --git a/testutil/integration/os/factory/sign.go b/testutil/integration/os/factory/sign.go new file mode 100644 index 00000000..376b5428 --- /dev/null +++ b/testutil/integration/os/factory/sign.go @@ -0,0 +1,22 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package factory + +import ( + errorsmod "cosmossdk.io/errors" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + gethtypes "github.com/ethereum/go-ethereum/core/types" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/tx" +) + +// SignMsgEthereumTx signs a MsgEthereumTx with the provided private key and chainID. +func (tf *IntegrationTxFactory) SignMsgEthereumTx(privKey cryptotypes.PrivKey, msgEthereumTx evmtypes.MsgEthereumTx) (evmtypes.MsgEthereumTx, error) { + ethChainID := tf.network.GetEIP155ChainID() + signer := gethtypes.LatestSignerForChainID(ethChainID) + err := msgEthereumTx.Sign(signer, tx.NewSigner(privKey)) + if err != nil { + return evmtypes.MsgEthereumTx{}, errorsmod.Wrap(err, "failed to sign transaction") + } + return msgEthereumTx, nil +} diff --git a/testutil/integration/os/factory/types.go b/testutil/integration/os/factory/types.go new file mode 100644 index 00000000..390781bf --- /dev/null +++ b/testutil/integration/os/factory/types.go @@ -0,0 +1,44 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package factory + +import ( + sdkmath "cosmossdk.io/math" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// CosmosTxArgs contains the params to create a cosmos tx +type CosmosTxArgs struct { + // ChainID is the chain's id in cosmos format, e.g. 'evmos_9000-1' + ChainID string + // Gas to be used on the tx + Gas uint64 + // GasPrice to use on tx + GasPrice *sdkmath.Int + // Fees is the fee to be used on the tx (amount and denom) + Fees sdktypes.Coins + // FeeGranter is the account address of the fee granter + FeeGranter sdktypes.AccAddress + // Msgs slice of messages to include on the tx + Msgs []sdktypes.Msg +} + +// CallArgs is a struct to define all relevant data to call a smart contract. +type CallArgs struct { + // ContractABI is the ABI of the contract to call. + ContractABI abi.ABI + // MethodName is the name of the method to call. + MethodName string + // Args are the arguments to pass to the method. + Args []interface{} +} + +// ContractDeploymentData is a struct to define all relevant data to deploy a smart contract. +type ContractDeploymentData struct { + // Contract is the compiled contract to deploy. + Contract evmtypes.CompiledContract + // ConstructorArgs are the arguments to pass to the constructor. + ConstructorArgs []interface{} +} diff --git a/testutil/integration/os/grpc/evm.go b/testutil/integration/os/grpc/evm.go new file mode 100644 index 00000000..f3ed64ed --- /dev/null +++ b/testutil/integration/os/grpc/evm.go @@ -0,0 +1,65 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package grpc + +import ( + "context" + "errors" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" + + "github.com/evmos/os/x/evm/core/vm" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// GetEvmAccount returns the EVM account for the given address. +func (gqh *IntegrationHandler) GetEvmAccount(address common.Address) (*evmtypes.QueryAccountResponse, error) { + evmClient := gqh.network.GetEvmClient() + return evmClient.Account(context.Background(), &evmtypes.QueryAccountRequest{ + Address: address.String(), + }) +} + +// EstimateGas returns the estimated gas for the given call args. +func (gqh *IntegrationHandler) EstimateGas(args []byte, gasCap uint64) (*evmtypes.EstimateGasResponse, error) { + evmClient := gqh.network.GetEvmClient() + res, err := evmClient.EstimateGas(context.Background(), &evmtypes.EthCallRequest{ + Args: args, + GasCap: gasCap, + }) + if err != nil { + return nil, err + } + + // handle case where there's a revert related error + if res.Failed() { + if (res.VmError != vm.ErrExecutionReverted.Error()) || len(res.Ret) == 0 { + return nil, errors.New(res.VmError) + } + return nil, evmtypes.NewExecErrorWithReason(res.Ret) + } + + return res, err +} + +// GetEvmParams returns the EVM module params. +func (gqh *IntegrationHandler) GetEvmParams() (*evmtypes.QueryParamsResponse, error) { + evmClient := gqh.network.GetEvmClient() + return evmClient.Params(context.Background(), &evmtypes.QueryParamsRequest{}) +} + +// GetEvmParams returns the EVM module params. +func (gqh *IntegrationHandler) GetEvmBaseFee() (*evmtypes.QueryBaseFeeResponse, error) { + evmClient := gqh.network.GetEvmClient() + return evmClient.BaseFee(context.Background(), &evmtypes.QueryBaseFeeRequest{}) +} + +// GetBalanceFromEVM returns the balance for the given address. +func (gqh *IntegrationHandler) GetBalanceFromEVM(address sdktypes.AccAddress) (*evmtypes.QueryBalanceResponse, error) { + evmClient := gqh.network.GetEvmClient() + return evmClient.Balance(context.Background(), &evmtypes.QueryBalanceRequest{ + Address: common.BytesToAddress(address).Hex(), + }) +} diff --git a/testutil/integration/os/grpc/feemarket.go b/testutil/integration/os/grpc/feemarket.go new file mode 100644 index 00000000..d5094ba9 --- /dev/null +++ b/testutil/integration/os/grpc/feemarket.go @@ -0,0 +1,21 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package grpc + +import ( + "context" + + feemarkettypes "github.com/evmos/os/x/feemarket/types" +) + +// GetBaseFee returns the base fee from the feemarket module. +func (gqh *IntegrationHandler) GetBaseFee() (*feemarkettypes.QueryBaseFeeResponse, error) { + feeMarketClient := gqh.network.GetFeeMarketClient() + return feeMarketClient.BaseFee(context.Background(), &feemarkettypes.QueryBaseFeeRequest{}) +} + +// GetBaseFee returns the base fee from the feemarket module. +func (gqh *IntegrationHandler) GetFeeMarketParams() (*feemarkettypes.QueryParamsResponse, error) { + feeMarketClient := gqh.network.GetFeeMarketClient() + return feeMarketClient.Params(context.Background(), &feemarkettypes.QueryParamsRequest{}) +} diff --git a/testutil/integration/os/grpc/gov.go b/testutil/integration/os/grpc/gov.go new file mode 100644 index 00000000..e916c7d8 --- /dev/null +++ b/testutil/integration/os/grpc/gov.go @@ -0,0 +1,28 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + "fmt" + "slices" + + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +// GetGovParams returns the gov params from the gov module. +func (gqh *IntegrationHandler) GetGovParams(paramsType string) (*govtypes.QueryParamsResponse, error) { + possibleTypes := []string{"deposit", "tallying", "voting"} + if !slices.Contains(possibleTypes, paramsType) { + return nil, fmt.Errorf("invalid params type: %s\npossible types: %s", paramsType, possibleTypes) + } + + govClient := gqh.network.GetGovClient() + return govClient.Params(gqh.network.GetContext(), &govtypes.QueryParamsRequest{ParamsType: paramsType}) +} + +// GetProposal returns the proposal from the gov module. +func (gqh *IntegrationHandler) GetProposal(proposalID uint64) (*govtypes.QueryProposalResponse, error) { + govClient := gqh.network.GetGovClient() + return govClient.Proposal(gqh.network.GetContext(), &govtypes.QueryProposalRequest{ProposalId: proposalID}) +} diff --git a/testutil/integration/os/grpc/grpc.go b/testutil/integration/os/grpc/grpc.go new file mode 100644 index 00000000..659958c1 --- /dev/null +++ b/testutil/integration/os/grpc/grpc.go @@ -0,0 +1,55 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package grpc + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/ethereum/go-ethereum/common" + commongrpc "github.com/evmos/os/testutil/integration/common/grpc" + evmtypes "github.com/evmos/os/x/evm/types" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// Handler is an interface that defines the methods that are used to query +// the network's modules via gRPC. +type Handler interface { + commongrpc.Handler + + // EVM methods + GetEvmAccount(address common.Address) (*evmtypes.QueryAccountResponse, error) + EstimateGas(args []byte, GasCap uint64) (*evmtypes.EstimateGasResponse, error) + GetEvmParams() (*evmtypes.QueryParamsResponse, error) + GetEvmBaseFee() (*evmtypes.QueryBaseFeeResponse, error) + GetBalanceFromEVM(address sdk.AccAddress) (*evmtypes.QueryBalanceResponse, error) + + // FeeMarket methods + GetBaseFee() (*feemarkettypes.QueryBaseFeeResponse, error) + GetFeeMarketParams() (*feemarkettypes.QueryParamsResponse, error) + + // Gov methods + GetProposal(proposalID uint64) (*govtypes.QueryProposalResponse, error) + GetGovParams(paramsType string) (*govtypes.QueryParamsResponse, error) +} + +var _ Handler = (*IntegrationHandler)(nil) + +// IntegrationHandler is a helper struct to query the network's modules +// via gRPC. This is to simulate the behavior of a real user and avoid querying +// the modules directly. +type IntegrationHandler struct { + // We take the IntegrationHandler from common/grpc to get the common methods. + *commongrpc.IntegrationHandler + network network.Network +} + +// NewIntegrationHandler creates a new IntegrationHandler instance. +func NewIntegrationHandler(network network.Network) Handler { + return &IntegrationHandler{ + // Is there a better way to do this? + IntegrationHandler: commongrpc.NewIntegrationHandler(network), + network: network, + } +} diff --git a/testutil/integration/os/keyring/keyring.go b/testutil/integration/os/keyring/keyring.go new file mode 100644 index 00000000..52fbd199 --- /dev/null +++ b/testutil/integration/os/keyring/keyring.go @@ -0,0 +1,120 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package keyring + +import ( + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + utiltx "github.com/realiotech/realio-network/testutil/tx" +) + +type Key struct { + Addr common.Address + AccAddr sdktypes.AccAddress + Priv cryptotypes.PrivKey +} + +func NewKey() Key { + addr, privKey := utiltx.NewAddrKey() + return Key{ + Addr: addr, + AccAddr: sdktypes.AccAddress(addr.Bytes()), + Priv: privKey, + } +} + +type Keyring interface { + // GetPrivKey returns the private key of the account at the given keyring index. + GetPrivKey(index int) cryptotypes.PrivKey + // GetAddr returns the address of the account at the given keyring index. + GetAddr(index int) common.Address + // GetAccAddr returns the SDK address of the account at the given keyring index. + GetAccAddr(index int) sdktypes.AccAddress + // GetAllAccAddrs returns all the SDK addresses of the accounts in the keyring. + GetAllAccAddrs() []sdktypes.AccAddress + // GetKey returns the key at the given keyring index + GetKey(index int) Key + // GetKeys returns all the keys + GetKeys() []Key + + // AddKey adds a new account to the keyring + AddKey() int + + // Sign signs message with the specified account. + Sign(index int, msg []byte) ([]byte, error) +} + +// IntegrationKeyring is a keyring designed for integration tests. +type IntegrationKeyring struct { + keys []Key +} + +var _ Keyring = (*IntegrationKeyring)(nil) + +// New returns a new keyring with nAccs accounts. +func New(nAccs int) Keyring { + accs := make([]Key, 0, nAccs) + for i := 0; i < nAccs; i++ { + acc := NewKey() + accs = append(accs, acc) + } + return &IntegrationKeyring{ + keys: accs, + } +} + +// GetPrivKey returns the private key of the specified account. +func (kr *IntegrationKeyring) GetPrivKey(index int) cryptotypes.PrivKey { + return kr.keys[index].Priv +} + +// GetAddr returns the address of the specified account. +func (kr *IntegrationKeyring) GetAddr(index int) common.Address { + return kr.keys[index].Addr +} + +// GetAccAddr returns the sdk address of the specified account. +func (kr *IntegrationKeyring) GetAccAddr(index int) sdktypes.AccAddress { + return kr.keys[index].AccAddr +} + +// GetAllAccAddrs returns all the sdk addresses of the accounts in the keyring. +func (kr *IntegrationKeyring) GetAllAccAddrs() []sdktypes.AccAddress { + accs := make([]sdktypes.AccAddress, 0, len(kr.keys)) + for _, key := range kr.keys { + accs = append(accs, key.AccAddr) + } + return accs +} + +// GetKey returns the key specified by index. +func (kr *IntegrationKeyring) GetKey(index int) Key { + return kr.keys[index] +} + +// GetKeys returns all keys from the keyring. +func (kr *IntegrationKeyring) GetKeys() []Key { + return kr.keys +} + +// AddKey adds a new account to the keyring. It returns the index for the key. +func (kr *IntegrationKeyring) AddKey() int { + acc := NewKey() + index := len(kr.keys) + kr.keys = append(kr.keys, acc) + + return index +} + +// Sign signs message with the specified key. +func (kr *IntegrationKeyring) Sign(index int, msg []byte) ([]byte, error) { + privKey := kr.GetPrivKey(index) + if privKey == nil { + return nil, fmt.Errorf("no private key for account %d", index) + } + return privKey.Sign(msg) +} diff --git a/testutil/integration/os/network/abci.go b/testutil/integration/os/network/abci.go new file mode 100644 index 00000000..b1cd2069 --- /dev/null +++ b/testutil/integration/os/network/abci.go @@ -0,0 +1,101 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "time" + + storetypes "cosmossdk.io/store/types" + abcitypes "github.com/cometbft/cometbft/abci/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmttypes "github.com/cometbft/cometbft/types" +) + +// NextBlock is a private helper function that runs the EndBlocker logic, commits the changes, +// updates the header and runs the BeginBlocker +func (n *IntegrationNetwork) NextBlock() error { + return n.NextBlockAfter(time.Second) +} + +// NextBlockAfter is a private helper function that runs the FinalizeBlock logic, updates the context and +// commits the changes to have a block time after the given duration. +func (n *IntegrationNetwork) NextBlockAfter(duration time.Duration) error { + _, err := n.finalizeBlockAndCommit(duration) + return err +} + +// NextBlockWithTxs is a helper function that runs the FinalizeBlock logic +// with the provided tx bytes, updates the context and +// commits the changes to have a block time after the given duration. +func (n *IntegrationNetwork) NextBlockWithTxs(txBytes ...[]byte) (*abcitypes.ResponseFinalizeBlock, error) { + return n.finalizeBlockAndCommit(time.Second, txBytes...) +} + +// finalizeBlockAndCommit is a private helper function that runs the FinalizeBlock logic +// with the provided txBytes, updates the context and +// commits the changes to have a block time after the given duration. +func (n *IntegrationNetwork) finalizeBlockAndCommit(duration time.Duration, txBytes ...[]byte) (*abcitypes.ResponseFinalizeBlock, error) { + header := n.ctx.BlockHeader() + // Update block header and BeginBlock + header.Height++ + header.AppHash = n.app.LastCommitID().Hash + // Calculate new block time after duration + newBlockTime := header.Time.Add(duration) + header.Time = newBlockTime + + // FinalizeBlock to run endBlock, deliverTx & beginBlock logic + req := buildFinalizeBlockReq(header, n.valSet.Validators, txBytes...) + + res, err := n.app.FinalizeBlock(req) + if err != nil { + return nil, err + } + + newCtx := n.app.BaseApp.NewContextLegacy(false, header) + + // Update context header + newCtx = newCtx.WithMinGasPrices(n.ctx.MinGasPrices()) + newCtx = newCtx.WithKVGasConfig(n.ctx.KVGasConfig()) + newCtx = newCtx.WithTransientKVGasConfig(n.ctx.TransientKVGasConfig()) + newCtx = newCtx.WithConsensusParams(n.ctx.ConsensusParams()) + // This might have to be changed with time if we want to test gas limits + newCtx = newCtx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) + newCtx = newCtx.WithVoteInfos(req.DecidedLastCommit.GetVotes()) + n.ctx = newCtx + + // commit changes + _, err = n.app.Commit() + + return res, err +} + +// buildFinalizeBlockReq is a helper function to build +// properly the FinalizeBlock request +func buildFinalizeBlockReq(header cmtproto.Header, validators []*cmttypes.Validator, txs ...[]byte) *abcitypes.RequestFinalizeBlock { + // add validator's commit info to allocate corresponding tokens to validators + ci := getCommitInfo(validators) + return &abcitypes.RequestFinalizeBlock{ + Height: header.Height, + DecidedLastCommit: ci, + Hash: header.AppHash, + NextValidatorsHash: header.ValidatorsHash, + ProposerAddress: header.ProposerAddress, + Time: header.Time, + Txs: txs, + } +} + +func getCommitInfo(validators []*cmttypes.Validator) abcitypes.CommitInfo { + voteInfos := make([]abcitypes.VoteInfo, len(validators)) + for i, val := range validators { + voteInfos[i] = abcitypes.VoteInfo{ + Validator: abcitypes.Validator{ + Address: val.Address, + Power: val.VotingPower, + }, + BlockIdFlag: cmtproto.BlockIDFlagCommit, + } + } + return abcitypes.CommitInfo{Votes: voteInfos} +} diff --git a/testutil/integration/os/network/amounts.go b/testutil/integration/os/network/amounts.go new file mode 100644 index 00000000..363db058 --- /dev/null +++ b/testutil/integration/os/network/amounts.go @@ -0,0 +1,75 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package network + +import ( + "math/big" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + testconstants "github.com/evmos/os/testutil/constants" + "github.com/evmos/os/types" + evmtypes "github.com/evmos/os/x/evm/types" +) + +type InitialAmounts struct { + Base math.Int + Evm math.Int +} + +func DefaultInitialAmounts() InitialAmounts { + baseCoinInfo := testconstants.ExampleChainCoinInfo[defaultChain] + + return InitialAmounts{ + Base: GetInitialAmount(baseCoinInfo.Decimals), + Evm: GetInitialAmount(baseCoinInfo.Decimals), + } +} + +func DefaultInitialBondedAmount() math.Int { + baseCoinInfo := testconstants.ExampleChainCoinInfo[defaultChain] + + return GetInitialBondedAmount(baseCoinInfo.Decimals) +} + +func GetInitialAmount(decimals evmtypes.Decimals) math.Int { + if err := decimals.Validate(); err != nil { + panic("unsupported decimals") + } + + // initialBalance defines the initial balance represented in 18 decimals. + initialBalance, _ := math.NewIntFromString("100_000_000_000_000_000_000_000") + + // 18 decimals is the most precise representation we can have, for this + // reason we have to divide the initial balance by the decimals value to + // have the specific representation. + return initialBalance.Quo(decimals.ConversionFactor()) +} + +func GetInitialBondedAmount(decimals evmtypes.Decimals) math.Int { + if err := decimals.Validate(); err != nil { + panic("unsupported decimals") + } + + // initialBondedAmount represents the amount of tokens that each validator will + // have initially bonded expressed in the 18 decimals representation. + sdk.DefaultPowerReduction = math.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil)) + initialBondedAmount := sdk.TokensFromConsensusPower(1, types.AttoPowerReduction) + + return initialBondedAmount.Quo(decimals.ConversionFactor()) +} + +func GetInitialBaseFeeAmount(decimals evmtypes.Decimals) math.LegacyDec { + if err := decimals.Validate(); err != nil { + panic("unsupported decimals") + } + + switch decimals { + case evmtypes.EighteenDecimals: + return math.LegacyNewDec(1_000_000_000) + case evmtypes.SixDecimals: + return math.LegacyNewDecWithPrec(1, 3) + default: + panic("base fee not specified") + } +} diff --git a/testutil/integration/os/network/chain_id_modifiers.go b/testutil/integration/os/network/chain_id_modifiers.go new file mode 100644 index 00000000..88d09998 --- /dev/null +++ b/testutil/integration/os/network/chain_id_modifiers.go @@ -0,0 +1,76 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +// +// This files contains handler for the testing suite that has to be run to +// modify the chain configuration depending on the chainID + +package network + +import ( + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testconstants "github.com/evmos/os/testutil/constants" + erc20types "github.com/evmos/os/x/erc20/types" +) + +// updateErc20GenesisStateForChainID modify the default genesis state for the +// bank module of the testing suite depending on the chainID. +func updateBankGenesisStateForChainID(bankGenesisState banktypes.GenesisState) banktypes.GenesisState { + metadata := generateBankGenesisMetadata() + bankGenesisState.DenomMetadata = []banktypes.Metadata{metadata} + + return bankGenesisState +} + +// generateBankGenesisMetadata generates the metadata +// for the Evm coin depending on the chainID. +func generateBankGenesisMetadata() banktypes.Metadata { + return banktypes.Metadata{ + Description: "The native EVM, governance and staking token of the evmOS example chain", + Base: "aevmos", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: testconstants.ExampleAttoDenom, + Exponent: 0, + }, + { + Denom: testconstants.ExampleDisplayDenom, + Exponent: 18, + }, + }, + Name: "evmOS", + Symbol: "EVMOS", + Display: testconstants.ExampleDisplayDenom, + } +} + +// updateErc20GenesisStateForChainID modify the default genesis state for the +// erc20 module on the testing suite depending on the chainID. +func updateErc20GenesisStateForChainID(chainID string, erc20GenesisState erc20types.GenesisState) erc20types.GenesisState { + erc20GenesisState.TokenPairs = updateErc20TokenPairs(chainID, erc20GenesisState.TokenPairs) + + return erc20GenesisState +} + +// updateErc20TokenPairs modifies the erc20 token pairs to use the correct +// WEVMOS depending on ChainID +func updateErc20TokenPairs(chainID string, tokenPairs []erc20types.TokenPair) []erc20types.TokenPair { + testnetAddress := GetWEVMOSContractHex(chainID) + coinInfo := testconstants.ExampleChainCoinInfo[chainID] + + mainnetAddress := GetWEVMOSContractHex(testconstants.ExampleChainID) + + updatedTokenPairs := make([]erc20types.TokenPair, len(tokenPairs)) + for i, tokenPair := range tokenPairs { + if tokenPair.Erc20Address == mainnetAddress { + updatedTokenPairs[i] = erc20types.TokenPair{ + Erc20Address: testnetAddress, + Denom: coinInfo.Denom, + Enabled: tokenPair.Enabled, + ContractOwner: tokenPair.ContractOwner, + } + } else { + updatedTokenPairs[i] = tokenPair + } + } + return updatedTokenPairs +} diff --git a/testutil/integration/os/network/clients.go b/testutil/integration/os/network/clients.go new file mode 100644 index 00000000..9aa66893 --- /dev/null +++ b/testutil/integration/os/network/clients.go @@ -0,0 +1,93 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "github.com/cosmos/cosmos-sdk/baseapp" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module/testutil" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + feemarkettypes "github.com/evmos/os/x/feemarket/types" +) + +func getQueryHelper(ctx sdktypes.Context, encCfg testutil.TestEncodingConfig) *baseapp.QueryServiceTestHelper { + interfaceRegistry := encCfg.InterfaceRegistry + // This is needed so that state changes are not committed in precompiles + // simulations. + cacheCtx, _ := ctx.CacheContext() + return baseapp.NewQueryServerTestHelper(cacheCtx, interfaceRegistry) +} + +func (n *IntegrationNetwork) GetERC20Client() erc20types.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + erc20types.RegisterQueryServer(queryHelper, n.app.Erc20Keeper) + return erc20types.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetEvmClient() evmtypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + evmtypes.RegisterQueryServer(queryHelper, n.app.EVMKeeper) + return evmtypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetGovClient() govtypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + govtypes.RegisterQueryServer(queryHelper, govkeeper.NewQueryServer(&n.app.GovKeeper)) + return govtypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetBankClient() banktypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + banktypes.RegisterQueryServer(queryHelper, n.app.BankKeeper) + return banktypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetFeeMarketClient() feemarkettypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + feemarkettypes.RegisterQueryServer(queryHelper, n.app.FeeMarketKeeper) + return feemarkettypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetAuthClient() authtypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + authtypes.RegisterQueryServer(queryHelper, authkeeper.NewQueryServer(n.app.AccountKeeper)) + return authtypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetAuthzClient() authz.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + authz.RegisterQueryServer(queryHelper, n.app.AuthzKeeper) + return authz.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetStakingClient() stakingtypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + stakingtypes.RegisterQueryServer(queryHelper, stakingkeeper.Querier{Keeper: n.app.StakingKeeper}) + return stakingtypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetDistrClient() distrtypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + distrtypes.RegisterQueryServer(queryHelper, distrkeeper.Querier{Keeper: n.app.DistrKeeper}) + return distrtypes.NewQueryClient(queryHelper) +} + +func (n *IntegrationNetwork) GetMintClient() minttypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + minttypes.RegisterQueryServer(queryHelper, mintkeeper.NewQueryServerImpl(n.app.MintKeeper)) + return minttypes.NewQueryClient(queryHelper) +} diff --git a/testutil/integration/os/network/coins.go b/testutil/integration/os/network/coins.go new file mode 100644 index 00000000..faa8f4ee --- /dev/null +++ b/testutil/integration/os/network/coins.go @@ -0,0 +1,90 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + testconstants "github.com/evmos/os/testutil/constants" + evmtypes "github.com/evmos/os/x/evm/types" +) + +type CoinInfo struct { + Denom string + Decimals evmtypes.Decimals +} + +// ChainCoins information for the coins required from the chian to operate: +// - baseCoin: represents the base coin used to pay gas fees and staking in the +// Cosmos context. +// - evmCoin: represents the evm coin used to pay Ethereum +// transactions fees. +type ChainCoins struct { + // TODO: not sure if this is an overkill. Do we want to customize the + // decimals of the base denom? Maybe not.. + baseCoin *CoinInfo + evmCoin *CoinInfo +} + +// DefaultChainCoins returns the default values used for the ChainCoins in which +// base and evm denom are the same. +func DefaultChainCoins() ChainCoins { + baseCoinInfo := testconstants.ExampleChainCoinInfo[defaultChain] + + // baseCoin is used for both base and evm coin as default.. + baseCoin := getCoinInfo(baseCoinInfo) + evmCoin := getCoinInfo(baseCoinInfo) + + return ChainCoins{ + baseCoin: &baseCoin, + evmCoin: &evmCoin, + } +} + +func getCoinInfo(coinInfo evmtypes.EvmCoinInfo) CoinInfo { + return CoinInfo{ + Denom: coinInfo.Denom, + Decimals: coinInfo.Decimals, + } +} + +func (cc ChainCoins) BaseCoin() CoinInfo { + return *cc.baseCoin +} + +func (cc ChainCoins) EVMCoin() CoinInfo { + return *cc.evmCoin +} + +func (cc ChainCoins) BaseDenom() string { + return cc.baseCoin.Denom +} + +func (cc ChainCoins) EVMDenom() string { + return cc.evmCoin.Denom +} + +func (cc ChainCoins) BaseDecimals() evmtypes.Decimals { + return cc.baseCoin.Decimals +} + +func (cc ChainCoins) EVMDecimals() evmtypes.Decimals { + return cc.evmCoin.Decimals +} + +func (cc ChainCoins) IsBaseEqualToEVM() bool { + return cc.BaseDenom() == cc.EVMDenom() +} + +// DenomDecimalsMap returns a map of unique Denom -> Decimals for the chain +// coins. +func (cc ChainCoins) DenomDecimalsMap() map[string]evmtypes.Decimals { + chainDenomDecimals := map[string]evmtypes.Decimals{ + cc.BaseDenom(): cc.BaseDecimals(), + } + + // Insert the evm denom if base and evm denom are different. + if !cc.IsBaseEqualToEVM() { + chainDenomDecimals[cc.EVMDenom()] = cc.EVMDecimals() + } + return chainDenomDecimals +} diff --git a/testutil/integration/os/network/config.go b/testutil/integration/os/network/config.go new file mode 100644 index 00000000..e18a4ef8 --- /dev/null +++ b/testutil/integration/os/network/config.go @@ -0,0 +1,206 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "fmt" + "math/big" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/baseapp" + sdktypes "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + testconstants "github.com/evmos/os/testutil/constants" + evmostypes "github.com/evmos/os/types" + evmtypes "github.com/evmos/os/x/evm/types" + testtx "github.com/realiotech/realio-network/testutil/tx" +) + +// defaultChain represents the default chain ID used in the suite setup. +var defaultChain = testconstants.ExampleChainID + +// Config defines the configuration for a chain. +// It allows for customization of the network to adjust to +// testing needs. +type Config struct { + chainID string + eip155ChainID *big.Int + + customGenesisState CustomGenesisState + + customBaseAppOpts []func(*baseapp.BaseApp) + + amountOfValidators int + operatorsAddrs []sdktypes.AccAddress + initialBondedAmount math.Int + + chainCoins ChainCoins + initialAmounts InitialAmounts + // otherCoinDenoms represents the other possible coin denominations that can be passed during + // test suite intialization to provide other coins initial balances. + otherCoinDenoms []string + preFundedAccounts []sdktypes.AccAddress + balances []banktypes.Balance +} + +type CustomGenesisState map[string]interface{} + +// DefaultConfig returns the default configuration for a chain. +func DefaultConfig() Config { + account, _ := testtx.NewAccAddressAndKey() + + return Config{ + chainID: testconstants.ExampleChainID, + eip155ChainID: big.NewInt(testconstants.ExampleEIP155ChainID), + chainCoins: DefaultChainCoins(), + initialAmounts: DefaultInitialAmounts(), + initialBondedAmount: DefaultInitialBondedAmount(), + amountOfValidators: 3, + + // Only one account besides the validators + preFundedAccounts: []sdktypes.AccAddress{account}, + + // NOTE: Per default, the balances are left empty, and the pre-funded accounts are used. + balances: nil, + customGenesisState: nil, + } +} + +// getGenAccountsAndBalances takes the network configuration and returns the used +// genesis accounts and balances. +// +// NOTE: If the balances are set, the pre-funded accounts are ignored. +func getGenAccountsAndBalances(cfg Config, validators []stakingtypes.Validator) (genAccounts []authtypes.GenesisAccount, balances []banktypes.Balance) { + if len(cfg.balances) > 0 { + balances = cfg.balances + accounts := getAccAddrsFromBalances(balances) + genAccounts = createGenesisAccounts(accounts) + } else { + genAccounts = createGenesisAccounts(cfg.preFundedAccounts) + + denomDecimals := cfg.chainCoins.DenomDecimalsMap() + + // All extra denom specified are represented with the base coin decimal. + for _, denom := range cfg.otherCoinDenoms { + denomDecimals[denom] = cfg.chainCoins.BaseDecimals() + } + + balances = createBalances(cfg.preFundedAccounts, denomDecimals) + } + + // append validators to genesis accounts and balances + valAccs := make([]sdktypes.AccAddress, len(validators)) + for i, v := range validators { + valAddr, err := sdktypes.ValAddressFromBech32(v.OperatorAddress) + if err != nil { + panic(fmt.Sprintf("failed to derive validator address from %q: %s", v.OperatorAddress, err.Error())) + } + valAccs[i] = sdktypes.AccAddress(valAddr.Bytes()) + } + genAccounts = append(genAccounts, createGenesisAccounts(valAccs)...) + + return +} + +// ConfigOption defines a function that can modify the NetworkConfig. +// The purpose of this is to force to be declarative when the default configuration +// requires to be changed. +type ConfigOption func(*Config) + +// WithChainID sets a custom chainID for the network. Changing the chainID +// change automatically also the EVM coin used. It panics if the chainID is invalid. +func WithChainID(chainID string) ConfigOption { + eip155ChainID, err := evmostypes.ParseChainID(chainID) + if err != nil { + panic(err) + } + + evmCoinInfo, found := testconstants.ExampleChainCoinInfo[chainID] + if !found { + panic(fmt.Sprintf( + "chain id %q not found in chain coin info; available: %v", + chainID, + testconstants.ExampleChainCoinInfo, + )) + } + + return func(cfg *Config) { + cfg.chainID = chainID + cfg.eip155ChainID = eip155ChainID + + if cfg.chainCoins.IsBaseEqualToEVM() { + cfg.chainCoins.baseCoin.Denom = evmCoinInfo.Denom + cfg.chainCoins.baseCoin.Decimals = evmCoinInfo.Decimals + } + cfg.chainCoins.evmCoin.Denom = evmCoinInfo.Denom + cfg.chainCoins.evmCoin.Decimals = evmCoinInfo.Decimals + } +} + +// WithAmountOfValidators sets the amount of validators for the network. +func WithAmountOfValidators(amount int) ConfigOption { + return func(cfg *Config) { + cfg.amountOfValidators = amount + } +} + +// WithPreFundedAccounts sets the pre-funded accounts for the network. +func WithPreFundedAccounts(accounts ...sdktypes.AccAddress) ConfigOption { + return func(cfg *Config) { + cfg.preFundedAccounts = accounts + } +} + +// WithBalances sets the specific balances for the pre-funded accounts, that +// are being set up for the network. +func WithBalances(balances ...banktypes.Balance) ConfigOption { + return func(cfg *Config) { + cfg.balances = append(cfg.balances, balances...) + } +} + +// WithBaseCoin sets the denom and decimals for the base coin in the network. +func WithBaseCoin(denom string, decimals uint8) ConfigOption { + return func(cfg *Config) { + cfg.chainCoins.baseCoin.Denom = denom + cfg.chainCoins.baseCoin.Decimals = evmtypes.Decimals(decimals) + } +} + +// WithEVMCoin sets the denom and decimals for the evm coin in the network. +func WithEVMCoin(_ string, _ uint8) ConfigOption { + // The evm config can be changed only via chain ID because it should be + // handled properly from the configurator. + panic("EVM coin can be changed only via ChainID: se WithChainID method") +} + +// WithCustomGenesis sets the custom genesis of the network for specific modules. +func WithCustomGenesis(customGenesis CustomGenesisState) ConfigOption { + return func(cfg *Config) { + cfg.customGenesisState = customGenesis + } +} + +// WithOtherDenoms sets other possible coin denominations for the network. +func WithOtherDenoms(otherDenoms []string) ConfigOption { + return func(cfg *Config) { + cfg.otherCoinDenoms = otherDenoms + } +} + +// WithValidatorOperators overwrites the used operator address for the network instantiation. +func WithValidatorOperators(keys []sdktypes.AccAddress) ConfigOption { + return func(cfg *Config) { + cfg.operatorsAddrs = keys + } +} + +// WithCustomBaseAppOpts sets custom base app options for the network. +func WithCustomBaseAppOpts(opts ...func(*baseapp.BaseApp)) ConfigOption { + return func(cfg *Config) { + cfg.customBaseAppOpts = opts + } +} diff --git a/testutil/integration/os/network/config_test.go b/testutil/integration/os/network/config_test.go new file mode 100644 index 00000000..4d536337 --- /dev/null +++ b/testutil/integration/os/network/config_test.go @@ -0,0 +1,140 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network_test + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testconstants "github.com/evmos/os/testutil/constants" + grpchandler "github.com/evmos/os/testutil/integration/os/grpc" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" + "github.com/stretchr/testify/require" +) + +func TestWithChainID(t *testing.T) { + testCases := []struct { + name string + chainID string + denom string + decimals evmtypes.Decimals + expBaseFee math.LegacyDec + expCosmosAmount math.Int + }{ + { + name: "18 decimals", + chainID: testconstants.ExampleChainID, + denom: testconstants.ExampleAttoDenom, + decimals: evmtypes.EighteenDecimals, + expBaseFee: math.LegacyNewDec(875_000_000), + expCosmosAmount: network.GetInitialAmount(evmtypes.EighteenDecimals), + }, + { + name: "6 decimals", + chainID: testconstants.SixDecimalsChainID, + denom: testconstants.ExampleMicroDenom, + decimals: evmtypes.SixDecimals, + expBaseFee: math.LegacyNewDecWithPrec(875, 6), + expCosmosAmount: network.GetInitialAmount(evmtypes.SixDecimals), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a new network with 2 pre-funded accounts + keyring := testkeyring.New(1) + + opts := []network.ConfigOption{ + network.WithChainID(tc.chainID), + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + } + + nw := network.New(opts...) + + handler := grpchandler.NewIntegrationHandler(nw) //nolint:staticcheck // Somehow the linter marks this as not being used, even though it's used below to get balances + + // reset configuration to use the correct decimals coin info + configurator := evmtypes.NewEVMConfigurator() + configurator.ResetTestConfig() + require.NoError(t, configurator.WithEVMCoinInfo(tc.denom, uint8(tc.decimals)).Configure()) + + // ------------------------------------------------------------------------------------ + // Checks on initial balances. + // ------------------------------------------------------------------------------------ + + // Evm balance should always be in 18 decimals regardless of the + // chain ID. + + // Evm balance should always be in 18 decimals + req, err := handler.GetBalanceFromEVM(keyring.GetAccAddr(0)) + require.NoError(t, err, "error getting balances") + require.Equal(t, + network.GetInitialAmount(evmtypes.EighteenDecimals).String(), + req.Balance, + "expected amount to be in 18 decimals", + ) + + // Bank balance should always be in the original amount. + cReq, err := handler.GetBalanceFromBank(keyring.GetAccAddr(0), tc.denom) + require.NoError(t, err, "error getting balances") + require.Equal(t, + tc.expCosmosAmount.String(), + cReq.Balance.Amount.String(), + "expected amount to be in original decimals", + ) + + // ------------------------------------------------------------------------------------ + // Checks on the base fee. + // ------------------------------------------------------------------------------------ + // Base fee should always be represented with the decimal + // representation of the EVM denom coin. + bfResp, err := handler.GetBaseFee() + require.NoError(t, err, "error getting base fee") + require.Equal(t, + tc.expBaseFee.String(), + bfResp.BaseFee.String(), + "expected amount to be in 18 decimals", + ) + }) + } +} + +func TestWithBalances(t *testing.T) { + key1Balance := sdk.NewCoins(sdk.NewInt64Coin(testconstants.ExampleAttoDenom, 1e18)) + key2Balance := sdk.NewCoins( + sdk.NewInt64Coin(testconstants.ExampleAttoDenom, 2e18), + sdk.NewInt64Coin("other", 3e18), + ) + + // Create a new network with 2 pre-funded accounts + keyring := testkeyring.New(2) + balances := []banktypes.Balance{ + { + Address: keyring.GetAccAddr(0).String(), + Coins: key1Balance, + }, + { + Address: keyring.GetAccAddr(1).String(), + Coins: key2Balance, + }, + } + nw := network.New( + network.WithBalances(balances...), + ) + handler := grpchandler.NewIntegrationHandler(nw) + + req, err := handler.GetAllBalances(keyring.GetAccAddr(0)) + require.NoError(t, err, "error getting balances") + require.Len(t, req.Balances, 1, "wrong number of balances") + require.Equal(t, balances[0].Coins, req.Balances, "wrong balances") + + req, err = handler.GetAllBalances(keyring.GetAccAddr(1)) + require.NoError(t, err, "error getting balances") + require.Len(t, req.Balances, 2, "wrong number of balances") + require.Equal(t, balances[1].Coins, req.Balances, "wrong balances") +} diff --git a/testutil/integration/os/network/example_contracts.go b/testutil/integration/os/network/example_contracts.go new file mode 100644 index 00000000..429034e5 --- /dev/null +++ b/testutil/integration/os/network/example_contracts.go @@ -0,0 +1,30 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + testconstants "github.com/evmos/os/testutil/constants" +) + +// chainsWEVMOSHex is an utility map used to retrieve the WEVMOS contract +// address in hex format from the chain ID. +// +// TODO: refactor to define this in the example chain initialization and pass as function argument +var chainsWEVMOSHex = map[string]string{ + testconstants.ExampleChainID: testconstants.WEVMOSContractMainnet, +} + +// GetWEVMOSContractHex returns the hex format of address for the WEVMOS contract +// given the chainID. If the chainID is not found, it defaults to the mainnet +// address. +func GetWEVMOSContractHex(chainID string) string { + address, found := chainsWEVMOSHex[chainID] + + // default to mainnet address + if !found { + address = chainsWEVMOSHex[testconstants.ExampleChainID] + } + + return address +} diff --git a/testutil/integration/os/network/ibc.go b/testutil/integration/os/network/ibc.go new file mode 100644 index 00000000..2297be90 --- /dev/null +++ b/testutil/integration/os/network/ibc.go @@ -0,0 +1,29 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "testing" + + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +// GetIBCChain returns a TestChain instance for the given network. +// Note: the sender accounts are not populated. Do not use this accounts to send transactions during tests. +// The keyring should be used instead. +func (n *IntegrationNetwork) GetIBCChain(t *testing.T, coord *ibctesting.Coordinator) *ibctesting.TestChain { + return &ibctesting.TestChain{ + TB: t, + Coordinator: coord, + ChainID: n.GetChainID(), + App: n.app, + CurrentHeader: n.ctx.BlockHeader(), + QueryServer: n.app.GetIBCKeeper(), + TxConfig: n.app.GetTxConfig(), + Codec: n.app.AppCodec(), + Vals: n.valSet, + NextVals: n.valSet, + Signers: n.valSigners, + } +} diff --git a/testutil/integration/os/network/network.go b/testutil/integration/os/network/network.go new file mode 100644 index 00000000..5ea49b17 --- /dev/null +++ b/testutil/integration/os/network/network.go @@ -0,0 +1,358 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "fmt" + "math" + "math/big" + "time" + + sdkmath "cosmossdk.io/math" + abcitypes "github.com/cometbft/cometbft/abci/types" + cmtjson "github.com/cometbft/cometbft/libs/json" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmversion "github.com/cometbft/cometbft/proto/tendermint/version" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cometbft/cometbft/version" + sdktypes "github.com/cosmos/cosmos-sdk/types" + sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + gethparams "github.com/ethereum/go-ethereum/params" + chainutil "github.com/realiotech/realio-network/example_chain/testutil" + commonnetwork "github.com/evmos/os/testutil/integration/common/network" + "github.com/evmos/os/types" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + app "github.com/realiotech/realio-network/example_chain" +) + +// Network is the interface that wraps the methods to interact with integration test network. +// +// It was designed to avoid users to access module's keepers directly and force integration tests +// to be closer to the real user's behavior. +type Network interface { + commonnetwork.Network + + GetEIP155ChainID() *big.Int + GetEVMChainConfig() *gethparams.ChainConfig + + // Clients + GetERC20Client() erc20types.QueryClient + GetEvmClient() evmtypes.QueryClient + GetGovClient() govtypes.QueryClient + GetFeeMarketClient() feemarkettypes.QueryClient + GetMintClient() minttypes.QueryClient +} + +var _ Network = (*IntegrationNetwork)(nil) + +// IntegrationNetwork is the implementation of the Network interface for integration tests. +type IntegrationNetwork struct { + cfg Config + ctx sdktypes.Context + validators []stakingtypes.Validator + app *app.ExampleChain + + // This is only needed for IBC chain testing setup + valSet *cmttypes.ValidatorSet + valSigners map[string]cmttypes.PrivValidator +} + +// New configures and initializes a new integration Network instance with +// the given configuration options. If no configuration options are provided +// it uses the default configuration. +// +// It panics if an error occurs. +func New(opts ...ConfigOption) *IntegrationNetwork { + cfg := DefaultConfig() + // Modify the default config with the given options + for _, opt := range opts { + opt(&cfg) + } + + ctx := sdktypes.Context{} + network := &IntegrationNetwork{ + cfg: cfg, + ctx: ctx, + validators: []stakingtypes.Validator{}, + } + + err := network.configureAndInitChain() + if err != nil { + panic(err) + } + return network +} + +// PrefundedAccountInitialBalance is the amount of tokens that each +// prefunded account has at genesis. It represents a 100k amount expressed +// in the 18 decimals representation. +var PrefundedAccountInitialBalance, _ = sdkmath.NewIntFromString("100_000_000_000_000_000_000_000") + +// configureAndInitChain initializes the network with the given configuration. +// It creates the genesis state and starts the network. +func (n *IntegrationNetwork) configureAndInitChain() error { + // -------------------------------------------------------------------------------------------- + // Apply changes deriving from possible config options + // FIX: for sure there exists a better way to achieve that. + // -------------------------------------------------------------------------------------------- + + // The bonded amount should be updated to reflect the actual base denom + baseDecimals := n.cfg.chainCoins.BaseDecimals() + bondedAmount := GetInitialBondedAmount(baseDecimals) + + // Create validator set with the amount of validators specified in the config + // with the default power of 1. + valSet, valSigners := createValidatorSetAndSigners(n.cfg.amountOfValidators) + totalBonded := bondedAmount.Mul(sdkmath.NewInt(int64(n.cfg.amountOfValidators))) + + // Build staking type validators and delegations + validators, err := createStakingValidators(valSet.Validators, bondedAmount, n.cfg.operatorsAddrs) + if err != nil { + return err + } + + // Create genesis accounts and funded balances based on the config. + genAccounts, fundedAccountBalances := getGenAccountsAndBalances(n.cfg, validators) + + fundedAccountBalances = addBondedModuleAccountToFundedBalances( + fundedAccountBalances, + sdktypes.NewCoin(n.cfg.chainCoins.BaseDenom(), totalBonded), + ) + + delegations := createDelegations(validators, genAccounts[0].GetAddress()) + + // Create a new testing app with the following params + exampleApp := createTestingApp(n.cfg.chainID, n.cfg.customBaseAppOpts...) + + stakingParams := StakingCustomGenesisState{ + denom: n.cfg.chainCoins.BaseDenom(), + validators: validators, + delegations: delegations, + } + govParams := GovCustomGenesisState{ + denom: n.cfg.chainCoins.BaseDenom(), + } + + fmParams := FeeMarketCustomGenesisState{ + baseFee: GetInitialBaseFeeAmount(n.cfg.chainCoins.BaseDecimals()), + } + + mintParams := MintCustomGenesisState{ + denom: n.cfg.chainCoins.BaseDenom(), + inflationMax: sdkmath.LegacyNewDecWithPrec(0, 1), + inflationMin: sdkmath.LegacyNewDecWithPrec(0, 1), + } + + totalSupply := calculateTotalSupply(fundedAccountBalances) + bankParams := BankCustomGenesisState{ + totalSupply: totalSupply, + balances: fundedAccountBalances, + } + + // Get the corresponding slashing info and missed block info + // for the created validators + slashingParams, err := getValidatorsSlashingGen(validators, exampleApp.StakingKeeper) + if err != nil { + return err + } + + // Configure Genesis state + genesisState := newDefaultGenesisState( + exampleApp, + defaultGenesisParams{ + genAccounts: genAccounts, + staking: stakingParams, + bank: bankParams, + feemarket: fmParams, + slashing: slashingParams, + gov: govParams, + mint: mintParams, + }, + ) + + fmt.Println("genesisState", genesisState["asset"]) + + // modify genesis state if there're any custom genesis state + // for specific modules + genesisState, err = customizeGenesis(exampleApp, n.cfg.customGenesisState, genesisState) + if err != nil { + return err + } + + // Init chain + stateBytes, err := cmtjson.MarshalIndent(genesisState, "", " ") + if err != nil { + return err + } + + consensusParams := chainutil.DefaultConsensusParams + now := time.Now() + + if _, err = exampleApp.InitChain( + &abcitypes.RequestInitChain{ + Time: now, + ChainId: n.cfg.chainID, + Validators: []abcitypes.ValidatorUpdate{}, + ConsensusParams: consensusParams, + AppStateBytes: stateBytes, + }, + ); err != nil { + return err + } + + header := cmtproto.Header{ + ChainID: n.cfg.chainID, + Height: exampleApp.LastBlockHeight() + 1, + AppHash: exampleApp.LastCommitID().Hash, + Time: now, + ValidatorsHash: valSet.Hash(), + NextValidatorsHash: valSet.Hash(), + ProposerAddress: valSet.Proposer.Address, + Version: tmversion.Consensus{ + Block: version.BlockProtocol, + }, + } + + req := buildFinalizeBlockReq(header, valSet.Validators) + if _, err := exampleApp.FinalizeBlock(req); err != nil { + return err + } + + // TODO - this might not be the best way to initilize the context + n.ctx = exampleApp.BaseApp.NewContextLegacy(false, header) + + // Commit genesis changes + if _, err := exampleApp.Commit(); err != nil { + return err + } + + // Set networks global parameters + var blockMaxGas uint64 = math.MaxUint64 + if consensusParams.Block != nil && consensusParams.Block.MaxGas > 0 { + blockMaxGas = uint64(consensusParams.Block.MaxGas) //#nosec G115 -- max gas will not exceed uint64 + } + + n.app = exampleApp + n.ctx = n.ctx.WithConsensusParams(*consensusParams) + n.ctx = n.ctx.WithBlockGasMeter(types.NewInfiniteGasMeterWithLimit(blockMaxGas)) + + n.validators = validators + n.valSet = valSet + n.valSigners = valSigners + + return nil +} + +// GetContext returns the network's context +func (n *IntegrationNetwork) GetContext() sdktypes.Context { + return n.ctx +} + +// WithIsCheckTxCtx switches the network's checkTx property +func (n *IntegrationNetwork) WithIsCheckTxCtx(isCheckTx bool) sdktypes.Context { + n.ctx = n.ctx.WithIsCheckTx(isCheckTx) + return n.ctx +} + +// GetChainID returns the network's chainID +func (n *IntegrationNetwork) GetChainID() string { + return n.cfg.chainID +} + +// GetEIP155ChainID returns the network EIP-155 chainID number +func (n *IntegrationNetwork) GetEIP155ChainID() *big.Int { + return n.cfg.eip155ChainID +} + +// GetEVMChainConfig returns the network's EVM chain config +func (n *IntegrationNetwork) GetEVMChainConfig() *gethparams.ChainConfig { + return evmtypes.GetEthChainConfig() +} + +// GetBaseDenom returns the network's base denom +func (n *IntegrationNetwork) GetBaseDenom() string { + return n.cfg.chainCoins.baseCoin.Denom +} + +// GetEVMDenom returns the network's evm denom +func (n *IntegrationNetwork) GetEVMDenom() string { + return n.cfg.chainCoins.evmCoin.Denom +} + +// GetOtherDenoms returns network's other supported denoms +func (n *IntegrationNetwork) GetOtherDenoms() []string { + return n.cfg.otherCoinDenoms +} + +// GetValidators returns the network's validators +func (n *IntegrationNetwork) GetValidators() []stakingtypes.Validator { + return n.validators +} + +// GetEncodingConfig returns the network's encoding configuration +func (n *IntegrationNetwork) GetEncodingConfig() sdktestutil.TestEncodingConfig { + return sdktestutil.TestEncodingConfig{ + InterfaceRegistry: n.app.InterfaceRegistry(), + Codec: n.app.AppCodec(), + TxConfig: n.app.GetTxConfig(), + Amino: n.app.LegacyAmino(), + } +} + +// BroadcastTxSync broadcasts the given txBytes to the network and returns the response. +// TODO - this should be change to gRPC +func (n *IntegrationNetwork) BroadcastTxSync(txBytes []byte) (abcitypes.ExecTxResult, error) { + header := n.ctx.BlockHeader() + // Update block header and BeginBlock + header.Height++ + header.AppHash = n.app.LastCommitID().Hash + // Calculate new block time after duration + newBlockTime := header.Time.Add(time.Second) + header.Time = newBlockTime + + req := buildFinalizeBlockReq(header, n.valSet.Validators, txBytes) + + // dont include the DecidedLastCommit because we're not committing the changes + // here, is just for broadcasting the tx. To persist the changes, use the + // NextBlock or NextBlockAfter functions + req.DecidedLastCommit = abcitypes.CommitInfo{} + + blockRes, err := n.app.BaseApp.FinalizeBlock(req) + if err != nil { + return abcitypes.ExecTxResult{}, err + } + if len(blockRes.TxResults) != 1 { + return abcitypes.ExecTxResult{}, fmt.Errorf("unexpected number of tx results. Expected 1, got: %d", len(blockRes.TxResults)) + } + return *blockRes.TxResults[0], nil +} + +// Simulate simulates the given txBytes to the network and returns the simulated response. +// TODO - this should be change to gRPC +func (n *IntegrationNetwork) Simulate(txBytes []byte) (*txtypes.SimulateResponse, error) { + gas, result, err := n.app.BaseApp.Simulate(txBytes) + if err != nil { + return nil, err + } + return &txtypes.SimulateResponse{ + GasInfo: &gas, + Result: result, + }, nil +} + +// CheckTx calls the BaseApp's CheckTx method with the given txBytes to the network and returns the response. +func (n *IntegrationNetwork) CheckTx(txBytes []byte) (*abcitypes.ResponseCheckTx, error) { + req := &abcitypes.RequestCheckTx{Tx: txBytes} + res, err := n.app.BaseApp.CheckTx(req) + if err != nil { + return nil, err + } + return res, nil +} diff --git a/testutil/integration/os/network/setup.go b/testutil/integration/os/network/setup.go new file mode 100644 index 00000000..0b51c9ca --- /dev/null +++ b/testutil/integration/os/network/setup.go @@ -0,0 +1,540 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + "fmt" + "slices" + "time" + + "golang.org/x/exp/maps" + + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + cmttypes "github.com/cometbft/cometbft/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simutils "github.com/cosmos/cosmos-sdk/testutil/sims" + sdktypes "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/gogoproto/proto" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + exampleapp "github.com/realiotech/realio-network/example_chain" + evmostypes "github.com/evmos/os/types" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + assettypes "github.com/realiotech/realio-network/x/asset/types" +) + +// genSetupFn is the type for the module genesis setup functions +type genSetupFn func(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, customGenesis interface{}) (evmostypes.GenesisState, error) + +// defaultGenesisParams contains the params that are needed to +// setup the default genesis for the testing setup +type defaultGenesisParams struct { + genAccounts []authtypes.GenesisAccount + staking StakingCustomGenesisState + slashing SlashingCustomGenesisState + bank BankCustomGenesisState + gov GovCustomGenesisState + mint MintCustomGenesisState + feemarket FeeMarketCustomGenesisState +} + +// genesisSetupFunctions contains the available genesis setup functions +// that can be used to customize the network genesis +var genesisSetupFunctions = map[string]genSetupFn{ + evmtypes.ModuleName: genStateSetter[*evmtypes.GenesisState](evmtypes.ModuleName), + erc20types.ModuleName: genStateSetter[*erc20types.GenesisState](erc20types.ModuleName), + govtypes.ModuleName: genStateSetter[*govtypesv1.GenesisState](govtypes.ModuleName), + feemarkettypes.ModuleName: genStateSetter[*feemarkettypes.GenesisState](feemarkettypes.ModuleName), + distrtypes.ModuleName: genStateSetter[*distrtypes.GenesisState](distrtypes.ModuleName), + minttypes.ModuleName: genStateSetter[*minttypes.GenesisState](minttypes.ModuleName), + banktypes.ModuleName: setBankGenesisState, + authtypes.ModuleName: setAuthGenesisState, + consensustypes.ModuleName: func(_ *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, _ interface{}) (evmostypes.GenesisState, error) { + // no-op. Consensus does not have a genesis state on the application + // but the params are used on it + // (e.g. block max gas, max bytes). + // This is handled accordingly on chain and context initialization + return genesisState, nil + }, + capabilitytypes.ModuleName: genStateSetter[*capabilitytypes.GenesisState](capabilitytypes.ModuleName), +} + +// genStateSetter is a generic function to set module-specific genesis state +func genStateSetter[T proto.Message](moduleName string) genSetupFn { + return func(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, customGenesis interface{}) (evmostypes.GenesisState, error) { + moduleGenesis, ok := customGenesis.(T) + if !ok { + return nil, fmt.Errorf("invalid type %T for %s module genesis state", customGenesis, moduleName) + } + + genesisState[moduleName] = evmosApp.AppCodec().MustMarshalJSON(moduleGenesis) + return genesisState, nil + } +} + +// createValidatorSetAndSigners creates validator set with the amount of validators specified +// with the default power of 1. +func createValidatorSetAndSigners(numberOfValidators int) (*cmttypes.ValidatorSet, map[string]cmttypes.PrivValidator) { + // Create validator set + tmValidators := make([]*cmttypes.Validator, 0, numberOfValidators) + signers := make(map[string]cmttypes.PrivValidator, numberOfValidators) + + for i := 0; i < numberOfValidators; i++ { + privVal := mock.NewPV() + pubKey, _ := privVal.GetPubKey() + validator := cmttypes.NewValidator(pubKey, 1) + tmValidators = append(tmValidators, validator) + signers[pubKey.Address().String()] = privVal + } + + return cmttypes.NewValidatorSet(tmValidators), signers +} + +// createGenesisAccounts returns a slice of genesis accounts from the given +// account addresses. +func createGenesisAccounts(accounts []sdktypes.AccAddress) []authtypes.GenesisAccount { + numberOfAccounts := len(accounts) + genAccounts := make([]authtypes.GenesisAccount, 0, numberOfAccounts) + for _, acc := range accounts { + genAccounts = append(genAccounts, authtypes.NewBaseAccount( + acc, nil, 0, 0), + ) + } + return genAccounts +} + +// getAccAddrsFromBalances returns a slice of genesis accounts from the +// given balances. +func getAccAddrsFromBalances(balances []banktypes.Balance) []sdktypes.AccAddress { + numberOfBalances := len(balances) + genAccounts := make([]sdktypes.AccAddress, 0, numberOfBalances) + for _, balance := range balances { + genAccounts = append(genAccounts, sdktypes.AccAddress(balance.Address)) + } + return genAccounts +} + +// createBalances creates balances for the given accounts and coin. Depending on +// the decimal representation of the denom, the amount is scaled to have the +// same value for all denoms. +func createBalances( + accounts []sdktypes.AccAddress, + denomDecimals map[string]evmtypes.Decimals, +) []banktypes.Balance { + numberOfAccounts := len(accounts) + + denoms := maps.Keys(denomDecimals) + slices.Sort(denoms) + + coins := make([]sdktypes.Coin, len(denoms)) + for i, denom := range denoms { + amount := GetInitialAmount(denomDecimals[denom]) + coins[i] = sdktypes.NewCoin(denom, amount) + } + fundedAccountBalances := make([]banktypes.Balance, 0, numberOfAccounts) + for _, acc := range accounts { + balance := banktypes.Balance{ + Address: acc.String(), + Coins: coins, + } + + fundedAccountBalances = append(fundedAccountBalances, balance) + } + return fundedAccountBalances +} + +// createTestingApp creates an evmos app +func createTestingApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp)) *exampleapp.ExampleChain { + // Create evmos app + db := dbm.NewMemDB() + logger := log.NewNopLogger() + loadLatest := true + appOptions := simutils.NewAppOptionsWithFlagHome(exampleapp.DefaultNodeHome) + baseAppOptions := append(customBaseAppOptions, baseapp.SetChainID(chainID)) //nolint:gocritic + + return exampleapp.NewExampleApp( + logger, + db, + nil, + loadLatest, + appOptions, + exampleapp.EvmosAppOptions, + baseAppOptions..., + ) +} + +// createStakingValidator creates a staking validator from the given tm validator and bonded +func createStakingValidator(val *cmttypes.Validator, bondedAmt sdkmath.Int, operatorAddr *sdktypes.AccAddress) (stakingtypes.Validator, error) { + pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) //nolint:staticcheck + if err != nil { + return stakingtypes.Validator{}, err + } + + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + return stakingtypes.Validator{}, err + } + + opAddr := sdktypes.ValAddress(val.Address).String() + if operatorAddr != nil { + opAddr = sdktypes.ValAddress(operatorAddr.Bytes()).String() + } + + // Default to 5% commission + commission := stakingtypes.NewCommission(sdkmath.LegacyNewDecWithPrec(5, 2), sdkmath.LegacyNewDecWithPrec(2, 1), sdkmath.LegacyNewDecWithPrec(5, 2)) + validator := stakingtypes.Validator{ + OperatorAddress: opAddr, + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondedAmt, + DelegatorShares: sdkmath.LegacyOneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: commission, + MinSelfDelegation: sdkmath.ZeroInt(), + } + return validator, nil +} + +// createStakingValidators creates staking validators from the given tm validators and bonded +// amounts +func createStakingValidators(tmValidators []*cmttypes.Validator, bondedAmt sdkmath.Int, operatorsAddresses []sdktypes.AccAddress) ([]stakingtypes.Validator, error) { + if len(operatorsAddresses) == 0 { + return createStakingValidatorsWithRandomOperator(tmValidators, bondedAmt) + } + return createStakingValidatorsWithSpecificOperator(tmValidators, bondedAmt, operatorsAddresses) +} + +// createStakingValidatorsWithRandomOperator creates staking validators with non-specified operator addresses. +func createStakingValidatorsWithRandomOperator(tmValidators []*cmttypes.Validator, bondedAmt sdkmath.Int) ([]stakingtypes.Validator, error) { + amountOfValidators := len(tmValidators) + stakingValidators := make([]stakingtypes.Validator, 0, amountOfValidators) + for _, val := range tmValidators { + validator, err := createStakingValidator(val, bondedAmt, nil) + if err != nil { + return nil, err + } + stakingValidators = append(stakingValidators, validator) + } + return stakingValidators, nil +} + +// createStakingValidatorsWithSpecificOperator creates staking validators with the given operator addresses. +func createStakingValidatorsWithSpecificOperator(tmValidators []*cmttypes.Validator, bondedAmt sdkmath.Int, operatorsAddresses []sdktypes.AccAddress) ([]stakingtypes.Validator, error) { + amountOfValidators := len(tmValidators) + stakingValidators := make([]stakingtypes.Validator, 0, amountOfValidators) + operatorsCount := len(operatorsAddresses) + if operatorsCount != amountOfValidators { + panic(fmt.Sprintf("provided %d validator operator keys but need %d!", operatorsCount, amountOfValidators)) + } + for i, val := range tmValidators { + validator, err := createStakingValidator(val, bondedAmt, &operatorsAddresses[i]) + if err != nil { + return nil, err + } + stakingValidators = append(stakingValidators, validator) + } + return stakingValidators, nil +} + +// createDelegations creates delegations for the given validators and account +func createDelegations(validators []stakingtypes.Validator, fromAccount sdktypes.AccAddress) []stakingtypes.Delegation { + amountOfValidators := len(validators) + delegations := make([]stakingtypes.Delegation, 0, amountOfValidators) + for _, val := range validators { + delegation := stakingtypes.NewDelegation(fromAccount.String(), val.OperatorAddress, sdkmath.LegacyOneDec()) + delegations = append(delegations, delegation) + } + return delegations +} + +// getValidatorsSlashingGen creates the validators signingInfos and missedBlocks +// records necessary for the slashing module genesis +func getValidatorsSlashingGen(validators []stakingtypes.Validator, sk slashingtypes.StakingKeeper) (SlashingCustomGenesisState, error) { + valCount := len(validators) + signInfo := make([]slashingtypes.SigningInfo, valCount) + missedBlocks := make([]slashingtypes.ValidatorMissedBlocks, valCount) + for i, val := range validators { + consAddrBz, err := val.GetConsAddr() + if err != nil { + return SlashingCustomGenesisState{}, err + } + consAddr, err := sk.ConsensusAddressCodec().BytesToString(consAddrBz) + if err != nil { + return SlashingCustomGenesisState{}, err + } + signInfo[i] = slashingtypes.SigningInfo{ + Address: consAddr, + ValidatorSigningInfo: slashingtypes.ValidatorSigningInfo{ + Address: consAddr, + }, + } + missedBlocks[i] = slashingtypes.ValidatorMissedBlocks{ + Address: consAddr, + } + } + return SlashingCustomGenesisState{ + signingInfo: signInfo, + missedBlocks: missedBlocks, + }, nil +} + +// StakingCustomGenesisState defines the staking genesis state +type StakingCustomGenesisState struct { + denom string + + validators []stakingtypes.Validator + delegations []stakingtypes.Delegation +} + +// setDefaultStakingGenesisState sets the default staking genesis state +func setDefaultStakingGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams StakingCustomGenesisState) evmostypes.GenesisState { + // Set staking params + stakingParams := stakingtypes.DefaultParams() + stakingParams.BondDenom = overwriteParams.denom + + stakingGenesis := stakingtypes.NewGenesisState( + stakingParams, + overwriteParams.validators, + overwriteParams.delegations, + ) + genesisState[stakingtypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(stakingGenesis) + return genesisState +} + +type BankCustomGenesisState struct { + totalSupply sdktypes.Coins + balances []banktypes.Balance +} + +// setDefaultBankGenesisState sets the default bank genesis state +func setDefaultBankGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams BankCustomGenesisState) evmostypes.GenesisState { + bankGenesis := banktypes.NewGenesisState( + banktypes.DefaultGenesisState().Params, + overwriteParams.balances, + overwriteParams.totalSupply, + []banktypes.Metadata{}, + []banktypes.SendEnabled{}, + ) + updatedBankGen := updateBankGenesisStateForChainID(*bankGenesis) + genesisState[banktypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(&updatedBankGen) + return genesisState +} + +// SlashingCustomGenesisState defines the corresponding +// validators signing info and missed blocks for the genesis state +type SlashingCustomGenesisState struct { + signingInfo []slashingtypes.SigningInfo + missedBlocks []slashingtypes.ValidatorMissedBlocks +} + +// setDefaultSlashingGenesisState sets the default slashing genesis state +func setDefaultSlashingGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams SlashingCustomGenesisState) evmostypes.GenesisState { + slashingGen := slashingtypes.DefaultGenesisState() + slashingGen.SigningInfos = overwriteParams.signingInfo + slashingGen.MissedBlocks = overwriteParams.missedBlocks + + genesisState[slashingtypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(slashingGen) + return genesisState +} + +// setBankGenesisState updates the bank genesis state with custom genesis state +func setBankGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, customGenesis interface{}) (evmostypes.GenesisState, error) { + customGen, ok := customGenesis.(*banktypes.GenesisState) + if !ok { + return nil, fmt.Errorf("invalid type %T for bank module genesis state", customGenesis) + } + + bankGen := &banktypes.GenesisState{} + evmosApp.AppCodec().MustUnmarshalJSON(genesisState[banktypes.ModuleName], bankGen) + + if len(customGen.Balances) > 0 { + coins := sdktypes.NewCoins() + bankGen.Balances = append(bankGen.Balances, customGen.Balances...) + for _, b := range customGen.Balances { + coins = append(coins, b.Coins...) + } + bankGen.Supply = bankGen.Supply.Add(coins...) + } + if len(customGen.DenomMetadata) > 0 { + bankGen.DenomMetadata = append(bankGen.DenomMetadata, customGen.DenomMetadata...) + } + + if len(customGen.SendEnabled) > 0 { + bankGen.SendEnabled = append(bankGen.SendEnabled, customGen.SendEnabled...) + } + + bankGen.Params = customGen.Params + + genesisState[banktypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(bankGen) + return genesisState, nil +} + +// calculateTotalSupply calculates the total supply from the given balances +func calculateTotalSupply(fundedAccountsBalances []banktypes.Balance) sdktypes.Coins { + totalSupply := sdktypes.NewCoins() + for _, balance := range fundedAccountsBalances { + totalSupply = totalSupply.Add(balance.Coins...) + } + return totalSupply +} + +// addBondedModuleAccountToFundedBalances adds bonded amount to bonded pool module account and include it on funded accounts +func addBondedModuleAccountToFundedBalances( + fundedAccountsBalances []banktypes.Balance, + totalBonded sdktypes.Coin, +) []banktypes.Balance { + return append(fundedAccountsBalances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + Coins: sdktypes.Coins{totalBonded}, + }) +} + +// setDefaultAuthGenesisState sets the default auth genesis state +func setDefaultAuthGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, genAccs []authtypes.GenesisAccount) evmostypes.GenesisState { + defaultAuthGen := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genesisState[authtypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(defaultAuthGen) + return genesisState +} + +// setAuthGenesisState updates the bank genesis state with custom genesis state +func setAuthGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, customGenesis interface{}) (evmostypes.GenesisState, error) { + customGen, ok := customGenesis.(*authtypes.GenesisState) + if !ok { + return nil, fmt.Errorf("invalid type %T for auth module genesis state", customGenesis) + } + + authGen := &authtypes.GenesisState{} + evmosApp.AppCodec().MustUnmarshalJSON(genesisState[authtypes.ModuleName], authGen) + + if len(customGen.Accounts) > 0 { + authGen.Accounts = append(authGen.Accounts, customGen.Accounts...) + } + + authGen.Params = customGen.Params + + genesisState[authtypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(authGen) + return genesisState, nil +} + +// GovCustomGenesisState defines the gov genesis state +type GovCustomGenesisState struct { + denom string +} + +// setDefaultGovGenesisState sets the default gov genesis state +func setDefaultGovGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams GovCustomGenesisState) evmostypes.GenesisState { + govGen := govtypesv1.DefaultGenesisState() + updatedParams := govGen.Params + minDepositAmt := sdkmath.NewInt(1e18).Quo(evmtypes.GetEVMCoinDecimals().ConversionFactor()) + updatedParams.MinDeposit = sdktypes.NewCoins(sdktypes.NewCoin(overwriteParams.denom, minDepositAmt)) + updatedParams.ExpeditedMinDeposit = sdktypes.NewCoins(sdktypes.NewCoin(overwriteParams.denom, minDepositAmt)) + govGen.Params = updatedParams + genesisState[govtypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(govGen) + return genesisState +} + +// FeeMarketCustomGenesisState defines the fee market genesis state +type FeeMarketCustomGenesisState struct { + baseFee sdkmath.LegacyDec +} + +// setDefaultFeeMarketGenesisState sets the default fee market genesis state +func setDefaultFeeMarketGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams FeeMarketCustomGenesisState) evmostypes.GenesisState { + fmGen := feemarkettypes.DefaultGenesisState() + fmGen.Params.BaseFee = overwriteParams.baseFee + genesisState[feemarkettypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(fmGen) + return genesisState +} + +// MintCustomGenesisState defines the gov genesis state +type MintCustomGenesisState struct { + denom string + inflationMin sdkmath.LegacyDec + inflationMax sdkmath.LegacyDec +} + +// setDefaultGovGenesisState sets the default gov genesis state +// +// NOTE: for the testing network we don't want to have any minting +func setDefaultMintGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState, overwriteParams MintCustomGenesisState) evmostypes.GenesisState { + mintGen := minttypes.DefaultGenesisState() + updatedParams := mintGen.Params + updatedParams.MintDenom = overwriteParams.denom + updatedParams.InflationMin = overwriteParams.inflationMin + updatedParams.InflationMax = overwriteParams.inflationMax + + mintGen.Params = updatedParams + genesisState[minttypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(mintGen) + return genesisState +} + +func setDefaultErc20GenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState) evmostypes.GenesisState { + // NOTE: here we are using the setup from the example chain + erc20Gen := exampleapp.NewErc20GenesisState() + updatedErc20Gen := updateErc20GenesisStateForChainID(evmosApp.ChainID(), *erc20Gen) + + genesisState[erc20types.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(&updatedErc20Gen) + return genesisState +} + +func setDefaultAssetGenesisState(evmosApp *exampleapp.ExampleChain, genesisState evmostypes.GenesisState) evmostypes.GenesisState { + // NOTE: here we are using the setup from the example chain + assetGen := exampleapp.NewAssetGenesisState() + + genesisState[assettypes.ModuleName] = evmosApp.AppCodec().MustMarshalJSON(assetGen) + return genesisState +} + +// defaultAuthGenesisState sets the default genesis state +// for the testing setup +func newDefaultGenesisState(evmosApp *exampleapp.ExampleChain, params defaultGenesisParams) evmostypes.GenesisState { + genesisState := evmosApp.DefaultGenesis() + + genesisState = setDefaultAuthGenesisState(evmosApp, genesisState, params.genAccounts) + genesisState = setDefaultStakingGenesisState(evmosApp, genesisState, params.staking) + genesisState = setDefaultBankGenesisState(evmosApp, genesisState, params.bank) + genesisState = setDefaultGovGenesisState(evmosApp, genesisState, params.gov) + genesisState = setDefaultFeeMarketGenesisState(evmosApp, genesisState, params.feemarket) + genesisState = setDefaultSlashingGenesisState(evmosApp, genesisState, params.slashing) + genesisState = setDefaultMintGenesisState(evmosApp, genesisState, params.mint) + genesisState = setDefaultErc20GenesisState(evmosApp, genesisState) + genesisState = setDefaultAssetGenesisState(evmosApp, genesisState) + + return genesisState +} + +// customizeGenesis modifies genesis state if there are any custom genesis state +// for specific modules +func customizeGenesis(evmosApp *exampleapp.ExampleChain, customGen CustomGenesisState, genesisState evmostypes.GenesisState) (evmostypes.GenesisState, error) { + var err error + for mod, modGenState := range customGen { + if fn, found := genesisSetupFunctions[mod]; found { + genesisState, err = fn(evmosApp, genesisState, modGenState) + if err != nil { + return genesisState, err + } + } else { + panic(fmt.Sprintf("module %s not found in genesis setup functions", mod)) + } + } + return genesisState, err +} diff --git a/testutil/integration/os/network/unit_network.go b/testutil/integration/os/network/unit_network.go new file mode 100644 index 00000000..fe58a52d --- /dev/null +++ b/testutil/integration/os/network/unit_network.go @@ -0,0 +1,57 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package network + +import ( + sdktypes "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/ethereum/go-ethereum/common" + exampleapp "github.com/realiotech/realio-network/example_chain" + "github.com/evmos/os/x/evm/statedb" +) + +// UnitTestNetwork is the implementation of the Network interface for unit tests. +// It embeds the IntegrationNetwork struct to reuse its methods and +// makes the App public for easier testing. +type UnitTestNetwork struct { + IntegrationNetwork + App *exampleapp.ExampleChain +} + +var _ Network = (*UnitTestNetwork)(nil) + +// NewUnitTestNetwork configures and initializes a new Evmos Network instance with +// the given configuration options. If no configuration options are provided +// it uses the default configuration. +// +// It panics if an error occurs. +// Note: Only uses for Unit Tests +func NewUnitTestNetwork(opts ...ConfigOption) *UnitTestNetwork { + network := New(opts...) + return &UnitTestNetwork{ + IntegrationNetwork: *network, + App: network.app, + } +} + +// GetStateDB returns the state database for the current block. +func (n *UnitTestNetwork) GetStateDB() *statedb.StateDB { + headerHash := n.GetContext().HeaderHash() + return statedb.New( + n.GetContext(), + n.app.EVMKeeper, + statedb.NewEmptyTxConfig(common.BytesToHash(headerHash)), + ) +} + +// FundAccount funds the given account with the given amount of coins. +func (n *UnitTestNetwork) FundAccount(addr sdktypes.AccAddress, coins sdktypes.Coins) error { + ctx := n.GetContext() + + if err := n.app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, coins); err != nil { + return err + } + + return n.app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins) +} diff --git a/testutil/integration/os/utils/bank.go b/testutil/integration/os/utils/bank.go new file mode 100644 index 00000000..d9e4c516 --- /dev/null +++ b/testutil/integration/os/utils/bank.go @@ -0,0 +1,45 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "context" + "fmt" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + cmnfactory "github.com/evmos/os/testutil/integration/common/factory" + cmnnet "github.com/evmos/os/testutil/integration/common/network" + "github.com/evmos/os/testutil/integration/os/keyring" +) + +// FundAccountWithBaseDenom funds the given account with the given amount of the network's +// base denomination. +func FundAccountWithBaseDenom(tf cmnfactory.CoreTxFactory, nw cmnnet.Network, sender keyring.Key, receiver sdk.AccAddress, amount math.Int) error { + return tf.FundAccount(sender, receiver, sdk.NewCoins(sdk.NewCoin(nw.GetBaseDenom(), amount))) +} + +// CheckBalances checks that the given accounts have the expected balances and +// returns an error if that is not the case. +func CheckBalances(ctx context.Context, client banktypes.QueryClient, balances []banktypes.Balance) error { + for _, balance := range balances { + addr := balance.GetAddress() + for _, coin := range balance.GetCoins() { + balance, err := client.Balance(ctx, &banktypes.QueryBalanceRequest{Address: addr, Denom: coin.Denom}) + if err != nil { + return err + } + + if !balance.Balance.Equal(coin) { + return fmt.Errorf( + "expected balance %s, got %s for address %s", + coin, balance.Balance, addr, + ) + } + } + } + + return nil +} diff --git a/testutil/integration/os/utils/bank_test.go b/testutil/integration/os/utils/bank_test.go new file mode 100644 index 00000000..171cd58f --- /dev/null +++ b/testutil/integration/os/utils/bank_test.go @@ -0,0 +1,71 @@ +package utils_test + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + "github.com/evmos/os/testutil/integration/os/utils" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" + "github.com/stretchr/testify/require" +) + +func TestCheckBalances(t *testing.T) { + testDenom := "atest" + keyring := testkeyring.New(1) + address := keyring.GetAccAddr(0).String() + + testcases := []struct { + name string + decimals uint8 + expAmount math.Int + expPass bool + errContains string + }{ + { + name: "pass - eighteen decimals", + decimals: 18, + expAmount: network.GetInitialAmount(evmtypes.EighteenDecimals), + expPass: true, + }, + { + name: "pass - six decimals", + decimals: 6, + expAmount: network.GetInitialAmount(evmtypes.SixDecimals), + expPass: true, + }, + { + name: "fail - wrong amount", + decimals: 18, + expAmount: math.NewInt(1), + errContains: "expected balance", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + balances := []banktypes.Balance{{ + Address: address, + Coins: sdk.NewCoins( + sdk.NewCoin(testDenom, tc.expAmount), + ), + }} + + nw := network.New( + network.WithBaseCoin(testDenom, tc.decimals), + network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + ) + + err := utils.CheckBalances(nw.GetContext(), nw.GetBankClient(), balances) + if tc.expPass { + require.NoError(t, err, "unexpected error checking balances") + } else { + require.Error(t, err, "expected error checking balances") + require.ErrorContains(t, err, tc.errContains, "expected different error checking balances") + } + }) + } +} diff --git a/testutil/integration/os/utils/contracts.go b/testutil/integration/os/utils/contracts.go new file mode 100644 index 00000000..4c314a1e --- /dev/null +++ b/testutil/integration/os/utils/contracts.go @@ -0,0 +1,57 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "fmt" + "slices" + + abcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/evmos/os/testutil/integration/os/factory" + evmtypes "github.com/evmos/os/x/evm/types" +) + +// CheckTxTopics checks if all expected topics are present in the transaction response +func CheckTxTopics(res abcitypes.ExecTxResult, expectedTopics []string) error { + msgEthResponse, err := DecodeExecTxResult(res) + if err != nil { + return err + } + + // Collect all topics within the transaction + availableLogs := make([]string, 0, len(msgEthResponse.Logs)) + for _, log := range msgEthResponse.Logs { + availableLogs = append(availableLogs, log.Topics...) + } + + // Check if all expected topics are present + for _, expectedTopic := range expectedTopics { + if !slices.Contains(availableLogs, expectedTopic) { + return fmt.Errorf("expected topic %s not found in tx response", expectedTopic) + } + } + return nil +} + +// DecodeContractCallResponse decodes the response of a contract call query +func DecodeContractCallResponse(response interface{}, callArgs factory.CallArgs, res abcitypes.ExecTxResult) error { + msgEthResponse, err := DecodeExecTxResult(res) + if err != nil { + return err + } + + err = callArgs.ContractABI.UnpackIntoInterface(response, callArgs.MethodName, msgEthResponse.Ret) + if err != nil { + return err + } + return nil +} + +func DecodeExecTxResult(res abcitypes.ExecTxResult) (*evmtypes.MsgEthereumTxResponse, error) { + msgEthResponse, err := evmtypes.DecodeTxResponse(res.Data) + if err != nil { + return nil, err + } + return msgEthResponse, nil +} diff --git a/testutil/integration/os/utils/erc20.go b/testutil/integration/os/utils/erc20.go new file mode 100644 index 00000000..60f82ecb --- /dev/null +++ b/testutil/integration/os/utils/erc20.go @@ -0,0 +1,115 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/testutil/integration/os/factory" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// ERC20RegistrationData is the necessary data to provide in order to register an ERC20 token. +type ERC20RegistrationData struct { + // Addresses are the addresses of the ERC20 tokens. + Addresses []string + // ProposerPriv is the private key used to sign the proposal and voting transactions. + ProposerPriv cryptotypes.PrivKey +} + +// ValidateBasic does stateless validation of the data for the ERC20 registration. +func (ed ERC20RegistrationData) ValidateBasic() error { + emptyAddr := common.Address{} + + if len(ed.Addresses) == 0 { + return fmt.Errorf("addresses cannot be empty") + } + + for _, a := range ed.Addresses { + if ok := common.IsHexAddress(a); !ok { + return fmt.Errorf("invalid address %s", a) + } + hexAddr := common.HexToAddress(a) + if hexAddr.Hex() == emptyAddr.Hex() { + return fmt.Errorf("address cannot be empty") + } + } + + if ed.ProposerPriv == nil { + return fmt.Errorf("proposer private key cannot be nil") + } + + return nil +} + +// RegisterERC20 is a helper function to register ERC20 token through +// submitting a governance proposal and having it pass. +// It returns the registered token pair. +func RegisterERC20(tf factory.TxFactory, network network.Network, data ERC20RegistrationData) (res []erc20types.TokenPair, err error) { + err = data.ValidateBasic() + if err != nil { + return nil, errorsmod.Wrap(err, "failed to validate erc20 registration data") + } + + proposal := erc20types.MsgRegisterERC20{ + Authority: authtypes.NewModuleAddress("gov").String(), + Erc20Addresses: data.Addresses, + } + + // Submit the proposal + proposalID, err := SubmitProposal(tf, network, data.ProposerPriv, fmt.Sprintf("Register %d Token", len(data.Addresses)), &proposal) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to submit proposal") + } + + err = network.NextBlock() + if err != nil { + return nil, errorsmod.Wrap(err, "failed to commit block after proposal") + } + + // vote 'yes' and wait till proposal passes + err = ApproveProposal(tf, network, data.ProposerPriv, proposalID) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to approve proposal") + } + + // Check if token pair is registered + eq := network.GetERC20Client() + for _, a := range data.Addresses { + tokenPairRes, err := eq.TokenPair(network.GetContext(), &erc20types.QueryTokenPairRequest{Token: a}) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to query token pair") + } + res = append(res, tokenPairRes.TokenPair) + } + + return res, nil +} + +// ToggleTokenConversion is a helper function to toggle an ERC20 token pair conversion through +// submitting a governance proposal and having it pass. +func ToggleTokenConversion(tf factory.TxFactory, network network.Network, privKey cryptotypes.PrivKey, token string) error { + proposal := erc20types.MsgToggleConversion{ + Authority: authtypes.NewModuleAddress("gov").String(), + Token: token, + } + + // Submit the proposal + proposalID, err := SubmitProposal(tf, network, privKey, fmt.Sprintf("Toggle %s Token", token), &proposal) + if err != nil { + return errorsmod.Wrap(err, "failed to submit proposal") + } + + err = network.NextBlock() + if err != nil { + return errorsmod.Wrap(err, "failed to commit block after proposal") + } + + return ApproveProposal(tf, network, privKey, proposalID) +} diff --git a/testutil/integration/os/utils/events.go b/testutil/integration/os/utils/events.go new file mode 100644 index 00000000..bea28f58 --- /dev/null +++ b/testutil/integration/os/utils/events.go @@ -0,0 +1,55 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "errors" + "fmt" + + abcitypes "github.com/cometbft/cometbft/abci/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" +) + +// ContainsEventType returns true if the given events contain the given eventType. +func ContainsEventType(events []abcitypes.Event, eventType string) bool { + event := GetEventType(events, eventType) + return event != nil +} + +// GetEventType returns the given events if found +// Otherwise returns nil +func GetEventType(events []abcitypes.Event, eventType string) *abcitypes.Event { + for _, event := range events { + if event.Type == eventType { + return &event + } + } + return nil +} + +// GetEventAttributeValue returns the value for the required +// attribute key +func GetEventAttributeValue(event abcitypes.Event, attrKey string) string { + for _, attr := range event.Attributes { + if attr.Key == attrKey { + return attr.Value + } + } + return "" +} + +// GetFeesFromEvents returns the fees value for the +// specified events +func GetFeesFromEvents(events []abcitypes.Event) (sdktypes.DecCoins, error) { + event := GetEventType(events, sdktypes.EventTypeTx) + if event == nil { + return sdktypes.DecCoins{}, errors.New("tx event not found") + } + feeStr := GetEventAttributeValue(*event, sdktypes.AttributeKeyFee) + feeCoins, err := sdktypes.ParseDecCoins(feeStr) + if err != nil { + return sdktypes.DecCoins{}, fmt.Errorf("invalid fees: %v. got %s", err, feeStr) + } + return feeCoins, nil +} diff --git a/testutil/integration/os/utils/evm.go b/testutil/integration/os/utils/evm.go new file mode 100644 index 00000000..24a9af71 --- /dev/null +++ b/testutil/integration/os/utils/evm.go @@ -0,0 +1,58 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/evmos/os/contracts" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// GetERC20Balance returns the token balance of a given account address for +// an ERC-20 token at the given contract address. +func GetERC20Balance(nw network.Network, tokenAddress, accountAddress common.Address) (*big.Int, error) { + input, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack( + "balanceOf", + accountAddress, + ) + if err != nil { + return nil, err + } + + callData, err := json.Marshal(evmtypes.TransactionArgs{ + To: &tokenAddress, + Input: (*hexutil.Bytes)(&input), + }) + if err != nil { + return nil, err + } + + ethRes, err := nw.GetEvmClient().EthCall( + nw.GetContext(), + &evmtypes.EthCallRequest{ + Args: callData, + }, + ) + if err != nil { + return nil, err + } + + fmt.Println("got ret: ", ethRes.Ret) + fmt.Println("got eth call logs: ", ethRes.Logs) + fmt.Println("got eth call error: ", ethRes.VmError) + + var balance *big.Int + err = contracts.ERC20MinterBurnerDecimalsContract.ABI.UnpackIntoInterface(&balance, "balanceOf", ethRes.Ret) + if err != nil { + return nil, err + } + + return balance, nil +} diff --git a/testutil/integration/os/utils/evm_test.go b/testutil/integration/os/utils/evm_test.go new file mode 100644 index 00000000..79e65803 --- /dev/null +++ b/testutil/integration/os/utils/evm_test.go @@ -0,0 +1,64 @@ +package utils_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/contracts" + testfactory "github.com/evmos/os/testutil/integration/os/factory" + testhandler "github.com/evmos/os/testutil/integration/os/grpc" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + "github.com/evmos/os/testutil/integration/os/utils" + evmtypes "github.com/evmos/os/x/evm/types" + testnetwork "github.com/realiotech/realio-network/testutil/integration/os/network" + "github.com/stretchr/testify/require" +) + +func TestGetERC20Balance(t *testing.T) { + keyring := testkeyring.New(1) + network := testnetwork.NewUnitTestNetwork( + testnetwork.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), + ) + handler := testhandler.NewIntegrationHandler(network) + factory := testfactory.New(network, handler) + + sender := keyring.GetKey(0) + mintAmount := big.NewInt(100) + + // Deploy an ERC-20 contract + erc20Addr, err := factory.DeployContract( + sender.Priv, + evmtypes.EvmTxArgs{}, + testfactory.ContractDeploymentData{ + Contract: contracts.ERC20MinterBurnerDecimalsContract, + ConstructorArgs: []interface{}{"TestToken", "TT", uint8(18)}, + }, + ) + require.NoError(t, err, "failed to deploy contract") + require.NoError(t, network.NextBlock(), "failed to advance block") + + balance, err := utils.GetERC20Balance(network, erc20Addr, sender.Addr) + require.NoError(t, err, "failed to get ERC20 balance") + require.Equal(t, common.Big0.Int64(), balance.Int64(), "expected no balance before minting") + + // Mint some tokens + _, err = factory.ExecuteContractCall( + sender.Priv, + evmtypes.EvmTxArgs{ + To: &erc20Addr, + }, + testfactory.CallArgs{ + ContractABI: contracts.ERC20MinterBurnerDecimalsContract.ABI, + MethodName: "mint", + Args: []interface{}{sender.Addr, mintAmount}, + }, + ) + require.NoError(t, err, "failed to mint tokens") + + require.NoError(t, network.NextBlock(), "failed to advance block") + + balance, err = utils.GetERC20Balance(network, erc20Addr, sender.Addr) + require.NoError(t, err, "failed to get ERC20 balance") + require.Equal(t, mintAmount.Int64(), balance.Int64(), "expected different balance after minting") +} diff --git a/testutil/integration/os/utils/genesis.go b/testutil/integration/os/utils/genesis.go new file mode 100644 index 00000000..15727700 --- /dev/null +++ b/testutil/integration/os/utils/genesis.go @@ -0,0 +1,84 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/evmos/os/testutil/constants" + testkeyring "github.com/evmos/os/testutil/integration/os/keyring" + erc20types "github.com/evmos/os/x/erc20/types" + exampleapp "github.com/realiotech/realio-network/example_chain" + "github.com/realiotech/realio-network/testutil/integration/os/network" + utiltx "github.com/realiotech/realio-network/testutil/tx" +) + +// CreateGenesisWithTokenPairs creates a genesis that includes +// the WEVMOS and the provided denoms. +// If no denoms provided, creates only one dynamic precompile with the 'xmpl' denom. +func CreateGenesisWithTokenPairs(keyring testkeyring.Keyring, denoms ...string) network.CustomGenesisState { + // Add all keys from the keyring to the genesis accounts as well. + // + // NOTE: This is necessary to enable the account to send EVM transactions, + // because the Mono ante handler checks the account balance by querying the + // account from the account keeper first. If these accounts are not in the genesis + // state, the ante handler finds a zero balance because of the missing account. + + // if denom not provided, defaults to create only one dynamic erc20 + // precompile with the 'xmpl' denom + if len(denoms) == 0 { + denoms = []string{"xmpl"} + } + + accs := keyring.GetAllAccAddrs() + genesisAccounts := make([]*authtypes.BaseAccount, len(accs)) + for i, addr := range accs { + genesisAccounts[i] = &authtypes.BaseAccount{ + Address: addr.String(), + PubKey: nil, + AccountNumber: uint64(i + 1), //nolint:gosec // G115 + Sequence: 1, + } + } + + accGenesisState := authtypes.DefaultGenesisState() + for _, genesisAccount := range genesisAccounts { + // NOTE: This type requires to be packed into a *types.Any as seen on SDK tests, + // e.g. https://github.com/evmos/cosmos-sdk/blob/v0.47.5-evmos.2/x/auth/keeper/keeper_test.go#L193-L223 + accGenesisState.Accounts = append(accGenesisState.Accounts, codectypes.UnsafePackAny(genesisAccount)) + } + + // Add token pairs to genesis + tokenPairs := make([]erc20types.TokenPair, 0, len(denoms)+1) + tokenPairs = append(tokenPairs, + // NOTE: the example token pairs are being added in the integration test utils + exampleapp.ExampleTokenPairs..., + ) + + dynPrecAddr := make([]string, 0, len(denoms)) + for _, denom := range denoms { + addr := utiltx.GenerateAddress().Hex() + tp := erc20types.TokenPair{ + Erc20Address: addr, + Denom: denom, + Enabled: true, + ContractOwner: erc20types.OWNER_MODULE, // NOTE: Owner is the module account since it's a native token and was registered through governance + } + tokenPairs = append(tokenPairs, tp) + dynPrecAddr = append(dynPrecAddr, addr) + } + + // STR v2: update the NativePrecompiles and DynamicPrecompiles + // with the WEVMOS (default is mainnet) and 'xmpl' tokens in the erc20 params + erc20GenesisState := exampleapp.NewErc20GenesisState() + erc20GenesisState.TokenPairs = tokenPairs + erc20GenesisState.Params.NativePrecompiles = []string{constants.WEVMOSContractMainnet} + erc20GenesisState.Params.DynamicPrecompiles = dynPrecAddr + + // Combine module genesis states + return network.CustomGenesisState{ + authtypes.ModuleName: accGenesisState, + erc20types.ModuleName: erc20GenesisState, + } +} diff --git a/testutil/integration/os/utils/gov.go b/testutil/integration/os/utils/gov.go new file mode 100644 index 00000000..66d7725c --- /dev/null +++ b/testutil/integration/os/utils/gov.go @@ -0,0 +1,197 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "errors" + "fmt" + "strconv" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + abcitypes "github.com/cometbft/cometbft/abci/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + commonfactory "github.com/evmos/os/testutil/integration/common/factory" + "github.com/evmos/os/testutil/integration/os/factory" + evmtypes "github.com/evmos/os/x/evm/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// SubmitProposal is a helper function to submit a governance proposal and +// return the proposal ID. +func SubmitProposal(tf factory.TxFactory, network network.Network, proposerPriv cryptotypes.PrivKey, title string, msgs ...sdk.Msg) (uint64, error) { + proposerAccAddr := sdk.AccAddress(proposerPriv.PubKey().Address()).String() + // Tokens send to submit the proposal has to be adjusted to take into account the EVM coin decimals. + proposal, err := govv1.NewMsgSubmitProposal( + msgs, + sdk.NewCoins(sdk.NewCoin(network.GetBaseDenom(), math.NewInt(1e18).Quo(evmtypes.GetEVMCoinDecimals().ConversionFactor()))), + proposerAccAddr, + "", + title, + title, + false, + ) + if err != nil { + return 0, err + } + + txArgs := commonfactory.CosmosTxArgs{ + Msgs: []sdk.Msg{proposal}, + } + + return submitProposal(tf, network, proposerPriv, txArgs) +} + +// SubmitLegacyProposal is a helper function to submit a governance proposal and +// return the proposal ID. +func SubmitLegacyProposal(tf factory.TxFactory, network network.Network, proposerPriv cryptotypes.PrivKey, proposal govv1beta1.Content) (uint64, error) { + proposerAccAddr := sdk.AccAddress(proposerPriv.PubKey().Address()) + + msgSubmitProposal, err := govv1beta1.NewMsgSubmitProposal( + proposal, + sdk.NewCoins(sdk.NewCoin(network.GetBaseDenom(), math.NewInt(1e18))), + proposerAccAddr, + ) + if err != nil { + return 0, err + } + + txArgs := commonfactory.CosmosTxArgs{ + Msgs: []sdk.Msg{msgSubmitProposal}, + } + + return submitProposal(tf, network, proposerPriv, txArgs) +} + +// VoteOnProposal is a helper function to vote on a governance proposal given the private key of the voter and +// the option to vote. +func VoteOnProposal(tf factory.TxFactory, voterPriv cryptotypes.PrivKey, proposalID uint64, option govv1.VoteOption) (abcitypes.ExecTxResult, error) { + voterAccAddr := sdk.AccAddress(voterPriv.PubKey().Address()) + + msgVote := govv1.NewMsgVote( + voterAccAddr, + proposalID, + option, + "", + ) + + res, err := tf.CommitCosmosTx(voterPriv, commonfactory.CosmosTxArgs{ + Msgs: []sdk.Msg{msgVote}, + }) + + return res, err +} + +// ApproveProposal is a helper function to vote 'yes' +// for it and wait till it passes. +func ApproveProposal(tf factory.TxFactory, network network.Network, proposerPriv cryptotypes.PrivKey, proposalID uint64) error { + // Vote on proposal + if _, err := VoteOnProposal(tf, proposerPriv, proposalID, govv1.OptionYes); err != nil { + return errorsmod.Wrap(err, "failed to vote on proposal") + } + + if err := waitVotingPeriod(network); err != nil { + return errorsmod.Wrap(err, "failed to wait for voting period to pass") + } + + return checkProposalStatus(network, proposalID, govv1.StatusPassed) +} + +// getProposalIDFromEvents returns the proposal ID from the events in +// the ResponseDeliverTx. +func getProposalIDFromEvents(events []abcitypes.Event) (uint64, error) { + var ( + err error + found bool + proposalID uint64 + ) + + for _, event := range events { + if event.Type != govtypes.EventTypeProposalDeposit { + continue + } + + for _, attr := range event.Attributes { + if attr.Key != govtypes.AttributeKeyProposalID { + continue + } + + proposalID, err = strconv.ParseUint(attr.Value, 10, 64) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to parse proposal ID") + } + + found = true + break + } + + if found { + break + } + } + + if !found { + return 0, errors.New("proposal deposit not found") + } + + return proposalID, nil +} + +func submitProposal(tf factory.TxFactory, network network.Network, proposerPriv cryptotypes.PrivKey, txArgs commonfactory.CosmosTxArgs) (uint64, error) { + res, err := tf.CommitCosmosTx(proposerPriv, txArgs) + if err != nil { + return 0, err + } + + proposalID, err := getProposalIDFromEvents(res.Events) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to get proposal ID from events") + } + + err = network.NextBlock() + if err != nil { + return 0, errorsmod.Wrap(err, "failed to commit block after proposal") + } + + if err := checkProposalStatus(network, proposalID, govv1.StatusVotingPeriod); err != nil { + return 0, errorsmod.Wrap(err, "error while checking proposal") + } + + return proposalID, nil +} + +// waitVotingPeriod is a helper function that waits for the current voting period +// defined in the gov module params to pass +func waitVotingPeriod(n network.Network) error { + gq := n.GetGovClient() + params, err := gq.Params(n.GetContext(), &govv1.QueryParamsRequest{ParamsType: "voting"}) + if err != nil { + return errorsmod.Wrap(err, "failed to query voting params") + } + + err = n.NextBlockAfter(*params.Params.VotingPeriod) // commit after voting period is over + if err != nil { + return errorsmod.Wrap(err, "failed to commit block after voting period ends") + } + + return n.NextBlock() +} + +// checkProposalStatus is a helper function to check for a specific proposal status +func checkProposalStatus(n network.Network, proposalID uint64, expStatus govv1.ProposalStatus) error { + gq := n.GetGovClient() + proposalRes, err := gq.Proposal(n.GetContext(), &govv1.QueryProposalRequest{ProposalId: proposalID}) + if err != nil { + return errorsmod.Wrap(err, "failed to query proposal") + } + + if proposalRes.Proposal.Status != expStatus { + return fmt.Errorf("proposal status different than expected. Expected %s; got: %s", expStatus.String(), proposalRes.Proposal.Status.String()) + } + return nil +} diff --git a/testutil/integration/os/utils/params.go b/testutil/integration/os/utils/params.go new file mode 100644 index 00000000..6b2f9ec0 --- /dev/null +++ b/testutil/integration/os/utils/params.go @@ -0,0 +1,87 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/evmos/os/testutil/integration/os/factory" + erc20types "github.com/evmos/os/x/erc20/types" + evmtypes "github.com/evmos/os/x/evm/types" + feemarkettypes "github.com/evmos/os/x/feemarket/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +type UpdateParamsInput struct { + Tf factory.TxFactory + Network network.Network + Pk cryptotypes.PrivKey + Params interface{} +} + +var authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() + +// UpdateEvmParams helper function to update the EVM module parameters +// It submits an update params proposal, votes for it, and waits till it passes +func UpdateEvmParams(input UpdateParamsInput) error { + return updateModuleParams[evmtypes.Params](input, evmtypes.ModuleName) +} + +// UpdateGovParams helper function to update the governance module parameters +// It submits an update params proposal, votes for it, and waits till it passes +func UpdateGovParams(input UpdateParamsInput) error { + return updateModuleParams[govv1types.Params](input, govtypes.ModuleName) +} + +// UpdateFeeMarketParams helper function to update the feemarket module parameters +// It submits an update params proposal, votes for it, and waits till it passes +func UpdateFeeMarketParams(input UpdateParamsInput) error { + return updateModuleParams[feemarkettypes.Params](input, feemarkettypes.ModuleName) +} + +// UpdateERC20Params helper function to update the erc20 module parameters +// It submits an update params proposal, votes for it, and waits till it passes +func UpdateERC20Params(input UpdateParamsInput) error { + return updateModuleParams[erc20types.Params](input, erc20types.ModuleName) +} + +// updateModuleParams helper function to update module parameters +// It submits an update params proposal, votes for it, and waits till it passes +func updateModuleParams[T interface{}](input UpdateParamsInput, moduleName string) error { + newParams, ok := input.Params.(T) + if !ok { + return fmt.Errorf("invalid params type %T for module %s", input.Params, moduleName) + } + + proposalMsg := createProposalMsg(newParams, moduleName) + + title := fmt.Sprintf("Update %s params", moduleName) + proposalID, err := SubmitProposal(input.Tf, input.Network, input.Pk, title, proposalMsg) + if err != nil { + return err + } + + return ApproveProposal(input.Tf, input.Network, input.Pk, proposalID) +} + +// createProposalMsg creates the module-specific update params message +func createProposalMsg(params interface{}, name string) sdk.Msg { + switch name { + case evmtypes.ModuleName: + return &evmtypes.MsgUpdateParams{Authority: authority, Params: params.(evmtypes.Params)} + case govtypes.ModuleName: + return &govv1types.MsgUpdateParams{Authority: authority, Params: params.(govv1types.Params)} + case feemarkettypes.ModuleName: + return &feemarkettypes.MsgUpdateParams{Authority: authority, Params: params.(feemarkettypes.Params)} + case erc20types.ModuleName: + return &erc20types.MsgUpdateParams{Authority: authority, Params: params.(erc20types.Params)} + default: + return nil + } +} diff --git a/testutil/integration/os/utils/staking.go b/testutil/integration/os/utils/staking.go new file mode 100644 index 00000000..33ccf71f --- /dev/null +++ b/testutil/integration/os/utils/staking.go @@ -0,0 +1,111 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "errors" + "time" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/evmos/os/testutil/integration/os/grpc" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +// WaitToAccrueRewards is a helper function that waits for rewards to +// accumulate up to a specified expected amount +func WaitToAccrueRewards(n network.Network, gh grpc.Handler, delegatorAddr string, expRewards sdk.DecCoins) (sdk.DecCoins, error) { + var ( + err error + lapse = time.Hour * 24 * 7 // one week + rewards = sdk.DecCoins{} + ) + + if err = checkNonZeroInflation(n); err != nil { + return nil, err + } + + expAmt := expRewards.AmountOf(n.GetBaseDenom()) + for rewards.AmountOf(n.GetBaseDenom()).LT(expAmt) { + rewards, err = checkRewardsAfter(n, gh, delegatorAddr, lapse) + if err != nil { + return nil, errorsmod.Wrap(err, "error checking rewards") + } + } + + return rewards, err +} + +// checkRewardsAfter is a helper function that checks the accrued rewards +// after the provided timelapse +func checkRewardsAfter(n network.Network, gh grpc.Handler, delegatorAddr string, lapse time.Duration) (sdk.DecCoins, error) { + err := n.NextBlockAfter(lapse) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to commit block after voting period ends") + } + + res, err := gh.GetDelegationTotalRewards(delegatorAddr) + if err != nil { + return nil, errorsmod.Wrapf(err, "error while querying for delegation rewards") + } + + return res.Total, nil +} + +// WaitToAccrueCommission is a helper function that waits for commission to +// accumulate up to a specified expected amount +func WaitToAccrueCommission(n network.Network, gh grpc.Handler, validatorAddr string, expCommission sdk.DecCoins) (sdk.DecCoins, error) { + var ( + err error + lapse = time.Hour * 24 * 7 // one week + commission = sdk.DecCoins{} + ) + + if err := checkNonZeroInflation(n); err != nil { + return nil, err + } + + expAmt := expCommission.AmountOf(n.GetBaseDenom()) + for commission.AmountOf(n.GetBaseDenom()).LT(expAmt) { + commission, err = checkCommissionAfter(n, gh, validatorAddr, lapse) + if err != nil { + return nil, errorsmod.Wrap(err, "error checking commission") + } + } + + return commission, err +} + +// checkCommissionAfter is a helper function that checks the accrued commission +// after the provided time lapse +func checkCommissionAfter(n network.Network, gh grpc.Handler, valAddr string, lapse time.Duration) (sdk.DecCoins, error) { + err := n.NextBlockAfter(lapse) + if err != nil { + return nil, errorsmod.Wrap(err, "failed to commit block after voting period ends") + } + + res, err := gh.GetValidatorCommission(valAddr) + if err != nil { + return nil, errorsmod.Wrapf(err, "error while querying for delegation rewards") + } + + return res.Commission.Commission, nil +} + +// checkNonZeroInflation is a helper function that checks if the network's +// inflation is non-zero. +// This is required to ensure that rewards and commission are accrued. +func checkNonZeroInflation(n network.Network) error { + res, err := n.GetMintClient().Inflation(n.GetContext(), &minttypes.QueryInflationRequest{}) + if err != nil { + return errorsmod.Wrap(err, "failed to get inflation") + } + + if res.Inflation.IsZero() { + return errors.New("inflation is zero; must be non-zero for rewards or commission to be distributed") + } + + return nil +} diff --git a/testutil/integration/os/utils/types.go b/testutil/integration/os/utils/types.go new file mode 100644 index 00000000..96f17deb --- /dev/null +++ b/testutil/integration/os/utils/types.go @@ -0,0 +1,15 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package utils + +import ( + "github.com/ethereum/go-ethereum/common" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func ValidatorConsAddressToHex(valAddress string) common.Address { + coinbaseAddressBytes := sdk.ConsAddress(valAddress).Bytes() + return common.BytesToAddress(coinbaseAddressBytes) +} diff --git a/testutil/integration/os/utils/unit.go b/testutil/integration/os/utils/unit.go new file mode 100644 index 00000000..e00c82f0 --- /dev/null +++ b/testutil/integration/os/utils/unit.go @@ -0,0 +1,144 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +// +// This file contains all utility function that require the access to the unit +// test network and should only be used in unit tests. + +package utils + +import ( + "fmt" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + erc20types "github.com/evmos/os/x/erc20/types" + "github.com/realiotech/realio-network/testutil/integration/os/network" +) + +const ( + TokenToMint = 1e18 +) + +// RegisterEvmosERC20Coins uses the UnitNetwork to register the evmos token as an +// ERC20 token. The function performs all the required steps for the registration +// like registering the denom trace in the transfer keeper and minting the token +// with the bank. Returns the TokenPair or an error. +func RegisterEvmosERC20Coins( + network network.UnitTestNetwork, + tokenReceiver sdk.AccAddress, +) (erc20types.TokenPair, error) { + bondDenom, err := network.App.StakingKeeper.BondDenom(network.GetContext()) + if err != nil { + return erc20types.TokenPair{}, err + } + + coin := sdk.NewCoin(bondDenom, math.NewInt(TokenToMint)) + err = network.App.BankKeeper.MintCoins( + network.GetContext(), + minttypes.ModuleName, + sdk.NewCoins(coin), + ) + if err != nil { + return erc20types.TokenPair{}, err + } + err = network.App.BankKeeper.SendCoinsFromModuleToAccount( + network.GetContext(), + minttypes.ModuleName, + tokenReceiver, + sdk.NewCoins(coin), + ) + if err != nil { + return erc20types.TokenPair{}, err + } + + evmosMetadata, found := network.App.BankKeeper.GetDenomMetaData(network.GetContext(), bondDenom) + if !found { + return erc20types.TokenPair{}, fmt.Errorf("expected evmos denom metadata") + } + + _, err = network.App.Erc20Keeper.RegisterERC20Extension(network.GetContext(), evmosMetadata.Base) + if err != nil { + return erc20types.TokenPair{}, err + } + + evmosDenomID := network.App.Erc20Keeper.GetDenomMap(network.GetContext(), bondDenom) + tokenPair, ok := network.App.Erc20Keeper.GetTokenPair(network.GetContext(), evmosDenomID) + if !ok { + return erc20types.TokenPair{}, fmt.Errorf("expected evmos erc20 token pair") + } + + return tokenPair, nil +} + +// RegisterIBCERC20Coins uses the UnitNetwork to register the denomTrace as an +// ERC20 token. The function performs all the required steps for the registration +// like registering the denom trace in the transfer keeper and minting the token +// with the bank. Returns the TokenPair or an error. +// +// TODO: why is this not yet used +func RegisterIBCERC20Coins( + network *network.UnitTestNetwork, + tokenReceiver sdk.AccAddress, + denomTrace transfertypes.DenomTrace, +) (erc20types.TokenPair, error) { + ibcDenom := denomTrace.IBCDenom() + network.App.TransferKeeper.SetDenomTrace(network.GetContext(), denomTrace) + ibcMetadata := banktypes.Metadata{ + Name: "Generic IBC name", + Symbol: "IBC", + Description: "Generic IBC token description", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: ibcDenom, + Exponent: 0, + Aliases: []string{ibcDenom}, + }, + { + Denom: ibcDenom, + Exponent: 18, + }, + }, + Display: ibcDenom, + Base: ibcDenom, + } + + coin := sdk.NewCoin(ibcMetadata.Base, math.NewInt(TokenToMint)) + err := network.App.BankKeeper.MintCoins( + network.GetContext(), + minttypes.ModuleName, + sdk.NewCoins(coin), + ) + if err != nil { + return erc20types.TokenPair{}, err + } + + err = network.App.BankKeeper.SendCoinsFromModuleToAccount( + network.GetContext(), + minttypes.ModuleName, + tokenReceiver, + sdk.NewCoins(coin), + ) + if err != nil { + return erc20types.TokenPair{}, err + } + + _, err = network.App.Erc20Keeper.RegisterERC20Extension(network.GetContext(), ibcMetadata.Base) + if err != nil { + return erc20types.TokenPair{}, err + } + + ibcDenomID := network.App.Erc20Keeper.GetDenomMap( + network.GetContext(), + denomTrace.IBCDenom(), + ) + tokenPair, ok := network.App.Erc20Keeper.GetTokenPair(network.GetContext(), ibcDenomID) + if !ok { + return erc20types.TokenPair{}, fmt.Errorf("expected %s erc20 token pair", ibcDenom) + } + + return tokenPair, nil +} diff --git a/testutil/tx/cosmos.go b/testutil/tx/cosmos.go new file mode 100644 index 00000000..06756551 --- /dev/null +++ b/testutil/tx/cosmos.go @@ -0,0 +1,146 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package tx + +import ( + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/evmos/os/testutil/constants" + exampleapp "github.com/realiotech/realio-network/example_chain" + protov2 "google.golang.org/protobuf/proto" +) + +var DefaultFee = sdk.NewCoin(constants.ExampleAttoDenom, sdkmath.NewInt(1e16)) // 0.01 AEVMOS + +// CosmosTxArgs contains the params to create a cosmos tx +type CosmosTxArgs struct { + // TxCfg is the client transaction config + TxCfg client.TxConfig + // Priv is the private key that will be used to sign the tx + Priv cryptotypes.PrivKey + // ChainID is the chain's id on cosmos format, e.g. 'evmos_9000-1' + ChainID string + // Gas to be used on the tx + Gas uint64 + // GasPrice to use on tx + GasPrice *sdkmath.Int + // Fees is the fee to be used on the tx (amount and denom) + Fees sdk.Coins + // FeeGranter is the account address of the fee granter + FeeGranter sdk.AccAddress + // Msgs slice of messages to include on the tx + Msgs []sdk.Msg +} + +// PrepareCosmosTx creates a cosmos tx and signs it with the provided messages and private key. +// It returns the signed transaction and an error +func PrepareCosmosTx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + args CosmosTxArgs, +) (authsigning.Tx, error) { + txBuilder := args.TxCfg.NewTxBuilder() + + txBuilder.SetGasLimit(args.Gas) + + var fees sdk.Coins + if args.GasPrice != nil { + fees = sdk.Coins{{Denom: constants.ExampleAttoDenom, Amount: args.GasPrice.MulRaw(int64(args.Gas))}} //#nosec G115 + } else { + fees = sdk.Coins{DefaultFee} + } + + txBuilder.SetFeeAmount(fees) + if err := txBuilder.SetMsgs(args.Msgs...); err != nil { + return nil, err + } + + txBuilder.SetFeeGranter(args.FeeGranter) + + return signCosmosTx( + ctx, + exampleApp, + args, + txBuilder, + ) +} + +// signCosmosTx signs the cosmos transaction on the txBuilder provided using +// the provided private key +func signCosmosTx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + args CosmosTxArgs, + txBuilder client.TxBuilder, +) (authsigning.Tx, error) { + addr := sdk.AccAddress(args.Priv.PubKey().Address().Bytes()) + seq, err := exampleApp.AccountKeeper.GetSequence(ctx, addr) + if err != nil { + return nil, err + } + + signMode, err := authsigning.APISignModeToInternal(args.TxCfg.SignModeHandler().DefaultMode()) + if err != nil { + return nil, err + } + + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + sigV2 := signing.SignatureV2{ + PubKey: args.Priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + Signature: nil, + }, + Sequence: seq, + } + + sigsV2 := []signing.SignatureV2{sigV2} + + if err := txBuilder.SetSignatures(sigsV2...); err != nil { + return nil, err + } + + // Second round: all signer infos are set, so each signer can sign. + accNumber := exampleApp.AccountKeeper.GetAccount(ctx, addr).GetAccountNumber() + signerData := authsigning.SignerData{ + ChainID: args.ChainID, + AccountNumber: accNumber, + Sequence: seq, + } + sigV2, err = tx.SignWithPrivKey( + ctx, + signMode, + signerData, + txBuilder, args.Priv, args.TxCfg, + seq, + ) + if err != nil { + return nil, err + } + + sigsV2 = []signing.SignatureV2{sigV2} + if err = txBuilder.SetSignatures(sigsV2...); err != nil { + return nil, err + } + return txBuilder.GetTx(), nil +} + +var _ sdk.Tx = &InvalidTx{} + +// InvalidTx defines a type, which satisfies the sdk.Tx interface, but +// holds no valid transaction information. +// +// NOTE: This is used for testing purposes, to serve the edge case of invalid data being passed to functions. +type InvalidTx struct{} + +func (InvalidTx) GetMsgs() []sdk.Msg { return nil } +func (InvalidTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil } + +func (InvalidTx) ValidateBasic() error { return nil } diff --git a/testutil/tx/eip712.go b/testutil/tx/eip712.go new file mode 100644 index 00000000..c66aadf7 --- /dev/null +++ b/testutil/tx/eip712.go @@ -0,0 +1,206 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package tx + +import ( + "errors" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + cryptocodec "github.com/evmos/os/crypto/codec" + "github.com/evmos/os/ethereum/eip712" + "github.com/evmos/os/types" + exampleapp "github.com/realiotech/realio-network/example_chain" +) + +type EIP712TxArgs struct { + CosmosTxArgs CosmosTxArgs + UseLegacyTypedData bool +} + +type typedDataArgs struct { + chainID uint64 + data []byte + legacyFeePayer sdk.AccAddress + legacyMsg sdk.Msg +} + +type signatureV2Args struct { + pubKey cryptotypes.PubKey + signature []byte + nonce uint64 +} + +// CreateEIP712CosmosTx creates a cosmos tx for typed data according to EIP712. +// Also, signs the tx with the provided messages and private key. +// It returns the signed transaction and an error +func CreateEIP712CosmosTx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + args EIP712TxArgs, +) (sdk.Tx, error) { + builder, err := PrepareEIP712CosmosTx( + ctx, + exampleApp, + args, + ) + return builder.GetTx(), err +} + +// PrepareEIP712CosmosTx creates a cosmos tx for typed data according to EIP712. +// Also, signs the tx with the provided messages and private key. +// It returns the tx builder with the signed transaction and an error +func PrepareEIP712CosmosTx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + args EIP712TxArgs, +) (client.TxBuilder, error) { + txArgs := args.CosmosTxArgs + + pc, err := types.ParseChainID(txArgs.ChainID) + if err != nil { + return nil, err + } + chainIDNum := pc.Uint64() + + from := sdk.AccAddress(txArgs.Priv.PubKey().Address().Bytes()) + accNumber := exampleApp.AccountKeeper.GetAccount(ctx, from).GetAccountNumber() + + nonce, err := exampleApp.AccountKeeper.GetSequence(ctx, from) + if err != nil { + return nil, err + } + + // using nolint:all because the staticcheck nolint is not working as expected + fee := legacytx.NewStdFee(txArgs.Gas, txArgs.Fees) //nolint:all + + msgs := txArgs.Msgs + data := legacytx.StdSignBytes(ctx.ChainID(), accNumber, nonce, 0, fee, msgs, "") + + typedDataArgs := typedDataArgs{ + chainID: chainIDNum, + data: data, + legacyFeePayer: from, + legacyMsg: msgs[0], + } + typedData, err := createTypedData(typedDataArgs, args.UseLegacyTypedData) + if err != nil { + return nil, err + } + + txBuilder := txArgs.TxCfg.NewTxBuilder() + builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder) + if !ok { + return nil, errors.New("txBuilder could not be casted to authtx.ExtensionOptionsTxBuilder type") + } + + builder.SetFeeAmount(fee.Amount) + builder.SetGasLimit(txArgs.Gas) + + err = builder.SetMsgs(txArgs.Msgs...) + if err != nil { + return nil, err + } + + return signCosmosEIP712Tx( + ctx, + exampleApp, + args, + builder, + typedData, + ) +} + +// signCosmosEIP712Tx signs the cosmos transaction on the txBuilder provided using +// the provided private key and the typed data +func signCosmosEIP712Tx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + args EIP712TxArgs, + builder authtx.ExtensionOptionsTxBuilder, + data apitypes.TypedData, +) (client.TxBuilder, error) { + priv := args.CosmosTxArgs.Priv + + from := sdk.AccAddress(priv.PubKey().Address().Bytes()) + nonce, err := exampleApp.AccountKeeper.GetSequence(ctx, from) + if err != nil { + return nil, err + } + + sigHash, _, err := apitypes.TypedDataAndHash(data) + if err != nil { + return nil, err + } + + keyringSigner := NewSigner(priv) + signature, pubKey, err := keyringSigner.SignByAddress(from, sigHash, signingtypes.SignMode_SIGN_MODE_DIRECT) + if err != nil { + return nil, err + } + signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper + + sigsV2 := getTxSignatureV2( + signatureV2Args{ + pubKey: pubKey, + signature: signature, + nonce: nonce, + }, + ) + + err = builder.SetSignatures(sigsV2) + if err != nil { + return nil, err + } + + return builder, nil +} + +// createTypedData creates the TypedData object corresponding to +// the arguments, using the legacy implementation as specified. +func createTypedData(args typedDataArgs, useLegacy bool) (apitypes.TypedData, error) { + if useLegacy { + registry := codectypes.NewInterfaceRegistry() + types.RegisterInterfaces(registry) + cryptocodec.RegisterInterfaces(registry) + evmosCodec := codec.NewProtoCodec(registry) + + feeDelegation := &eip712.FeeDelegationOptions{ + FeePayer: args.legacyFeePayer, + } + + return eip712.LegacyWrapTxToTypedData( + evmosCodec, + args.chainID, + args.legacyMsg, + args.data, + feeDelegation, + ) + } + + return eip712.WrapTxToTypedData(args.chainID, args.data) +} + +// getTxSignatureV2 returns the SignatureV2 object corresponding to +// the arguments, using the legacy implementation as needed. +func getTxSignatureV2(args signatureV2Args) signingtypes.SignatureV2 { + // Must use SIGN_MODE_DIRECT, since Amino has some trouble parsing certain Any values from a SignDoc + // with the Legacy EIP-712 TypedData encodings. This is not an issue with the latest encoding. + return signingtypes.SignatureV2{ + PubKey: args.pubKey, + Data: &signingtypes.SingleSignatureData{ + SignMode: signingtypes.SignMode_SIGN_MODE_DIRECT, + Signature: args.signature, + }, + Sequence: args.nonce, + } +} diff --git a/testutil/tx/eth.go b/testutil/tx/eth.go new file mode 100644 index 00000000..fb205836 --- /dev/null +++ b/testutil/tx/eth.go @@ -0,0 +1,165 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package tx + +import ( + "context" + "encoding/json" + "math/big" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/evmos/os/server/config" + evmtypes "github.com/evmos/os/x/evm/types" + exampleapp "github.com/realiotech/realio-network/example_chain" +) + +// PrepareEthTx creates an ethereum tx and signs it with the provided messages and private key. +// It returns the signed transaction and an error +func PrepareEthTx( + txCfg client.TxConfig, + priv cryptotypes.PrivKey, + msgs ...sdk.Msg, +) (authsigning.Tx, error) { + txBuilder := txCfg.NewTxBuilder() + + signer := ethtypes.LatestSignerForChainID(evmtypes.GetEthChainConfig().ChainID) + txFee := sdk.Coins{} + txGasLimit := uint64(0) + + baseDenom := evmtypes.GetEVMCoinDenom() + + // Sign messages and compute gas/fees. + for _, m := range msgs { + msg, ok := m.(*evmtypes.MsgEthereumTx) + if !ok { + return nil, errorsmod.Wrapf(errorsmod.Error{}, "cannot mix Ethereum and Cosmos messages in one Tx") + } + + if priv != nil { + err := msg.Sign(signer, NewSigner(priv)) + if err != nil { + return nil, err + } + } + + msg.From = "" + + txGasLimit += msg.GetGas() + txFee = txFee.Add(sdk.Coin{Denom: baseDenom, Amount: sdkmath.NewIntFromBigInt(msg.GetFee())}) + } + + if err := txBuilder.SetMsgs(msgs...); err != nil { + return nil, err + } + + // Set the extension + var option *codectypes.Any + option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{}) + if err != nil { + return nil, err + } + + builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder) + if !ok { + return nil, errorsmod.Wrapf(errorsmod.Error{}, "could not set extensions for Ethereum tx") + } + + builder.SetExtensionOptions(option) + + txBuilder.SetGasLimit(txGasLimit) + txBuilder.SetFeeAmount(txFee) + + return txBuilder.GetTx(), nil +} + +// CreateEthTx is a helper function to create and sign an Ethereum transaction. +// +// If the given private key is not nil, it will be used to sign the transaction. +// +// It offers the ability to increment the nonce by a given amount in case one wants to set up +// multiple transactions that are supposed to be executed one after another. +// Should this not be the case, just pass in zero. +func CreateEthTx( + ctx sdk.Context, + exampleApp *exampleapp.ExampleChain, + privKey cryptotypes.PrivKey, + from sdk.AccAddress, + dest sdk.AccAddress, + amount *big.Int, + nonceIncrement int, +) (*evmtypes.MsgEthereumTx, error) { + toAddr := common.BytesToAddress(dest.Bytes()) + fromAddr := common.BytesToAddress(from.Bytes()) + chainID := evmtypes.GetEthChainConfig().ChainID + + baseFeeRes, err := exampleApp.EVMKeeper.BaseFee(ctx, &evmtypes.QueryBaseFeeRequest{}) + if err != nil { + return nil, err + } + baseFee := baseFeeRes.BaseFee.BigInt() + + // When we send multiple Ethereum Tx's in one Cosmos Tx, we need to increment the nonce for each one. + nonce := exampleApp.EVMKeeper.GetNonce(ctx, fromAddr) + uint64(nonceIncrement) //#nosec G115 -- will not exceed uint64 + evmTxParams := &evmtypes.EvmTxArgs{ + ChainID: chainID, + Nonce: nonce, + To: &toAddr, + Amount: amount, + GasLimit: 100000, + GasFeeCap: baseFee, + GasTipCap: big.NewInt(1), + Accesses: ðtypes.AccessList{}, + } + msgEthereumTx := evmtypes.NewTx(evmTxParams) + msgEthereumTx.From = fromAddr.String() + + // If we are creating multiple eth Tx's with different senders, we need to sign here rather than later. + if privKey != nil { + signer := ethtypes.LatestSignerForChainID(evmtypes.GetEthChainConfig().ChainID) + err := msgEthereumTx.Sign(signer, NewSigner(privKey)) + if err != nil { + return nil, err + } + } + + return msgEthereumTx, nil +} + +// GasLimit estimates the gas limit for the provided parameters. To achieve +// this, need to provide the corresponding QueryClient to call the +// `eth_estimateGas` rpc method. If not provided, returns a default value +func GasLimit(ctx context.Context, from common.Address, data evmtypes.HexString, queryClientEvm evmtypes.QueryClient) (uint64, error) { + // default gas limit (used if no queryClientEvm is provided) + gas := uint64(100000000000) + + if queryClientEvm != nil { + args, err := json.Marshal(&evmtypes.TransactionArgs{ + From: &from, + Data: (*hexutil.Bytes)(&data), + }) + if err != nil { + return gas, err + } + + res, err := queryClientEvm.EstimateGas(ctx, &evmtypes.EthCallRequest{ + Args: args, + GasCap: config.DefaultGasCap, + }) + if err != nil { + return gas, err + } + gas = res.Gas + } + return gas, nil +} diff --git a/testutil/tx/signer.go b/testutil/tx/signer.go new file mode 100644 index 00000000..b6217f4c --- /dev/null +++ b/testutil/tx/signer.go @@ -0,0 +1,83 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package tx + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/os/crypto/ethsecp256k1" +) + +// NewAddrKey generates an Ethereum address and its corresponding private key. +func NewAddrKey() (common.Address, *ethsecp256k1.PrivKey) { + privkey, _ := ethsecp256k1.GenerateKey() + key, err := privkey.ToECDSA() + if err != nil { + return common.Address{}, nil + } + + addr := crypto.PubkeyToAddress(key.PublicKey) + + return addr, privkey +} + +// NewAccAddressAndKey generates a private key and its corresponding +// Cosmos SDK address. +func NewAccAddressAndKey() (sdk.AccAddress, *ethsecp256k1.PrivKey) { + addr, privKey := NewAddrKey() + return sdk.AccAddress(addr.Bytes()), privKey +} + +// GenerateAddress generates an Ethereum address. +func GenerateAddress() common.Address { + addr, _ := NewAddrKey() + return addr +} + +var _ keyring.Signer = &Signer{} + +// Signer defines a type that is used on testing for signing MsgEthereumTx +type Signer struct { + privKey cryptotypes.PrivKey +} + +func NewSigner(sk cryptotypes.PrivKey) keyring.Signer { + return &Signer{ + privKey: sk, + } +} + +// Sign signs the message using the underlying private key +func (s Signer) Sign(_ string, msg []byte, _ signing.SignMode) ([]byte, cryptotypes.PubKey, error) { + if s.privKey.Type() != ethsecp256k1.KeyType { + return nil, nil, fmt.Errorf( + "invalid private key type for signing ethereum tx; expected %s, got %s", + ethsecp256k1.KeyType, + s.privKey.Type(), + ) + } + + sig, err := s.privKey.Sign(msg) + if err != nil { + return nil, nil, err + } + + return sig, s.privKey.PubKey(), nil +} + +// SignByAddress sign byte messages with a user key providing the address. +func (s Signer) SignByAddress(address sdk.Address, msg []byte, signMode signing.SignMode) ([]byte, cryptotypes.PubKey, error) { + signer := sdk.AccAddress(s.privKey.PubKey().Address()) + if !signer.Equals(address) { + return nil, nil, fmt.Errorf("address mismatch: signer %s ≠ given address %s", signer, address) + } + + return s.Sign("", msg, signMode) +} diff --git a/x/asset/genesis.go b/x/asset/genesis.go index c88c4e3b..729c97b0 100644 --- a/x/asset/genesis.go +++ b/x/asset/genesis.go @@ -2,6 +2,7 @@ package asset import ( "context" + "fmt" "github.com/realiotech/realio-network/x/asset/keeper" "github.com/realiotech/realio-network/x/asset/types" @@ -10,6 +11,7 @@ import ( // InitGenesis initializes the assets module's state from a provided genesis // state. func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisState) { + fmt.Println("Go here") err := k.Params.Set(ctx, genState.Params) if err != nil { panic(err) @@ -20,6 +22,8 @@ func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisSta panic(err) } } + ma := k.Ak.GetModuleAccount(ctx, types.ModuleName) + fmt.Println("asset module account", ma) } // ExportGenesis returns the capability module's exported genesis. diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index 472798e0..b7d6931c 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -20,7 +20,7 @@ type Keeper struct { cdc codec.Codec storeService store.KVStoreService bk types.BankKeeper - ak types.AccountKeeper + Ak types.AccountKeeper // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. @@ -49,7 +49,7 @@ func NewKeeper( storeService: storeService, authority: authority, bk: bk, - ak: ak, + Ak: ak, Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), Token: collections.NewMap(sb, types.TokenKey, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), TokenManagement: collections.NewMap(sb, types.TokenManagementKey, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), diff --git a/x/asset/module.go b/x/asset/module.go index 8f72efab..5b098f15 100644 --- a/x/asset/module.go +++ b/x/asset/module.go @@ -3,6 +3,7 @@ package asset import ( "context" "encoding/json" + "fmt" // this line is used by starport scaffolding # 1 @@ -24,7 +25,7 @@ import ( var ( _ module.AppModuleBasic = AppModule{} _ module.AppModuleSimulation = AppModule{} - // _ module.HasGenesis = AppModule{} + _ module.HasGenesis = AppModule{} // _ module.HasServices = AppModule{} _ appmodule.AppModule = AppModule{} @@ -67,18 +68,18 @@ func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { } // DefaultGenesis returns the capability module's default genesis state. -// func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { -// return cdc.MustMarshalJSON(types.DefaultGenesis()) -// } +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} // ValidateGenesis performs genesis state validation for the capability module. -// func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { -// var genState types.GenesisState -// if err := cdc.UnmarshalJSON(bz, &genState); err != nil { -// return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) -// } -// return genState.Validate() -// } +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { diff --git a/x/asset/types/expected_keepers.go b/x/asset/types/expected_keepers.go index cee33cfb..09fbc687 100644 --- a/x/asset/types/expected_keepers.go +++ b/x/asset/types/expected_keepers.go @@ -14,6 +14,7 @@ type AccountKeeper interface { GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI GetModuleAddress(moduleName string) sdk.AccAddress // Methods imported from account should be defined here + GetModuleAccount(ctx context.Context, moduleName string) sdk.ModuleAccountI } // BankKeeper defines the expected interface needed to retrieve account balances. diff --git a/x/asset/types/params.go b/x/asset/types/params.go index 18f98de6..4831c3a0 100644 --- a/x/asset/types/params.go +++ b/x/asset/types/params.go @@ -8,7 +8,9 @@ import ( // NewParams creates a new Params instance func NewParams() Params { - return Params{} + return Params{ + AllowExtensions: []string{"transfer", "mint"}, + } } // DefaultParams returns a default set of parameters From cd742104b5cb1285f9ccf372c1052870bcd9ccec Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Thu, 6 Feb 2025 22:01:11 +0700 Subject: [PATCH 46/53] fix burn, burnFrom & test --- app/ante/handler_options_test.go | 2 +- app/ante/utils_test.go | 2 +- precompiles/erc20/abi.json | 13 ++ precompiles/erc20/events.go | 2 +- precompiles/erc20/tx.go | 4 +- precompiles/erc20/tx_test.go | 236 +++++++++++++++++++++++++++++++ precompiles/erc20/types.go | 2 +- 7 files changed, 255 insertions(+), 6 deletions(-) diff --git a/app/ante/handler_options_test.go b/app/ante/handler_options_test.go index 2b10f8c6..f0e0df0b 100644 --- a/app/ante/handler_options_test.go +++ b/app/ante/handler_options_test.go @@ -138,7 +138,7 @@ func (suite *AnteTestSuite) TestValidateHandlerOptions() { SignModeHandler: encoding.MakeConfig().TxConfig.SignModeHandler(), SigGasConsumer: evmosante.SigVerificationGasConsumer, MaxTxGasWanted: 40000000, - TxFeeChecker: evmosanteevm.NewDynamicFeeChecker(suite.app.EvmKeeper), + TxFeeChecker: evmosanteevm.NewDynamicFeeChecker(suite.app.FeeMarketKeeper), }, true, }, diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index 39ed6ea9..25484454 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -185,7 +185,7 @@ func (suite *AnteTestSuite) BuildTestEthTx( gasTipCap *big.Int, accesses *ethtypes.AccessList, ) *evmtypes.MsgEthereumTx { - chainID := suite.app.EvmKeeper.ChainID() + chainID := evmtypes.GetEthChainConfig().ChainID nonce := suite.app.EvmKeeper.GetNonce( suite.ctx, common.BytesToAddress(from.Bytes()), diff --git a/precompiles/erc20/abi.json b/precompiles/erc20/abi.json index 32ca187c..6a6bf143 100644 --- a/precompiles/erc20/abi.json +++ b/precompiles/erc20/abi.json @@ -181,6 +181,19 @@ "name": "Mint", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event" + }, { "anonymous": false, "inputs": [ diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index d55491bd..25a7b50e 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -109,7 +109,7 @@ func (p Precompile) EmitBurnEvent(ctx sdk.Context, stateDB vm.StateDB, from comm return err } - arguments := abi.Arguments{event.Inputs[1]} + arguments := abi.Arguments{event.Inputs[0]} packed, err := arguments.Pack(value) if err != nil { return err diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index 2bb7f882..21328974 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -179,7 +179,7 @@ func (p *Precompile) mint( havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) fmt.Println("have perm", havePerm, err) if err != nil || !havePerm { - return nil, fmt.Errorf("Sender is not token manager") + return nil, fmt.Errorf("sender is not token manager") } mintToAddr := sdk.AccAddress(to.Bytes()) @@ -266,7 +266,7 @@ func (p *Precompile) burn( minter := contract.CallerAddress havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) if err != nil || !havePerm { - return nil, err + return nil, fmt.Errorf("sender is not token manager") } burnFromAddr := sdk.AccAddress(from.Bytes()) diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go index a2f21cb9..aef84297 100644 --- a/precompiles/erc20/tx_test.go +++ b/precompiles/erc20/tx_test.go @@ -23,6 +23,8 @@ var ( XMPLCoin = sdk.NewCoins(sdk.NewInt64Coin(tokenDenom, 1e18)) // toAddr is a dummy address used for testing purposes. toAddr = utiltx.GenerateAddress() + // toAddr is a dummy address used for testing purposes. + fromAddr = utiltx.GenerateAddress() ) func (s *PrecompileTestSuite) TestTransfer() { @@ -375,3 +377,237 @@ func (s *PrecompileTestSuite) TestMint() { }) } } + +func (s *PrecompileTestSuite) TestBurn() { + method := s.precompile.Methods[MintMethod] + // fromAddr is the address of the keyring account used for testing. + sender := s.keyring.GetKey(0) + invalidSender := s.keyring.GetKey(1) + maxSupply := math.NewInt(200) + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + sender keyring.Key + }{ + { + "fail - negative amount", + func() []interface{} { + return []interface{}{big.NewInt(-1)} + }, + func() {}, + true, + "coin -1xmpl amount is not positive", + sender, + }, + { + "fail - invalid amount", + func() []interface{} { + return []interface{}{""} + }, + func() {}, + true, + "invalid amount", + sender, + }, + { + "fail - sender is not manager", + func() []interface{} { + return []interface{}{big.NewInt(100)} + }, + func() {}, + true, + "sender is not token manager", + invalidSender, + }, + { + "fail - not enough balance", + func() []interface{} { + return []interface{}{big.NewInt(300)} + }, + func() {}, + true, + "not enough balance", + sender, + }, + { + "pass", + func() []interface{} { + return []interface{}{big.NewInt(100)} + }, + func() { + addrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), sender.AccAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), addrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + sender, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), tc.sender.Addr, s.precompile, 0) + + // Set up manager role for valid sender + err := s.precompile.assetKeep.TokenManagement.Set( + ctx, + s.tokenDenom, + assettypes.TokenManagement{ + Managers: []string{sender.AccAddr.String()}, + ExtensionsList: []string{"mint"}, + MaxSupply: maxSupply, + }, + ) + s.Require().NoError(err) + + // Mint amount to fromAddr to burn lately + // _, err = s.precompile.Mint(ctx, contract, stateDB, &method, []interface{}{sender.Addr, big.NewInt(maxSupply.Int64())}) + // fmt.Println("errrrr", err) + // s.Require().NoError(err) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.BankKeeper.MintCoins(ctx, erc20types.ModuleName, sdk.NewCoins(sdk.NewCoin(tokenDenom, maxSupply))) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(ctx, erc20types.ModuleName, sender.AccAddr, sdk.NewCoins(sdk.NewCoin(tokenDenom, maxSupply))) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = s.precompile.Burn(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected burn transaction to fail") + // s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected burn transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestBurnFrom() { + method := s.precompile.Methods[MintMethod] + // fromAddr is the address of the keyring account used for testing. + sender := s.keyring.GetKey(0) + invalidSender := s.keyring.GetKey(1) + maxSupply := math.NewInt(200) + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + sender keyring.Key + }{ + { + "fail - negative amount", + func() []interface{} { + return []interface{}{fromAddr, big.NewInt(-1)} + }, + func() {}, + true, + "coin -1xmpl amount is not positive", + sender, + }, + { + "fail - invalid from address", + func() []interface{} { + return []interface{}{"", big.NewInt(100)} + }, + func() {}, + true, + "invalid from address", + sender, + }, + { + "fail - invalid amount", + func() []interface{} { + return []interface{}{fromAddr, ""} + }, + func() {}, + true, + "invalid amount", + sender, + }, + { + "fail - sender is not manager", + func() []interface{} { + return []interface{}{fromAddr, big.NewInt(100)} + }, + func() {}, + true, + "sender is not token manager", + invalidSender, + }, + { + "fail - not enough balance", + func() []interface{} { + return []interface{}{fromAddr, big.NewInt(300)} + }, + func() {}, + true, + "not enough balance", + sender, + }, + { + "pass", + func() []interface{} { + return []interface{}{fromAddr, big.NewInt(100)} + }, + func() { + addrBalance := s.network.App.BankKeeper.GetBalance(s.network.GetContext(), fromAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), addrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + sender, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), tc.sender.Addr, s.precompile, 0) + + // Set up manager role for valid sender + err := s.precompile.assetKeep.TokenManagement.Set( + ctx, + s.tokenDenom, + assettypes.TokenManagement{ + Managers: []string{sender.AccAddr.String()}, + ExtensionsList: []string{"mint"}, + MaxSupply: maxSupply, + }, + ) + s.Require().NoError(err) + + // Mint amount to fromAddr to burn lately + // _, err = s.precompile.Mint(ctx, contract, stateDB, &method, []interface{}{sender.Addr, big.NewInt(maxSupply.Int64())}) + // fmt.Println("errrrr", err) + // s.Require().NoError(err) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.BankKeeper.MintCoins(ctx, erc20types.ModuleName, sdk.NewCoins(sdk.NewCoin(tokenDenom, maxSupply))) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.BankKeeper.SendCoinsFromModuleToAccount(ctx, erc20types.ModuleName, fromAddr.Bytes(), sdk.NewCoins(sdk.NewCoin(tokenDenom, maxSupply))) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = s.precompile.BurnFrom(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected burn transaction to fail") + // s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected burn transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index 565e4b45..cdaf90c2 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -180,7 +180,7 @@ func ParseBurnArgs(args []interface{}) ( amount, ok := args[0].(*big.Int) if !ok { - return nil, fmt.Errorf("invalid amount: %v", args[1]) + return nil, fmt.Errorf("invalid amount: %v", args[0]) } return amount, nil From 8448f467d0f292410529035a39690cbdd3331ea1 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Fri, 7 Feb 2025 11:16:13 +0700 Subject: [PATCH 47/53] freeze logic --- precompiles/erc20/abi.json | 48 +++++++++++++++++++- precompiles/erc20/approve.go | 6 +++ precompiles/erc20/erc20.go | 12 ++++- precompiles/erc20/events.go | 23 ++++++++++ precompiles/erc20/tx.go | 61 +++++++++++++++++++++++++ precompiles/erc20/tx_test.go | 88 +++++++++++++++++++++++++++++++++++- precompiles/erc20/types.go | 17 +++++++ x/asset/keeper/keeper.go | 20 +++++++- x/asset/types/keys.go | 1 + 9 files changed, 269 insertions(+), 7 deletions(-) diff --git a/precompiles/erc20/abi.json b/precompiles/erc20/abi.json index 6a6bf143..071e5942 100644 --- a/precompiles/erc20/abi.json +++ b/precompiles/erc20/abi.json @@ -181,6 +181,19 @@ "name": "Mint", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "Freeze", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -335,7 +348,32 @@ } ], "name": "burn", - "outputs": [], + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "freeze", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "nonpayable", "type": "function" }, @@ -371,7 +409,13 @@ } ], "name": "burnFrom", - "outputs": [], + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "nonpayable", "type": "function" }, diff --git a/precompiles/erc20/approve.go b/precompiles/erc20/approve.go index 605ad4b4..8dc673ba 100644 --- a/precompiles/erc20/approve.go +++ b/precompiles/erc20/approve.go @@ -225,6 +225,12 @@ func (p Precompile) createAuthorization(ctx sdk.Context, grantee, granter common coins := sdk.Coins{{Denom: p.denom, Amount: sdkmath.NewIntFromBigInt(amount)}} expiration := ctx.BlockTime().Add(p.ApprovalExpiration) + // Check if granter is freezed + freezed := p.assetKeep.IsFreezed(ctx, granter) + if freezed { + return fmt.Errorf("address %s already be freezed", granter.String()) + } + // NOTE: we leave the allowed arg empty as all recipients are allowed (per ERC20 standard) authorization := banktypes.NewSendAuthorization(coins, []sdk.AccAddress{}) if err := authorization.ValidateBasic(); err != nil { diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index ab67457b..5cc3a26f 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -190,8 +190,11 @@ func (p *Precompile) HandleMethod( method *abi.Method, args []interface{}, ) (bz []byte, err error) { - params, err := p.assetKeep.GetParams(ctx) - allowedMethods := params.AllowExtensions + tm, err := p.assetKeep.GetTokenManager(ctx, p.denom) + if err != nil { + return nil, err + } + allowedMethods := tm.ExtensionsList if err != nil { return nil, err } @@ -216,6 +219,11 @@ func (p *Precompile) HandleMethod( return nil, fmt.Errorf("method %s is not supported", BurnFromMethod) } bz, err = p.BurnFrom(ctx, contract, stateDB, method, args) + case FreezeMethod: + if !slices.Contains(allowedMethods, FreezeMethod) { + return nil, fmt.Errorf("method %s is not supported", FreezeMethod) + } + bz, err = p.Freeze(ctx, contract, stateDB, method, args) case auth.ApproveMethod: bz, err = p.Approve(ctx, contract, stateDB, method, args) case auth.IncreaseAllowanceMethod: diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index 25a7b50e..b09da709 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -125,6 +125,29 @@ func (p Precompile) EmitBurnEvent(ctx sdk.Context, stateDB vm.StateDB, from comm return nil } +func (p Precompile) EmitFreezeEvent(ctx sdk.Context, stateDB vm.StateDB, to common.Address) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeBurn] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(to) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + // EmitApprovalEvent creates a new approval event emitted on Approve, IncreaseAllowance // and DecreaseAllowance transactions. func (p Precompile) EmitApprovalEvent(ctx sdk.Context, stateDB vm.StateDB, owner, spender common.Address, value *big.Int) error { diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index 21328974..72d082d5 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -34,6 +34,8 @@ const ( BurnFromMethod = "burnFrom" MintMethod = "mint" + + FreezeMethod = "freeze" ) // SendMsgURL defines the authorization type for MsgSend @@ -93,6 +95,12 @@ func (p *Precompile) transfer( return nil, err } + // Check if from is freezed + freezed := p.assetKeep.IsFreezed(ctx, from) + if freezed { + return nil, fmt.Errorf("address %s already be freezed", from.String()) + } + isTransferFrom := method.Name == TransferFromMethod owner := sdk.AccAddress(from.Bytes()) spenderAddr := contract.CallerAddress @@ -269,6 +277,12 @@ func (p *Precompile) burn( return nil, fmt.Errorf("sender is not token manager") } + // Check if from is freezed + freezed := p.assetKeep.IsFreezed(ctx, from) + if freezed { + return nil, fmt.Errorf("address %s already be freezed", from.String()) + } + burnFromAddr := sdk.AccAddress(from.Bytes()) coins := sdk.Coins{{Denom: p.denom, Amount: math.NewIntFromBigInt(amount)}} @@ -296,3 +310,50 @@ func (p *Precompile) burn( return method.Outputs.Pack(true) } + +func (p *Precompile) Freeze( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + from, err := ParseFreezeArgs(args) + if err != nil { + return nil, err + } + + return p.freeze(ctx, contract, stateDB, method, from) +} + +func (p *Precompile) freeze( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + to common.Address, +) (data []byte, err error) { + + sender := contract.CallerAddress + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, sender) + if err != nil || !havePerm { + return nil, fmt.Errorf("sender is not token manager") + } + + // Check if addr already freeze + exist := p.assetKeep.IsFreezed(ctx, to) + if exist { + return nil, fmt.Errorf("address already freezed") + } + + err = p.assetKeep.SetFreezeAddress(ctx, to) + if err != nil { + return nil, err + } + + if err = p.EmitFreezeEvent(ctx, stateDB, to); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go index aef84297..8a9b87e4 100644 --- a/precompiles/erc20/tx_test.go +++ b/precompiles/erc20/tx_test.go @@ -379,7 +379,7 @@ func (s *PrecompileTestSuite) TestMint() { } func (s *PrecompileTestSuite) TestBurn() { - method := s.precompile.Methods[MintMethod] + method := s.precompile.Methods[BurnMethod] // fromAddr is the address of the keyring account used for testing. sender := s.keyring.GetKey(0) invalidSender := s.keyring.GetKey(1) @@ -491,7 +491,7 @@ func (s *PrecompileTestSuite) TestBurn() { } func (s *PrecompileTestSuite) TestBurnFrom() { - method := s.precompile.Methods[MintMethod] + method := s.precompile.Methods[BurnFromMethod] // fromAddr is the address of the keyring account used for testing. sender := s.keyring.GetKey(0) invalidSender := s.keyring.GetKey(1) @@ -611,3 +611,87 @@ func (s *PrecompileTestSuite) TestBurnFrom() { }) } } + +func (s *PrecompileTestSuite) TestFreeze() { + method := s.precompile.Methods[FreezeMethod] + // fromAddr is the address of the keyring account used for testing. + sender := s.keyring.GetKey(0) + invalidSender := s.keyring.GetKey(1) + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + sender keyring.Key + }{ + { + "fail - invalid to address", + func() []interface{} { + return []interface{}{""} + }, + func() {}, + true, + "invalid from address", + sender, + }, + { + "fail - sender is not manager", + func() []interface{} { + return []interface{}{toAddr} + }, + func() {}, + true, + "sender is not token manager", + invalidSender, + }, + { + "pass", + func() []interface{} { + return []interface{}{toAddr} + }, + func() { + exist := s.network.App.AssetKeeper.IsFreezed(s.network.GetContext(), toAddr) + s.Require().True(exist) + }, + false, + "", + sender, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), tc.sender.Addr, s.precompile, 0) + + // Set up manager role for valid sender + err := s.precompile.assetKeep.TokenManagement.Set( + ctx, + s.tokenDenom, + assettypes.TokenManagement{ + Managers: []string{sender.AccAddr.String()}, + ExtensionsList: []string{"mint"}, + }, + ) + s.Require().NoError(err) + + // Mint amount to fromAddr to burn lately + // _, err = s.precompile.Mint(ctx, contract, stateDB, &method, []interface{}{sender.Addr, big.NewInt(maxSupply.Int64())}) + // fmt.Println("errrrr", err) + // s.Require().NoError(err) + + _, err = s.precompile.Freeze(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected burn transaction to fail") + // s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected burn transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index cdaf90c2..fc6d37ab 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -205,3 +205,20 @@ func ParseBurnFromArgs(args []interface{}) ( return from, amount, nil } + +func ParseFreezeArgs(args []interface{}) ( + from common.Address, err error, +) { + if len(args) != 1 { + return common.Address{}, fmt.Errorf("invalid number of arguments; expected 1; got: %d", len(args)) + } + + to, ok := args[0].(common.Address) + if !ok { + return common.Address{}, fmt.Errorf("invalid to address: %v", args[0]) + } + + return to, nil +} + + diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index b7d6931c..ed33df9b 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -31,6 +31,7 @@ type Keeper struct { Token collections.Map[string, types.Token] TokenManagement collections.Map[string, types.TokenManagement] WhitelistAddresses collections.Map[string, bool] + FreezeAddresses collections.Map[[]byte, bool] } // NewKeeper returns a new Keeper object with a given codec, dedicated @@ -54,6 +55,7 @@ func NewKeeper( Token: collections.NewMap(sb, types.TokenKey, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), TokenManagement: collections.NewMap(sb, types.TokenManagementKey, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), WhitelistAddresses: collections.NewMap(sb, types.WhitelistAddressesKey, "whitelist_addresses", collections.StringKey, collections.BoolValue), + FreezeAddresses: collections.NewMap(sb, types.FreezeAddressesKey, "freeze_addresses", collections.BytesKey, collections.BoolValue), } schema, err := sb.Build() @@ -105,7 +107,7 @@ func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr common. exist := false tm, err := k.TokenManagement.Get(ctx, tokenId) if err != nil { - return false, nil + return false, err } for _, manager := range tm.Managers { if bytes.Equal(addr.Bytes(), sdk.MustAccAddressFromBech32(manager).Bytes()) { @@ -116,6 +118,22 @@ func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr common. return exist, nil } +func (k Keeper) IsFreezed(ctx context.Context, addr common.Address) bool { + exist, err := k.FreezeAddresses.Get(ctx, addr.Bytes()) + if err != nil { + return false + } + return exist +} + +func (k Keeper) SetFreezeAddress(ctx context.Context, addr common.Address) error { + err := k.FreezeAddresses.Set(ctx, addr.Bytes(), true) + if err != nil { + return err + } + return nil +} + func (k Keeper) GetToken(ctx context.Context, tokenId string) (types.Token, error) { return k.Token.Get(ctx, tokenId) } diff --git a/x/asset/types/keys.go b/x/asset/types/keys.go index 17b3644e..5f32e6f3 100644 --- a/x/asset/types/keys.go +++ b/x/asset/types/keys.go @@ -10,6 +10,7 @@ var ( TokenManagementKey = collections.NewPrefix(2) TokenDistributionKey = collections.NewPrefix(3) WhitelistAddressesKey = collections.NewPrefix(4) + FreezeAddressesKey = collections.NewPrefix(5) ) const ( From ca63777014f4bc893c60fab03136a9c21dc300ca Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 10 Feb 2025 11:15:57 +0700 Subject: [PATCH 48/53] clean up example chain --- example_chain/activators.go | 2 +- example_chain/ante/ante.go | 55 --- example_chain/ante/cosmos_handler.go | 41 -- example_chain/ante/evm_benchmark_test.go | 157 ------- example_chain/ante/evm_handler.go | 21 - example_chain/ante/handler_options.go | 66 --- example_chain/ante/handler_options_test.go | 146 ------ example_chain/ante/integration_test.go | 173 ------- example_chain/app.go | 2 +- example_chain/eips/README.md | 258 ---------- example_chain/eips/eips.go | 36 -- example_chain/eips/eips_test.go | 441 ------------------ example_chain/eips/testdata/Counter.json | 38 -- example_chain/eips/testdata/Counter.sol | 15 - .../eips/testdata/CounterFactory.json | 56 --- .../eips/testdata/CounterFactory.sol | 25 - example_chain/eips/testdata/contracts.go | 17 - example_chain/osd/cmd/root.go | 415 ---------------- example_chain/osd/config/config.go | 42 -- example_chain/osd/main.go | 31 -- example_chain/test_helpers.go | 2 +- example_chain/testutil/abci.go | 280 ----------- example_chain/testutil/contract.go | 170 ------- example_chain/testutil/eth_setup.go | 205 -------- example_chain/testutil/fund.go | 43 -- example_chain/testutil/gas.go | 18 - example_chain/testutil/integration.go | 81 ---- testutil/integration/os/network/network.go | 2 +- 28 files changed, 4 insertions(+), 2834 deletions(-) delete mode 100644 example_chain/ante/ante.go delete mode 100644 example_chain/ante/cosmos_handler.go delete mode 100644 example_chain/ante/evm_benchmark_test.go delete mode 100644 example_chain/ante/evm_handler.go delete mode 100644 example_chain/ante/handler_options.go delete mode 100644 example_chain/ante/handler_options_test.go delete mode 100644 example_chain/ante/integration_test.go delete mode 100644 example_chain/eips/README.md delete mode 100644 example_chain/eips/eips.go delete mode 100644 example_chain/eips/eips_test.go delete mode 100644 example_chain/eips/testdata/Counter.json delete mode 100644 example_chain/eips/testdata/Counter.sol delete mode 100644 example_chain/eips/testdata/CounterFactory.json delete mode 100644 example_chain/eips/testdata/CounterFactory.sol delete mode 100644 example_chain/eips/testdata/contracts.go delete mode 100644 example_chain/osd/cmd/root.go delete mode 100644 example_chain/osd/config/config.go delete mode 100644 example_chain/osd/main.go delete mode 100644 example_chain/testutil/abci.go delete mode 100644 example_chain/testutil/contract.go delete mode 100644 example_chain/testutil/eth_setup.go delete mode 100644 example_chain/testutil/fund.go delete mode 100644 example_chain/testutil/gas.go delete mode 100644 example_chain/testutil/integration.go diff --git a/example_chain/activators.go b/example_chain/activators.go index 265e84a5..fbcff013 100644 --- a/example_chain/activators.go +++ b/example_chain/activators.go @@ -4,7 +4,7 @@ package example_chain import ( "github.com/evmos/os/x/evm/core/vm" - "github.com/realiotech/realio-network/example_chain/eips" + "github.com/evmos/os/example_chain/eips" ) // evmosActivators defines a map of opcode modifiers associated diff --git a/example_chain/ante/ante.go b/example_chain/ante/ante.go deleted file mode 100644 index 059dfcea..00000000 --- a/example_chain/ante/ante.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package ante - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" -) - -// NewAnteHandler returns an ante handler responsible for attempting to route an -// Ethereum or SDK transaction to an internal ante handler for performing -// transaction-level processing (e.g. fee payment, signature verification) before -// being passed onto it's respective handler. -func NewAnteHandler(options HandlerOptions) sdk.AnteHandler { - return func( - ctx sdk.Context, tx sdk.Tx, sim bool, - ) (newCtx sdk.Context, err error) { - var anteHandler sdk.AnteHandler - - txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx) - if ok { - opts := txWithExtensions.GetExtensionOptions() - if len(opts) > 0 { - switch typeURL := opts[0].GetTypeUrl(); typeURL { - case "/os.evm.v1.ExtensionOptionsEthereumTx": - // handle as *evmtypes.MsgEthereumTx - anteHandler = newMonoEVMAnteHandler(options) - case "/os.types.v1.ExtensionOptionDynamicFeeTx": - // cosmos-sdk tx with dynamic fee extension - anteHandler = newCosmosAnteHandler(options) - default: - return ctx, errorsmod.Wrapf( - errortypes.ErrUnknownExtensionOptions, - "rejecting tx with unsupported extension option: %s", typeURL, - ) - } - - return anteHandler(ctx, tx, sim) - } - } - - // handle as totally normal Cosmos SDK tx - switch tx.(type) { - case sdk.Tx: - anteHandler = newCosmosAnteHandler(options) - default: - return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx) - } - - return anteHandler(ctx, tx, sim) - } -} diff --git a/example_chain/ante/cosmos_handler.go b/example_chain/ante/cosmos_handler.go deleted file mode 100644 index 0f934754..00000000 --- a/example_chain/ante/cosmos_handler.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package ante - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - sdkvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante" - evmoscosmosante "github.com/evmos/os/ante/cosmos" - evmante "github.com/evmos/os/ante/evm" - evmtypes "github.com/evmos/os/x/evm/types" -) - -// newCosmosAnteHandler creates the default ante handler for Cosmos transactions -func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { - return sdk.ChainAnteDecorators( - evmoscosmosante.NewRejectMessagesDecorator(), // reject MsgEthereumTxs - evmoscosmosante.NewAuthzLimiterDecorator( // disable the Msg types that cannot be included on an authz.MsgExec msgs field - sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), - sdk.MsgTypeURL(&sdkvesting.MsgCreateVestingAccount{}), - ), - ante.NewSetUpContextDecorator(), - ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), - ante.NewValidateBasicDecorator(), - ante.NewTxTimeoutHeightDecorator(), - ante.NewValidateMemoDecorator(options.AccountKeeper), - evmoscosmosante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), - ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), - // SetPubKeyDecorator must be called before all signature verification decorators - ante.NewSetPubKeyDecorator(options.AccountKeeper), - ante.NewValidateSigCountDecorator(options.AccountKeeper), - ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), - ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), - ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewRedundantRelayDecorator(options.IBCKeeper), - evmante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), - ) -} diff --git a/example_chain/ante/evm_benchmark_test.go b/example_chain/ante/evm_benchmark_test.go deleted file mode 100644 index d603d38c..00000000 --- a/example_chain/ante/evm_benchmark_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) -package ante_test - -import ( - "fmt" - "math/big" - "testing" - - "cosmossdk.io/errors" - "cosmossdk.io/math" - sdktypes "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/evmos/os/ante" - ethante "github.com/evmos/os/ante/evm" - cmmnfactory "github.com/evmos/os/testutil/integration/common/factory" - "github.com/evmos/os/testutil/integration/os/factory" - "github.com/evmos/os/testutil/integration/os/grpc" - testkeyring "github.com/evmos/os/testutil/integration/os/keyring" - evmostypes "github.com/evmos/os/types" - evmtypes "github.com/evmos/os/x/evm/types" - chainante "github.com/realiotech/realio-network/example_chain/ante" - "github.com/realiotech/realio-network/testutil/integration/os/network" -) - -type benchmarkSuite struct { - network *network.UnitTestNetwork - grpcHandler grpc.Handler - txFactory factory.TxFactory - keyring testkeyring.Keyring -} - -// Setup -var table = []struct { - name string - txType string - simulate bool -}{ - { - "evm_transfer_sim", - "evm_transfer", - true, - }, - { - "evm_transfer", - "evm_transfer", - false, - }, - { - "bank_msg_send_sim", - "bank_msg_send", - true, - }, - { - "bank_msg_send", - "bank_msg_send", - false, - }, -} - -func BenchmarkAnteHandler(b *testing.B) { - keyring := testkeyring.New(2) - - for _, v := range table { - // Reset chain on every tx type to have a clean state - // and a fair benchmark - b.StopTimer() - unitNetwork := network.NewUnitTestNetwork( - network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), - ) - grpcHandler := grpc.NewIntegrationHandler(unitNetwork) - txFactory := factory.New(unitNetwork, grpcHandler) - suite := benchmarkSuite{ - network: unitNetwork, - grpcHandler: grpcHandler, - txFactory: txFactory, - keyring: keyring, - } - - handlerOptions := suite.generateHandlerOptions() - ante := chainante.NewAnteHandler(handlerOptions) - b.StartTimer() - - b.Run(fmt.Sprintf("tx_type_%v", v.name), func(b *testing.B) { - for i := 0; i < b.N; i++ { - // Stop timer while building the tx setup - b.StopTimer() - // Start with a clean block - if err := unitNetwork.NextBlock(); err != nil { - b.Fatal(errors.Wrap(err, "failed to create block")) - } - ctx := unitNetwork.GetContext() - - // Generate fresh tx type - tx, err := suite.generateTxType(v.txType) - if err != nil { - b.Fatal(errors.Wrap(err, "failed to generate tx type")) - } - b.StartTimer() - - // Run benchmark - _, err = ante(ctx, tx, v.simulate) - if err != nil { - b.Fatal(errors.Wrap(err, "failed to run ante handler")) - } - } - }) - } -} - -func (s *benchmarkSuite) generateTxType(txType string) (sdktypes.Tx, error) { - switch txType { - case "evm_transfer": - senderPriv := s.keyring.GetPrivKey(0) - receiver := s.keyring.GetKey(1) - txArgs := evmtypes.EvmTxArgs{ - To: &receiver.Addr, - Amount: big.NewInt(1000), - } - return s.txFactory.GenerateSignedEthTx(senderPriv, txArgs) - case "bank_msg_send": - sender := s.keyring.GetKey(1) - receiver := s.keyring.GetAccAddr(0) - bankmsg := banktypes.NewMsgSend( - sender.AccAddr, - receiver, - sdktypes.NewCoins( - sdktypes.NewCoin( - s.network.GetBaseDenom(), - math.NewInt(1000), - ), - ), - ) - txArgs := cmmnfactory.CosmosTxArgs{Msgs: []sdktypes.Msg{bankmsg}} - return s.txFactory.BuildCosmosTx(sender.Priv, txArgs) - default: - return nil, fmt.Errorf("invalid tx type") - } -} - -func (s *benchmarkSuite) generateHandlerOptions() chainante.HandlerOptions { - encCfg := s.network.GetEncodingConfig() - return chainante.HandlerOptions{ - Cdc: s.network.App.AppCodec(), - AccountKeeper: s.network.App.AccountKeeper, - BankKeeper: s.network.App.BankKeeper, - ExtensionOptionChecker: evmostypes.HasDynamicFeeExtensionOption, - EvmKeeper: s.network.App.EVMKeeper, - FeegrantKeeper: s.network.App.FeeGrantKeeper, - IBCKeeper: s.network.App.IBCKeeper, - FeeMarketKeeper: s.network.App.FeeMarketKeeper, - SignModeHandler: encCfg.TxConfig.SignModeHandler(), - SigGasConsumer: ante.SigVerificationGasConsumer, - MaxTxGasWanted: 1_000_000_000, - TxFeeChecker: ethante.NewDynamicFeeChecker(s.network.App.FeeMarketKeeper), - } -} diff --git a/example_chain/ante/evm_handler.go b/example_chain/ante/evm_handler.go deleted file mode 100644 index fdb7e54c..00000000 --- a/example_chain/ante/evm_handler.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package ante - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - evmante "github.com/evmos/os/ante/evm" -) - -// newMonoEVMAnteHandler creates the sdk.AnteHandler implementation for the EVM transactions. -func newMonoEVMAnteHandler(options HandlerOptions) sdk.AnteHandler { - return sdk.ChainAnteDecorators( - evmante.NewEVMMonoDecorator( - options.AccountKeeper, - options.FeeMarketKeeper, - options.EvmKeeper, - options.MaxTxGasWanted, - ), - ) -} diff --git a/example_chain/ante/handler_options.go b/example_chain/ante/handler_options.go deleted file mode 100644 index 8dcaa065..00000000 --- a/example_chain/ante/handler_options.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package ante - -import ( - errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" - txsigning "cosmossdk.io/x/tx/signing" - "github.com/cosmos/cosmos-sdk/codec" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/cosmos-sdk/x/auth/ante" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" - anteinterfaces "github.com/evmos/os/ante/interfaces" -) - -// HandlerOptions defines the list of module keepers required to run the Evmos -// AnteHandler decorators. -type HandlerOptions struct { - Cdc codec.BinaryCodec - AccountKeeper anteinterfaces.AccountKeeper - BankKeeper anteinterfaces.BankKeeper - IBCKeeper *ibckeeper.Keeper - FeeMarketKeeper anteinterfaces.FeeMarketKeeper - EvmKeeper anteinterfaces.EVMKeeper - FeegrantKeeper ante.FeegrantKeeper - ExtensionOptionChecker ante.ExtensionOptionChecker - SignModeHandler *txsigning.HandlerMap - SigGasConsumer func(meter storetypes.GasMeter, sig signing.SignatureV2, params authtypes.Params) error - MaxTxGasWanted uint64 - TxFeeChecker ante.TxFeeChecker -} - -// Validate checks if the keepers are defined -func (options HandlerOptions) Validate() error { - if options.Cdc == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "codec is required for AnteHandler") - } - if options.AccountKeeper == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler") - } - if options.BankKeeper == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler") - } - if options.IBCKeeper == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "ibc keeper is required for AnteHandler") - } - if options.FeeMarketKeeper == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler") - } - if options.EvmKeeper == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler") - } - if options.SigGasConsumer == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "signature gas consumer is required for AnteHandler") - } - if options.SignModeHandler == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for AnteHandler") - } - if options.TxFeeChecker == nil { - return errorsmod.Wrap(errortypes.ErrLogic, "tx fee checker is required for AnteHandler") - } - return nil -} diff --git a/example_chain/ante/handler_options_test.go b/example_chain/ante/handler_options_test.go deleted file mode 100644 index ee0cb9a6..00000000 --- a/example_chain/ante/handler_options_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package ante_test - -import ( - "testing" - - "github.com/evmos/os/ante" - ethante "github.com/evmos/os/ante/evm" - "github.com/evmos/os/types" - chainante "github.com/realiotech/realio-network/example_chain/ante" - "github.com/realiotech/realio-network/testutil/integration/os/network" - "github.com/stretchr/testify/require" -) - -func TestValidateHandlerOptions(t *testing.T) { - nw := network.NewUnitTestNetwork() - cases := []struct { - name string - options chainante.HandlerOptions - expPass bool - }{ - { - "fail - empty options", - chainante.HandlerOptions{}, - false, - }, - { - "fail - empty account keeper", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nil, - }, - false, - }, - { - "fail - empty bank keeper", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nil, - }, - false, - }, - { - "fail - empty IBC keeper", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nil, - }, - false, - }, - { - "fail - empty fee market keeper", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nil, - }, - false, - }, - { - "fail - empty EVM keeper", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nw.App.FeeMarketKeeper, - EvmKeeper: nil, - }, - false, - }, - { - "fail - empty signature gas consumer", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nw.App.FeeMarketKeeper, - EvmKeeper: nw.App.EVMKeeper, - SigGasConsumer: nil, - }, - false, - }, - { - "fail - empty signature mode handler", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nw.App.FeeMarketKeeper, - EvmKeeper: nw.App.EVMKeeper, - SigGasConsumer: ante.SigVerificationGasConsumer, - SignModeHandler: nil, - }, - false, - }, - { - "fail - empty tx fee checker", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nw.App.FeeMarketKeeper, - EvmKeeper: nw.App.EVMKeeper, - SigGasConsumer: ante.SigVerificationGasConsumer, - SignModeHandler: nw.App.GetTxConfig().SignModeHandler(), - TxFeeChecker: nil, - }, - false, - }, - { - "success - default app options", - chainante.HandlerOptions{ - Cdc: nw.App.AppCodec(), - AccountKeeper: nw.App.AccountKeeper, - BankKeeper: nw.App.BankKeeper, - ExtensionOptionChecker: types.HasDynamicFeeExtensionOption, - EvmKeeper: nw.App.EVMKeeper, - FeegrantKeeper: nw.App.FeeGrantKeeper, - IBCKeeper: nw.App.IBCKeeper, - FeeMarketKeeper: nw.App.FeeMarketKeeper, - SignModeHandler: nw.GetEncodingConfig().TxConfig.SignModeHandler(), - SigGasConsumer: ante.SigVerificationGasConsumer, - MaxTxGasWanted: 40000000, - TxFeeChecker: ethante.NewDynamicFeeChecker(nw.App.FeeMarketKeeper), - }, - true, - }, - } - - for _, tc := range cases { - err := tc.options.Validate() - if tc.expPass { - require.NoError(t, err, tc.name) - } else { - require.Error(t, err, tc.name) - } - } -} diff --git a/example_chain/ante/integration_test.go b/example_chain/ante/integration_test.go deleted file mode 100644 index ed5240c4..00000000 --- a/example_chain/ante/integration_test.go +++ /dev/null @@ -1,173 +0,0 @@ -package ante_test - -import ( - "cosmossdk.io/math" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - commonfactory "github.com/evmos/os/testutil/integration/common/factory" - "github.com/evmos/os/testutil/integration/os/factory" - "github.com/evmos/os/testutil/integration/os/grpc" - testkeyring "github.com/evmos/os/testutil/integration/os/keyring" - integrationutils "github.com/evmos/os/testutil/integration/os/utils" - "github.com/realiotech/realio-network/testutil/integration/os/network" - testutiltx "github.com/realiotech/realio-network/testutil/tx" - - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/ginkgo/v2" - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/gomega" -) - -type IntegrationTestSuite struct { - network network.Network - factory factory.TxFactory - grpcHandler grpc.Handler - keyring testkeyring.Keyring -} - -var _ = Describe("when sending a Cosmos transaction", Label("AnteHandler"), Ordered, func() { - var ( - s *IntegrationTestSuite - addr sdk.AccAddress - priv cryptotypes.PrivKey - msg sdk.Msg - ) - - BeforeAll(func() { - keyring := testkeyring.New(3) - - integrationNetwork := network.New( - network.WithPreFundedAccounts(keyring.GetAllAccAddrs()...), - ) - grpcHandler := grpc.NewIntegrationHandler(integrationNetwork) - txFactory := factory.New(integrationNetwork, grpcHandler) - s = &IntegrationTestSuite{ - network: integrationNetwork, - factory: txFactory, - grpcHandler: grpcHandler, - keyring: keyring, - } - }) - - Context("and the sender account has enough balance to pay for the transaction cost", Ordered, func() { - var ( - // rewards are the real accrued rewards - rewards sdk.DecCoins - // minExpRewards are the minimun rewards that should be accrued - // for the test case - minExpRewards = sdk.DecCoins{sdk.DecCoin{Amount: math.LegacyNewDec(1e5), Denom: s.network.GetBaseDenom()}} - delegationCoin = sdk.Coin{Amount: math.NewInt(1e15), Denom: s.network.GetBaseDenom()} - transferAmt = math.NewInt(1e14) - ) - - BeforeEach(func() { - key := s.keyring.GetKey(0) - addr = key.AccAddr - priv = key.Priv - - msg = &banktypes.MsgSend{ - FromAddress: addr.String(), - ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn", - Amount: sdk.Coins{sdk.Coin{Amount: transferAmt, Denom: s.network.GetBaseDenom()}}, - } - - valAddr := s.network.GetValidators()[0].OperatorAddress - err := s.factory.Delegate(priv, valAddr, delegationCoin) - Expect(err).To(BeNil()) - - rewards, err = integrationutils.WaitToAccrueRewards(s.network, s.grpcHandler, addr.String(), minExpRewards) - Expect(err).To(BeNil()) - }) - - It("should succeed & not withdraw any staking rewards", func() { - prevBalanceRes, err := s.grpcHandler.GetBalanceFromBank(addr, s.network.GetBaseDenom()) - Expect(err).To(BeNil()) - - baseFeeRes, err := s.grpcHandler.GetEvmBaseFee() - Expect(err).To(BeNil()) - Expect(baseFeeRes).ToNot(BeNil(), "baseFeeRes is nil") - - gasPrice := baseFeeRes.BaseFee - - res, err := s.factory.ExecuteCosmosTx( - priv, - commonfactory.CosmosTxArgs{ - Msgs: []sdk.Msg{msg}, - GasPrice: gasPrice, - }, - ) - Expect(err).To(BeNil()) - Expect(res.IsOK()).To(BeTrue()) - - // include the tx in a block to update state - err = s.network.NextBlock() - Expect(err).To(BeNil()) - - // fees should be deducted from balance - Expect(baseFeeRes.BaseFee).ToNot(BeNil(), "baseFeeRes.BaseFee is nil") - - feesAmt := math.NewInt(res.GasWanted).Mul(*baseFeeRes.BaseFee) - balanceRes, err := s.grpcHandler.GetBalanceFromBank(addr, s.network.GetBaseDenom()) - Expect(err).To(BeNil()) - Expect(balanceRes.Balance.Amount).To(Equal(prevBalanceRes.Balance.Amount.Sub(transferAmt).Sub(feesAmt))) - - rewardsRes, err := s.grpcHandler.GetDelegationTotalRewards(addr.String()) - Expect(err).To(BeNil()) - - // rewards should not be used. Should be more - // than the previous value queried - Expect(rewardsRes.Total.Sub(rewards).IsAllPositive()).To(BeTrue()) - }) - }) - - Context("and the sender account neither has enough balance nor sufficient staking rewards to pay for the transaction cost", func() { - BeforeEach(func() { - addr, priv = testutiltx.NewAccAddressAndKey() - - // this is a new address that does not exist on chain. - // Transfer 1 aevmos to this account so it is - // added on chain - err := s.factory.FundAccount( - s.keyring.GetKey(0), - addr, - sdk.Coins{ - sdk.Coin{ - Amount: math.NewInt(1), - Denom: s.network.GetBaseDenom(), - }, - }, - ) - Expect(err).To(BeNil()) - // persist the state changes - Expect(s.network.NextBlock()).To(BeNil()) - - msg = &banktypes.MsgSend{ - FromAddress: addr.String(), - ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn", - Amount: sdk.Coins{sdk.Coin{Amount: math.NewInt(1e14), Denom: s.network.GetBaseDenom()}}, - } - }) - - It("should fail", func() { - var gas uint64 = 200_000 // specify gas to avoid failing on simulation tx (internal call in the ExecuteCosmosTx if gas not specified) - res, err := s.factory.ExecuteCosmosTx( - priv, - commonfactory.CosmosTxArgs{ - Msgs: []sdk.Msg{msg}, - Gas: &gas, - }, - ) - Expect(res.IsErr()).To(BeTrue()) - Expect(res.GetLog()).To(ContainSubstring("insufficient funds")) - Expect(err).To(BeNil()) - Expect(s.network.NextBlock()).To(BeNil()) - }) - - It("should not withdraw any staking rewards", func() { - rewardsRes, err := s.grpcHandler.GetDelegationTotalRewards(addr.String()) - Expect(err).To(BeNil()) - Expect(rewardsRes.Total.Empty()).To(BeTrue()) - }) - }) -}) diff --git a/example_chain/app.go b/example_chain/app.go index 9691db6e..02828b4a 100644 --- a/example_chain/app.go +++ b/example_chain/app.go @@ -118,7 +118,7 @@ import ( "github.com/evmos/os/x/feemarket" feemarketkeeper "github.com/evmos/os/x/feemarket/keeper" feemarkettypes "github.com/evmos/os/x/feemarket/types" - chainante "github.com/realiotech/realio-network/example_chain/ante" + chainante "github.com/evmos/os/example_chain/ante" "github.com/spf13/cast" // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens diff --git a/example_chain/eips/README.md b/example_chain/eips/README.md deleted file mode 100644 index 18c1f4ef..00000000 --- a/example_chain/eips/README.md +++ /dev/null @@ -1,258 +0,0 @@ -# Evmos Custom EIPs - -This document explain how **evmOS** allows chain built on top of it to define custom EIPs to modify the behavior of EVM -opcodes. - -## Custom EIPs - -Inside an EVM, every state transition or query is executed by evaluating opcodes. Custom EIPs are functions used to -change the behavior of these opcodes to tailor the EVM functionalities to fit the app-chain requirements. - -Custom EIPs should be defined in an `eips` package inside the `./app/eips/` folder of chains using the **evmOS** -framework. This organization of custom implementations is not a strict requirement, but is the suggested approach to -have a clean organization of functionalities. In this file, only the custom modifier should be defined. - -Inside this package, custom EIP should be defined in a file called `eips.go`. In this file, the EIPs modifier should be -defined with the signature: - -```go -func(jt *vm.JumpTable) {} -``` - -where `vm` is the package `"github.com/evmos/os/x/evm/core/vm"`. - -Custom EIPs are used to modify the behavior of opcodes, which are described by the `operation` structure: - -```go -type operation struct { - // execute is the operation function - execute executionFunc - constantGas uint64 - dynamicGas gasFunc - // minStack tells how many stack items are required - minStack int - // maxStack specifies the max length the stack can have for this operation - // to not overflow the stack. - maxStack int - - // memorySize returns the memory size required for the operation - memorySize memorySizeFunc -} -``` - -With the **evmOS** framework, it is possible to modify any of the fields defined in the type via the `operation` setter -methods: - -- `SetExecute`: update the execution logic for the opcode. - -- `SetConstantGas`: update the value used for the constant gas cost. - -- `SetDynamicGas`: update the function used to compute the dynamic gas cost. - -- `SetMinStack`: update the minimum number of items in the stack required to execute the `operation`. - -- `SetMaxStack`: update the maximum number of items that will be in the stack after executing the `operation`. - -- `SetMemorySize`: the memory size required by the `operation`. - -An example for an EIP which modifies the constant gas used for the `CREATE` opcode is reported below: - -```go -// Enable a custom EIP-0000 -func Enable0000(jt *vm.JumpTable) { - jt[vm.CREATE].SetConstantGas(1) -} -``` - -In the same folder should also be defined tests and contracts used to verify the EIPs logic. - -## Activate Custom EIPs - -The activation of custom EIPs should be done inside the `config.go` file defined in the `./app/` folder. This file has -the role of the single source for modify the EVM implementation which is defined in the -[`x/evm/`](https://github.com/evmos/os/tree/main/x/evm) folder -of **evmOS**. - -In this file, 3 main components should be defined: - -- The custom EIPs, also called activators. -- The additional default EIPs enabled. -- The EVM configurator instance. - -All these components will be described in the following sections. - -### Opcode & EIP Activators - -Activators is the name provided by [Go-ethereum](https://geth.ethereum.org/) to the definition of the structure -grouping all possible non-default EIPs: - -```go -var activators = map[int]func(*JumpTable){ - 3855: enable3855, - ... -} -``` - -It can be interpreted as a list of available functionalities that can be toggled to change opcodes behavior. The -structure is a map where the key is the EIP number in the octal representation, and the value is the custom EIP -function that has to be evaluated. - -In **evmOS**, custom activators should be defined in a structure with the same data type, like in the example below: - -```go -// Activate custom EIPs: 0000, 0001, 0002, etc -evmosActivators = map[int]func(*vm.JumpTable){ - "evmos_0": eips.Enable0000, - "evmos_1": eips.Enable0001, - "evmos_2": eips.Enable0002, -} -``` - -It should be noted that the value of each key in the example is the modifier defined in the `eips` package in the -example provided at the of the [Custom EIPs](#custom-eips) section. - -### Default EIPs - -Custom EIPs defined in the `activators` map are not enabled by default. This type is only used to define the list of -custom functionalities that can be activated. To specify which custom EIP activate, we should modify the -**evmOS** `x/evm` module params. The parameter orchestrating enabled custom EIPs is the `DefaultExtraEIPs` and -**evmOS** provide an easy and safe way to customize it. - -To specify which activator enable in the chain, a new variable containing a slice of keys of the custom activators -should be defined. An example is reported below: - -```go -evmosEnabledEIPs = []int64{ - "evmos_0", -} -``` - -In this way, even though the custom activators defined $3$ new EIPs, we are going to activate only the number `evmos_0` - -### EVM Configurator - -The EVM configuration is the type used to modify the EVM configuration before starting a node. The type is defined as: - -```go -type EVMConfigurator struct { - extendedEIPs map[int]func(*vm.JumpTable) - extendedDefaultExtraEIPs []int64 - sealed bool -} -``` - -Currently, only 2 customizations are possible: - -- `WithExtendedEips`: extended the default available EIPs. - -- `WithExtendedDefaultExtraEIPs`: extended the default active EIPs. - -It is important to notice that the configurator will only allow to append new entries to the default ones defined by -**evmOS**. The reason behind this choice is to ensure the correct and safe execution of the virtual machine but still -allowing partners to customize their implementation. - -The `EVMConfigurator` type should be constructed using the builder pattern inside the `init()` function of the file so -that it is run during the creation of the application. - -An example of the usage of the configurator is reported below: - -```go -configurator := evmconfig.NewEVMConfigurator(). - WithExtendedEips(customActivators). - WithExtendedDefaultExtraEIPs(defaultEnabledEIPs...). - Configure() - -err := configurator.Configure() -``` - -Errors are raised when the configurator tries to append an item with the same name of one of the default one. Since -this type is used to configure the EVM before starting the node, it is safe, and suggested, to panic: - -```go -if err != nil { - panic(err) -} -``` - -## Custom EIPs Deep Dive - -When the chain receives an EVM transaction, it is handled by the `MsgServer` of the `x/evm` within the method -`EthereumTx`. The method then calls `ApplyTransaction` where the EVM configuration is created: - -```go -cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID) -``` - -During the creation of this type, a query is made to retrieve the `x/evm` params. After this step, the request is -passed inside the `ApplyMessageWithConfig` where a new instance of the EVM is created: - -```go -evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB) -``` - -The `NewEVM` method calls the `NewEVMWithHooks` where a new instance of the virtual machine interpreter is created: - -```go -evm.interpreter = NewEVMInterpreter(evm, config) -``` - -The management of activators is handled in this function: - -```go -func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { - // If jump table was not initialised we set the default one. - if cfg.JumpTable == nil { - cfg.JumpTable = DefaultJumpTable(evm.chainRules) - for i, eip := range cfg.ExtraEips { - // Deep-copy jumptable to prevent modification of opcodes in other tables - copy := CopyJumpTable(cfg.JumpTable) - if err := EnableEIP(eip, copy); err != nil { - // Disable it, so caller can check if it's activated or not - cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) - log.Error("EIP activation failed", "eip", eip, "error", err) - } - cfg.JumpTable = copy - } - } - - return &EVMInterpreter{ - evm: evm, - cfg: cfg, - } -} -``` - -As we can see, a new `JumpTable` is created if it is not received from previous evm executions in the same transaction. -After that, the function iterate over the `ExtraEips` defined in the configuration. Then, it is checked if the EIP is -associated with an activator. If yes, the activator function is execute, otherwise an error is returned and the EIP is -removed from the VM configuration. At this point, all the opcodes are ready to be executed. - -## How to Use It - -In previous sections has been described required structures and files to use the EVM configurator to enable custom -EIPs. In this the general procedure is taken into considerations. Two different scenarios are described: - -- New chain. - -- Running chain. - -### New Chain - -For a new chain starting from block genesis, the procedure described in the sections above is enough. To summarize it: - -- Create the eip file with custom activators. - -- Create the config file with custom activators, default EIPs, and the configurator. - -After starting the chain, the genesis validation will perform all the required checks and the chain will be ready using -the new custom EIPs. - -### Running Chain - -The proper approach to include and enable new EIPs, with the current state of the development, is via coordinate chain -upgrade. During the chain upgrade it is important to define the custom activators since they are not stored in the -chain. To enable them there are two possibilities: - -- Write a migration to add the new enabled EIPsm during the upgrade. - -- After the upgrade, create a governance proposal to modify the `x/evm` params. diff --git a/example_chain/eips/eips.go b/example_chain/eips/eips.go deleted file mode 100644 index 2c309414..00000000 --- a/example_chain/eips/eips.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package eips - -import ( - "github.com/evmos/os/x/evm/core/vm" -) - -var ( - Multiplier = uint64(10) - SstoreConstantGas = uint64(500) -) - -// enable0000 contains the logic to modify the CREATE and CREATE2 opcodes -// constant gas value. -func Enable0000(jt *vm.JumpTable) { - currentValCreate := jt[vm.CREATE].GetConstantGas() - jt[vm.CREATE].SetConstantGas(currentValCreate * Multiplier) - - currentValCreate2 := jt[vm.CREATE2].GetConstantGas() - jt[vm.CREATE2].SetConstantGas(currentValCreate2 * Multiplier) -} - -// enable0001 contains the logic to modify the CALL opcode -// constant gas value. -func Enable0001(jt *vm.JumpTable) { - currentVal := jt[vm.CALL].GetConstantGas() - jt[vm.CALL].SetConstantGas(currentVal * Multiplier) -} - -// enable0002 contains the logic to modify the SSTORE opcode -// constant gas value. -func Enable0002(jt *vm.JumpTable) { - jt[vm.SSTORE].SetConstantGas(SstoreConstantGas) -} diff --git a/example_chain/eips/eips_test.go b/example_chain/eips/eips_test.go deleted file mode 100644 index 80ad7357..00000000 --- a/example_chain/eips/eips_test.go +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package eips_test - -import ( - "fmt" - "math/big" - "testing" - - "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/ethereum/go-ethereum/common" - "github.com/evmos/os/example_chain/eips" - "github.com/evmos/os/example_chain/eips/testdata" - "github.com/evmos/os/testutil/integration/os/factory" - "github.com/evmos/os/testutil/integration/os/grpc" - "github.com/evmos/os/testutil/integration/os/keyring" - integrationutils "github.com/evmos/os/testutil/integration/os/utils" - "github.com/realiotech/realio-network/testutil/integration/os/network" - - evmtypes "github.com/evmos/os/x/evm/types" - - "github.com/ethereum/go-ethereum/params" - - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/ginkgo/v2" - //nolint:revive // dot imports are fine for Ginkgo - . "github.com/onsi/gomega" -) - -// Below tests are divided in 3 steps: -// 1. Deploy and interact with contracts to compute the gas used BEFORE enabling -// the IP. -// 2. Activate the IP under test. -// 3. Deploy and interact with contracts to compute the gas used AFTER enabling -// the IP. - -func TestIPs(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "EvmosIPs Suite") -} - -var _ = Describe("Improvement proposal evmos_0 - ", Ordered, func() { - var ( - in network.Network - tf factory.TxFactory - gh grpc.Handler - k keyring.Keyring - - senderPriv types.PrivKey - senderPriv2 types.PrivKey - senderAddr2 common.Address - - // Gas used before enabling the IP. - gasUsedPre int64 - ) - - // Multiplier used to modify the opcodes associated with evmos_0 IP. - ipMultiplier := uint64(5) - - // The factory counter is used because it will create a new instance of - // the counter contract, allowing to test the CREATE opcode. - counterFactoryContract, err := testdata.LoadCounterFactoryContract() - Expect(err).ToNot(HaveOccurred(), "failed to load Counter Factory contract") - - deploymentData := factory.ContractDeploymentData{ - Contract: counterFactoryContract, - ConstructorArgs: []interface{}{}, - } - - BeforeAll(func() { - k = keyring.New(2) - in = network.New( - network.WithPreFundedAccounts(k.GetAllAccAddrs()...), - ) - gh = grpc.NewIntegrationHandler(in) - tf = factory.New(in, gh) - - // Account used to deploy the contract before enabling the IP. - senderPriv = k.GetPrivKey(0) - // Account used to deploy the contract after enabling the IP. A second - // account is used to avoid possible additional gas costs due to the change - // in the Nonce. - senderPriv2 = k.GetPrivKey(1) - senderAddr2 = k.GetAddr(1) - - // Set extra IPs to empty to allow testing a single modifier. - defaultParams := evmtypes.DefaultParams() - defaultParams.ExtraEIPs = []string{} - - err := integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: defaultParams, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - Expect(in.NextBlock()).To(BeNil()) - }) - - It("should deploy the contract before enabling the IP", func() { - deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) - Expect(err).To(BeNil(), "failed to create deployment tx args") - - res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) - Expect(err).To(BeNil(), "failed during contract deployment") - gasUsedPre = res.GasUsed - }) - - It("should enable the new IP", func() { - eips.Multiplier = ipMultiplier - newIP := "evmos_0" - - qRes, err := gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) - err = integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: qRes.Params, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - - Expect(in.NextBlock()).To(BeNil()) - - qRes, err = gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have IP evmos_0 in evm params") - }) - - It("should change CREATE opcode constant gas after enabling evmos_0 IP", func() { - gasCostPre := params.CreateGas - - deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) - Expect(err).To(BeNil(), "failed to create deployment tx args") - - res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) - Expect(err).To(BeNil(), "failed during contract deployment") - // commit block to update sender nonce - Expect(in.NextBlock()).To(BeNil()) - - gasUsedPost := res.GasUsed - - // The difference in gas is the new cost of the opcode, minus the cost of the - // opcode before enabling the new eip. - gasUsedDiff := ipMultiplier*gasCostPre - gasCostPre - expectedGas := gasUsedPre + int64(gasUsedDiff) - Expect(gasUsedPost).To(Equal(expectedGas)) - }) -}) - -var _ = Describe("Improvement proposal evmos_1 - ", Ordered, func() { - var ( - in network.Network - tf factory.TxFactory - gh grpc.Handler - k keyring.Keyring - - senderPriv types.PrivKey - - // Gas used before enabling the IP. - gasUsedPre int64 - - // The address of the factory counter. - counterFactoryAddr common.Address - ) - - // Multiplier used to modify the opcodes associated with evmos_1. - eipMultiplier := uint64(5) - initialCounterValue := 1 - - // The counter factory contract is used to deploy a counter contract and - // perform state transition using the CALL opcode. - counterFactoryContract, err := testdata.LoadCounterFactoryContract() - Expect(err).ToNot(HaveOccurred(), "failed to load Counter Factory contract") - - BeforeAll(func() { - k = keyring.New(1) - in = network.New( - network.WithPreFundedAccounts(k.GetAllAccAddrs()...), - ) - gh = grpc.NewIntegrationHandler(in) - tf = factory.New(in, gh) - - senderPriv = k.GetPrivKey(0) - - // Set extra IPs to empty to allow testing a single modifier. - defaultParams := evmtypes.DefaultParams() - defaultParams.ExtraEIPs = []string{} - err = integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: defaultParams, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - - Expect(in.NextBlock()).To(BeNil()) - }) - - It("should deploy the contract before enabling the IP", func() { - counterFactoryAddr, err = tf.DeployContract( - senderPriv, - evmtypes.EvmTxArgs{}, - factory.ContractDeploymentData{ - Contract: counterFactoryContract, - ConstructorArgs: []interface{}{}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to deploy counter factory contract") - Expect(in.NextBlock()).To(BeNil()) - - res, err := tf.ExecuteContractCall( - senderPriv, - evmtypes.EvmTxArgs{To: &counterFactoryAddr}, - factory.CallArgs{ - ContractABI: counterFactoryContract.ABI, - MethodName: "incrementCounter", - Args: []interface{}{}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to increment counter value") - gasUsedPre = res.GasUsed - - Expect(in.NextBlock()).To(BeNil()) - - // Query the counter value to check proper state transition later. - res, err = tf.ExecuteContractCall( - senderPriv, - evmtypes.EvmTxArgs{To: &counterFactoryAddr}, - factory.CallArgs{ - ContractABI: counterFactoryContract.ABI, - MethodName: "getCounterValue", - Args: []interface{}{}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to get counter value") - Expect(in.NextBlock()).To(BeNil()) - - ethRes, err := evmtypes.DecodeTxResponse(res.Data) - Expect(err).ToNot(HaveOccurred(), "failed to decode tx response") - - unpacked, err := counterFactoryContract.ABI.Unpack( - "getCounterValue", - ethRes.Ret, - ) - Expect(err).ToNot(HaveOccurred(), "failed to unpack counter value") - - counter, ok := unpacked[0].(*big.Int) - Expect(ok).To(BeTrue(), "failed to convert counter to big.Int") - Expect(counter.String()).To(Equal(fmt.Sprintf("%d", initialCounterValue+1)), "counter is not correct") - }) - It("should enable the new IP", func() { - eips.Multiplier = eipMultiplier - newIP := "evmos_1" - - qRes, err := gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) - - err = integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: qRes.Params, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - - Expect(in.NextBlock()).To(BeNil()) - - qRes, err = gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have ip evmos_1 in evm params") - }) - It("should change CALL opcode constant gas after enabling IP", func() { - // Constant gas cost used before enabling the new IP. - gasCostPre := params.WarmStorageReadCostEIP2929 - - res, err := tf.ExecuteContractCall( - senderPriv, - evmtypes.EvmTxArgs{To: &counterFactoryAddr}, - factory.CallArgs{ - ContractABI: counterFactoryContract.ABI, - MethodName: "incrementCounter", - Args: []interface{}{}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to increment counter value") - gasUsedPost := res.GasUsed - Expect(in.NextBlock()).To(BeNil()) - - res, err = tf.ExecuteContractCall( - senderPriv, - evmtypes.EvmTxArgs{To: &counterFactoryAddr}, - factory.CallArgs{ - ContractABI: counterFactoryContract.ABI, - MethodName: "getCounterValue", - Args: []interface{}{}, - }, - ) - Expect(err).ToNot(HaveOccurred(), "failed to get counter value") - Expect(in.NextBlock()).To(BeNil()) - - ethRes, err := evmtypes.DecodeTxResponse(res.Data) - Expect(err).ToNot(HaveOccurred(), "failed to decode tx response") - - unpacked, err := counterFactoryContract.ABI.Unpack( - "getCounterValue", - ethRes.Ret, - ) - Expect(err).ToNot(HaveOccurred(), "failed to unpack counter value") - - counter, ok := unpacked[0].(*big.Int) - Expect(ok).To(BeTrue(), "failed to convert counter to big.Int") - Expect(counter.String()).To(Equal(fmt.Sprintf("%d", initialCounterValue+2)), "counter is not updated correctly") - - // The difference in gas is the new cost of the opcode, minus the cost of the - // opcode before enabling the new eip. - gasUsedDiff := eipMultiplier*gasCostPre - gasCostPre - expectedGas := gasUsedPre + int64(gasUsedDiff) - Expect(gasUsedPost).To(Equal(expectedGas)) - }) -}) - -var _ = Describe("Improvement proposal evmos_2 - ", Ordered, func() { - var ( - in network.Network - tf factory.TxFactory - gh grpc.Handler - k keyring.Keyring - - senderPriv types.PrivKey - senderAddr common.Address - senderPriv2 types.PrivKey - senderAddr2 common.Address - gasUsedPre int64 - ) - // Constant gas used to modify the opcodes associated with evmos_2. - constantGas := uint64(500) - - counterContract, err := testdata.LoadCounterContract() - Expect(err).ToNot(HaveOccurred(), "failed to load Counter contract") - - deploymentData := factory.ContractDeploymentData{ - Contract: counterContract, - ConstructorArgs: []interface{}{}, - } - BeforeAll(func() { - k = keyring.New(2) - in = network.New( - network.WithPreFundedAccounts(k.GetAllAccAddrs()...), - ) - gh = grpc.NewIntegrationHandler(in) - tf = factory.New(in, gh) - - // Account used to deploy the contract before enabling the IP. - senderPriv = k.GetPrivKey(0) - senderAddr = k.GetAddr(0) - // Account used to deploy the contract after enabling the IP. A second - // account is used to avoid possible additional gas costs due to the change - // in the Nonce. - senderPriv2 = k.GetPrivKey(0) - senderAddr2 = k.GetAddr(0) - - // Set extra IPs to empty to allow testing a single modifier. - defaultParams := evmtypes.DefaultParams() - defaultParams.ExtraEIPs = []string{} - - err = integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: defaultParams, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - - Expect(in.NextBlock()).To(BeNil()) - }) - - It("should deploy the contract before enabling the IP", func() { - deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr, evmtypes.EvmTxArgs{}, deploymentData) - Expect(err).To(BeNil(), "failed to create deployment tx args") - - res, err := tf.ExecuteEthTx(senderPriv, deploymentTxArgs) - Expect(err).To(BeNil(), "failed during contract deployment") - Expect(in.NextBlock()).To(BeNil()) - - gasUsedPre = res.GasUsed - }) - - It("should enable the new IP", func() { - eips.SstoreConstantGas = constantGas - newIP := "evmos_2" - - qRes, err := gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - qRes.Params.ExtraEIPs = append(qRes.Params.ExtraEIPs, newIP) - err = integrationutils.UpdateEvmParams( - integrationutils.UpdateParamsInput{ - Tf: tf, - Network: in, - Pk: senderPriv, - Params: qRes.Params, - }, - ) - Expect(err).To(BeNil(), "failed during update of evm params") - - Expect(in.NextBlock()).To(BeNil()) - - qRes, err = gh.GetEvmParams() - Expect(err).To(BeNil(), "failed during query to evm params") - Expect(qRes.Params.ExtraEIPs).To(ContainElement(newIP), "expected to have ip evmos_2 in evm params") - }) - - It("should change SSTORE opcode constant gas after enabling IP", func() { - deploymentTxArgs, err := tf.GenerateDeployContractArgs(senderAddr2, evmtypes.EvmTxArgs{}, deploymentData) - Expect(err).To(BeNil(), "failed to create deployment tx args") - - res, err := tf.ExecuteEthTx(senderPriv2, deploymentTxArgs) - Expect(err).To(BeNil(), "failed during contract deployment") - Expect(in.NextBlock()).To(BeNil()) - - gasUsedPost := res.GasUsed - - // The expected gas is previous gas plus the constant gas because - // previous this eip, SSTORE was using only the dynamic gas. - expectedGas := gasUsedPre + int64(constantGas) - Expect(gasUsedPost).To(Equal(expectedGas)) - }) -}) diff --git a/example_chain/eips/testdata/Counter.json b/example_chain/eips/testdata/Counter.json deleted file mode 100644 index 31819578..00000000 --- a/example_chain/eips/testdata/Counter.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "Counter", - "sourceName": "solidity/example_chain/eips/testdata/Counter.sol", - "abi": [ - { - "inputs": [], - "name": "counter", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decrement", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "increment", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x6080604052600160005534801561001557600080fd5b506101ba806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/example_chain/eips/testdata/Counter.sol b/example_chain/eips/testdata/Counter.sol deleted file mode 100644 index 30ba0869..00000000 --- a/example_chain/eips/testdata/Counter.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity >=0.7.0 <0.9.0; - -contract Counter { - uint256 public counter = 1; - - function increment() external { - counter++; - } - - function decrement() external { - counter--; - } -} diff --git a/example_chain/eips/testdata/CounterFactory.json b/example_chain/eips/testdata/CounterFactory.json deleted file mode 100644 index d3c9674d..00000000 --- a/example_chain/eips/testdata/CounterFactory.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "Counterfactory", - "sourceName": "solidity/example_chain/eips/testdata/CounterFactory.sol", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "counterInstance", - "outputs": [ - { - "internalType": "contract Counter", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decrementCounter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "getCounterValue", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "incrementCounter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x608060405234801561001057600080fd5b5060405161001d9061007e565b604051809103906000f080158015610039573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061008b565b6101df8061045c83390190565b6103c28061009a6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b9661461005157806372142b891461005b578063aef38e7214610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b610063610123565b6040516100709190610279565b60405180910390f35b6100816101ba565b60405161008e9190610313565b60405180910390f35b61009f6101de565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d09de08a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010957600080fd5b505af115801561011d573d6000803e3d6000fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166361bc221a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b5919061035f565b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632baeceb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561024657600080fd5b505af115801561025a573d6000803e3d6000fd5b50505050565b6000819050919050565b61027381610260565b82525050565b600060208201905061028e600083018461026a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102d96102d46102cf84610294565b6102b4565b610294565b9050919050565b60006102eb826102be565b9050919050565b60006102fd826102e0565b9050919050565b61030d816102f2565b82525050565b60006020820190506103286000830184610304565b92915050565b600080fd5b61033c81610260565b811461034757600080fd5b50565b60008151905061035981610333565b92915050565b6000602082840312156103755761037461032e565b5b60006103838482850161034a565b9150509291505056fea26469706673582212209247a66c2dbee615e99f0a204e17785fb9d8102833d627c3f5cc5f86d3d4793964736f6c634300081400336080604052600160005534801561001557600080fd5b506101ba806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80632baeceb71461004657806361bc221a14610050578063d09de08a1461006e575b600080fd5b61004e610078565b005b610058610091565b60405161006591906100c9565b60405180910390f35b610076610097565b005b60008081548092919061008a90610113565b9190505550565b60005481565b6000808154809291906100a99061013c565b9190505550565b6000819050919050565b6100c3816100b0565b82525050565b60006020820190506100de60008301846100ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061011e826100b0565b915060008203610131576101306100e4565b5b600182039050919050565b6000610147826100b0565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610179576101786100e4565b5b60018201905091905056fea2646970667358221220e2cfc61bbf42463bc63fe07f96984cffab77d85daac62b0017cf4c9306d056d064736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80635b34b9661461005157806372142b891461005b578063aef38e7214610079578063f5c5ad8314610097575b600080fd5b6100596100a1565b005b610063610123565b6040516100709190610279565b60405180910390f35b6100816101ba565b60405161008e9190610313565b60405180910390f35b61009f6101de565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d09de08a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010957600080fd5b505af115801561011d573d6000803e3d6000fd5b50505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166361bc221a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610191573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b5919061035f565b905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632baeceb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561024657600080fd5b505af115801561025a573d6000803e3d6000fd5b50505050565b6000819050919050565b61027381610260565b82525050565b600060208201905061028e600083018461026a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102d96102d46102cf84610294565b6102b4565b610294565b9050919050565b60006102eb826102be565b9050919050565b60006102fd826102e0565b9050919050565b61030d816102f2565b82525050565b60006020820190506103286000830184610304565b92915050565b600080fd5b61033c81610260565b811461034757600080fd5b50565b60008151905061035981610333565b92915050565b6000602082840312156103755761037461032e565b5b60006103838482850161034a565b9150509291505056fea26469706673582212209247a66c2dbee615e99f0a204e17785fb9d8102833d627c3f5cc5f86d3d4793964736f6c63430008140033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/example_chain/eips/testdata/CounterFactory.sol b/example_chain/eips/testdata/CounterFactory.sol deleted file mode 100644 index 7b64412d..00000000 --- a/example_chain/eips/testdata/CounterFactory.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity >=0.7.0 <0.9.0; - -import "./Counter.sol"; - -contract Counterfactory { - Counter public counterInstance; - - constructor() { - counterInstance = new Counter(); - } - - function incrementCounter() public { - counterInstance.increment(); - } - - function decrementCounter() public { - counterInstance.decrement(); - } - - function getCounterValue() public view returns (uint256) { - return counterInstance.counter(); - } -} diff --git a/example_chain/eips/testdata/contracts.go b/example_chain/eips/testdata/contracts.go deleted file mode 100644 index 2d336b52..00000000 --- a/example_chain/eips/testdata/contracts.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testdata - -import ( - contractutils "github.com/evmos/os/contracts/utils" - evmtypes "github.com/evmos/os/x/evm/types" -) - -func LoadCounterContract() (evmtypes.CompiledContract, error) { - return contractutils.LoadContractFromJSONFile("Counter.json") -} - -func LoadCounterFactoryContract() (evmtypes.CompiledContract, error) { - return contractutils.LoadContractFromJSONFile("CounterFactory.json") -} diff --git a/example_chain/osd/cmd/root.go b/example_chain/osd/cmd/root.go deleted file mode 100644 index b2e34ba8..00000000 --- a/example_chain/osd/cmd/root.go +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package cmd - -import ( - "errors" - "io" - "os" - - "cosmossdk.io/log" - "cosmossdk.io/store" - snapshottypes "cosmossdk.io/store/snapshots/types" - storetypes "cosmossdk.io/store/types" - confixcmd "cosmossdk.io/tools/confix/cmd" - tmcfg "github.com/cometbft/cometbft/config" - cmtcli "github.com/cometbft/cometbft/libs/cli" - dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" - clientcfg "github.com/cosmos/cosmos-sdk/client/config" - "github.com/cosmos/cosmos-sdk/client/debug" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/pruning" - "github.com/cosmos/cosmos-sdk/client/rpc" - "github.com/cosmos/cosmos-sdk/client/snapshot" - sdkserver "github.com/cosmos/cosmos-sdk/server" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" - sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - evmoscmd "github.com/evmos/os/client" - evmoscmdconfig "github.com/evmos/os/cmd/config" - evmoskeyring "github.com/evmos/os/crypto/keyring" - evmosserver "github.com/evmos/os/server" - evmosserverconfig "github.com/evmos/os/server/config" - srvflags "github.com/evmos/os/server/flags" - "github.com/realiotech/realio-network/example_chain" - cmdcfg "github.com/realiotech/realio-network/example_chain/osd/config" - "github.com/spf13/cast" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -type emptyAppOptions struct{} - -func (ao emptyAppOptions) Get(_ string) interface{} { return nil } - -// NewRootCmd creates a new root command for osd. It is called once in the -// main function. -func NewRootCmd() *cobra.Command { - // we "pre"-instantiate the application for getting the injected/configured encoding configuration - // and the CLI options for the modules - // add keyring to autocli opts - tempApp := example_chain.NewExampleApp( - log.NewNopLogger(), - dbm.NewMemDB(), - nil, - true, - emptyAppOptions{}, - example_chain.EvmosAppOptions, - ) - - encodingConfig := sdktestutil.TestEncodingConfig{ - InterfaceRegistry: tempApp.InterfaceRegistry(), - Codec: tempApp.AppCodec(), - TxConfig: tempApp.GetTxConfig(), - Amino: tempApp.LegacyAmino(), - } - - initClientCtx := client.Context{}. - WithCodec(encodingConfig.Codec). - WithInterfaceRegistry(encodingConfig.InterfaceRegistry). - WithTxConfig(encodingConfig.TxConfig). - WithLegacyAmino(encodingConfig.Amino). - WithInput(os.Stdin). - WithAccountRetriever(authtypes.AccountRetriever{}). - WithBroadcastMode(flags.FlagBroadcastMode). - WithHomeDir(example_chain.DefaultNodeHome). - WithViper(""). // In simapp, we don't use any prefix for env variables. - // evmOS specific setup - WithKeyringOptions(evmoskeyring.Option()). - WithLedgerHasProtobuf(true) - - rootCmd := &cobra.Command{ - Use: "osd", - Short: "exemplary evmOS app", - PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { - // set the default command outputs - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) - - initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) - initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) - if err != nil { - return err - } - - initClientCtx, err = clientcfg.ReadFromClientConfig(initClientCtx) - if err != nil { - return err - } - - // This needs to go after ReadFromClientConfig, as that function - // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode - // is only available if the client is online. - if !initClientCtx.Offline { - enabledSignModes := append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL) //nolint:gocritic - txConfigOpts := tx.ConfigOptions{ - EnabledSignModes: enabledSignModes, - TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), - } - txConfig, err := tx.NewTxConfigWithOptions( - initClientCtx.Codec, - txConfigOpts, - ) - if err != nil { - return err - } - - initClientCtx = initClientCtx.WithTxConfig(txConfig) - } - - if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { - return err - } - - customAppTemplate, customAppConfig := InitAppConfig(cmdcfg.BaseDenom) - customTMConfig := initTendermintConfig() - - return sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig) - }, - } - - initRootCmd(rootCmd, tempApp) - - autoCliOpts := tempApp.AutoCliOpts() - initClientCtx, _ = clientcfg.ReadFromClientConfig(initClientCtx) - autoCliOpts.ClientCtx = initClientCtx - - if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { - panic(err) - } - - return rootCmd -} - -// initTendermintConfig helps to override default Tendermint Config values. -// return tmcfg.DefaultConfig if no custom configuration is required for the application. -func initTendermintConfig() *tmcfg.Config { - cfg := tmcfg.DefaultConfig() - - // these values put a higher strain on node memory - // cfg.P2P.MaxNumInboundPeers = 100 - // cfg.P2P.MaxNumOutboundPeers = 40 - - return cfg -} - -// InitAppConfig helps to override default appConfig template and configs. -// return "", nil if no custom configuration is required for the application. -func InitAppConfig(denom string) (string, interface{}) { - type CustomAppConfig struct { - serverconfig.Config - - EVM evmosserverconfig.EVMConfig - JSONRPC evmosserverconfig.JSONRPCConfig - TLS evmosserverconfig.TLSConfig - } - - // Optionally allow the chain developer to overwrite the SDK's default - // server config. - srvCfg := serverconfig.DefaultConfig() - // The SDK's default minimum gas price is set to "" (empty value) inside - // app.toml. If left empty by validators, the node will halt on startup. - // However, the chain developer can set a default app.toml value for their - // validators here. - // - // In summary: - // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their - // own app.toml config, - // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their - // own app.toml to override, or use this default value. - // - // In this example application, we set the min gas prices to 0. - srvCfg.MinGasPrices = "0" + denom - - customAppConfig := CustomAppConfig{ - Config: *srvCfg, - EVM: *evmosserverconfig.DefaultEVMConfig(), - JSONRPC: *evmosserverconfig.DefaultJSONRPCConfig(), - TLS: *evmosserverconfig.DefaultTLSConfig(), - } - - customAppTemplate := serverconfig.DefaultConfigTemplate + - evmosserverconfig.DefaultEVMConfigTemplate - - return customAppTemplate, customAppConfig -} - -func initRootCmd(rootCmd *cobra.Command, osApp *example_chain.ExampleChain) { - cfg := sdk.GetConfig() - cfg.Seal() - - rootCmd.AddCommand( - genutilcli.InitCmd( - osApp.BasicModuleManager, - example_chain.DefaultNodeHome, - ), - genutilcli.Commands(osApp.TxConfig(), osApp.BasicModuleManager, example_chain.DefaultNodeHome), - cmtcli.NewCompletionCmd(rootCmd, true), - debug.Cmd(), - confixcmd.ConfigCommand(), - pruning.Cmd(newApp, example_chain.DefaultNodeHome), - snapshot.Cmd(newApp), - ) - - // add evmOS' flavored TM commands to start server, etc. - evmosserver.AddCommands( - rootCmd, - evmosserver.NewDefaultStartOptions(newApp, example_chain.DefaultNodeHome), - appExport, - addModuleInitFlags, - ) - - // add evmOS key commands - rootCmd.AddCommand( - evmoscmd.KeyCommands(example_chain.DefaultNodeHome, true), - ) - - // add keybase, auxiliary RPC, query, genesis, and tx child commands - rootCmd.AddCommand( - sdkserver.StatusCommand(), - queryCommand(), - txCommand(), - ) - - // add general tx flags to the root command - var err error - rootCmd, err = srvflags.AddTxFlags(rootCmd) - if err != nil { - panic(err) - } -} - -func addModuleInitFlags(_ *cobra.Command) {} - -func queryCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "query", - Aliases: []string{"q"}, - Short: "Querying subcommands", - DisableFlagParsing: false, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - rpc.QueryEventForTxCmd(), - rpc.ValidatorCommand(), - authcmd.QueryTxsByEventsCmd(), - authcmd.QueryTxCmd(), - sdkserver.QueryBlockCmd(), - sdkserver.QueryBlockResultsCmd(), - ) - - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: false, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), - authcmd.GetEncodeCommand(), - authcmd.GetDecodeCommand(), - authcmd.GetSimulateCmd(), - ) - - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") - - return cmd -} - -// newApp creates the application -func newApp( - logger log.Logger, - db dbm.DB, - traceStore io.Writer, - appOpts servertypes.AppOptions, -) servertypes.Application { - var cache storetypes.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(sdkserver.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - pruningOpts, err := sdkserver.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) - chainID := cast.ToString(appOpts.Get(flags.FlagChainID)) - if chainID == "" { - chainID, err = evmoscmdconfig.GetChainIDFromHome(homeDir) - if err != nil { - panic(err) - } - } - - snapshotStore, err := sdkserver.GetSnapshotStore(appOpts) - if err != nil { - panic(err) - } - - snapshotOptions := snapshottypes.NewSnapshotOptions( - cast.ToUint64(appOpts.Get(sdkserver.FlagStateSyncSnapshotInterval)), - cast.ToUint32(appOpts.Get(sdkserver.FlagStateSyncSnapshotKeepRecent)), - ) - - baseappOptions := []func(*baseapp.BaseApp){ - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(sdkserver.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(sdkserver.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(sdkserver.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))), - baseapp.SetSnapshot(snapshotStore, snapshotOptions), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))), - baseapp.SetChainID(chainID), - } - - // Set up the required mempool and ABCI proposal handlers for evmOS - baseappOptions = append(baseappOptions, func(app *baseapp.BaseApp) { - mempool := sdkmempool.NoOpMempool{} - app.SetMempool(mempool) - - handler := baseapp.NewDefaultProposalHandler(mempool, app) - app.SetPrepareProposal(handler.PrepareProposalHandler()) - app.SetProcessProposal(handler.ProcessProposalHandler()) - }) - - return example_chain.NewExampleApp( - logger, db, traceStore, true, - appOpts, - example_chain.EvmosAppOptions, - baseappOptions..., - ) -} - -// appExport creates a new application (optionally at a given height) and exports state. -func appExport( - logger log.Logger, - db dbm.DB, - traceStore io.Writer, - height int64, - forZeroHeight bool, - jailAllowedAddrs []string, - appOpts servertypes.AppOptions, - modulesToExport []string, -) (servertypes.ExportedApp, error) { - var exampleApp *example_chain.ExampleChain - - // this check is necessary as we use the flag in x/upgrade. - // we can exit more gracefully by checking the flag here. - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - viperAppOpts, ok := appOpts.(*viper.Viper) - if !ok { - return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") - } - - // overwrite the FlagInvCheckPeriod - viperAppOpts.Set(sdkserver.FlagInvCheckPeriod, 1) - appOpts = viperAppOpts - - if height != -1 { - exampleApp = example_chain.NewExampleApp(logger, db, traceStore, false, appOpts, example_chain.EvmosAppOptions) - - if err := exampleApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - exampleApp = example_chain.NewExampleApp(logger, db, traceStore, true, appOpts, example_chain.EvmosAppOptions) - } - - return exampleApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) -} diff --git a/example_chain/osd/config/config.go b/example_chain/osd/config/config.go deleted file mode 100644 index 9899d4c9..00000000 --- a/example_chain/osd/config/config.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package config - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const ( - // Bech32Prefix defines the Bech32 prefix used for accounts on the exemplary evmOS blockchain. - Bech32Prefix = "evmos" - - // Bech32PrefixAccAddr defines the Bech32 prefix of an account's address. - Bech32PrefixAccAddr = Bech32Prefix - // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key. - Bech32PrefixAccPub = Bech32Prefix + sdk.PrefixPublic - // Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address. - Bech32PrefixValAddr = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixOperator - // Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key. - Bech32PrefixValPub = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixOperator + sdk.PrefixPublic - // Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address. - Bech32PrefixConsAddr = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixConsensus - // Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key. - Bech32PrefixConsPub = Bech32Prefix + sdk.PrefixValidator + sdk.PrefixConsensus + sdk.PrefixPublic -) - -const ( - // DisplayDenom defines the denomination displayed to users in client applications. - DisplayDenom = "evmos" - // BaseDenom defines to the default denomination used in the evmOS example chain. - BaseDenom = "aevmos" - // BaseDenomUnit defines the precision of the base denomination. - BaseDenomUnit = 18 -) - -// SetBech32Prefixes sets the global prefixes to be used when serializing addresses and public keys to Bech32 strings. -func SetBech32Prefixes(config *sdk.Config) { - config.SetBech32PrefixForAccount(Bech32PrefixAccAddr, Bech32PrefixAccPub) - config.SetBech32PrefixForValidator(Bech32PrefixValAddr, Bech32PrefixValPub) - config.SetBech32PrefixForConsensusNode(Bech32PrefixConsAddr, Bech32PrefixConsPub) -} diff --git a/example_chain/osd/main.go b/example_chain/osd/main.go deleted file mode 100644 index 14e1b39e..00000000 --- a/example_chain/osd/main.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package main - -import ( - "fmt" - "os" - - svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - sdk "github.com/cosmos/cosmos-sdk/types" - examplechain "github.com/realiotech/realio-network/example_chain" - "github.com/realiotech/realio-network/example_chain/osd/cmd" - chainconfig "github.com/realiotech/realio-network/example_chain/osd/config" -) - -func main() { - setupSDKConfig() - - rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, "osd", examplechain.DefaultNodeHome); err != nil { - fmt.Fprintln(rootCmd.OutOrStderr(), err) - os.Exit(1) - } -} - -func setupSDKConfig() { - config := sdk.GetConfig() - chainconfig.SetBech32Prefixes(config) - config.Seal() -} diff --git a/example_chain/test_helpers.go b/example_chain/test_helpers.go index 768eb17e..6c4b412e 100644 --- a/example_chain/test_helpers.go +++ b/example_chain/test_helpers.go @@ -26,7 +26,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" "github.com/evmos/os/cmd/config" feemarkettypes "github.com/evmos/os/x/feemarket/types" - chainconfig "github.com/realiotech/realio-network/example_chain/osd/config" + chainconfig "github.com/evmos/os/example_chain/osd/config" "github.com/stretchr/testify/require" ) diff --git a/example_chain/testutil/abci.go b/example_chain/testutil/abci.go deleted file mode 100644 index b29efc00..00000000 --- a/example_chain/testutil/abci.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "fmt" - "time" - - errorsmod "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - cmttypes "github.com/cometbft/cometbft/types" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - errortypes "github.com/cosmos/cosmos-sdk/types/errors" - - app "github.com/realiotech/realio-network/example_chain" - "github.com/realiotech/realio-network/testutil/tx" -) - -// Commit commits a block at a given time. Reminder: At the end of each -// Tendermint Consensus round the following methods are run -// 1. BeginBlock -// 2. DeliverTx -// 3. EndBlock -// 4. Commit -func Commit(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (sdk.Context, error) { - header, err := commit(ctx, app, t, vs) - if err != nil { - return ctx, err - } - - return ctx.WithBlockHeader(header), nil -} - -// CommitAndCreateNewCtx commits a block at a given time creating a ctx with the current settings -// This is useful to keep test settings that could be affected by EndBlockers, e.g. -// setting a baseFee == 0 and expecting this condition to continue after commit -func CommitAndCreateNewCtx(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (sdk.Context, error) { - header, err := commit(ctx, app, t, vs) - if err != nil { - return ctx, err - } - - // NewContext function keeps the multistore - // but resets other context fields - // GasMeter is set as InfiniteGasMeter - newCtx := app.BaseApp.NewContextLegacy(false, header) - // set the reseted fields to keep the current ctx settings - newCtx = newCtx.WithMinGasPrices(ctx.MinGasPrices()) - newCtx = newCtx.WithEventManager(ctx.EventManager()) - newCtx = newCtx.WithKVGasConfig(ctx.KVGasConfig()) - newCtx = newCtx.WithTransientKVGasConfig(ctx.TransientKVGasConfig()) - - return newCtx, nil -} - -// DeliverTx delivers a cosmos tx for a given set of msgs -func DeliverTx( - ctx sdk.Context, - exampleApp *app.ExampleChain, - priv cryptotypes.PrivKey, - gasPrice *sdkmath.Int, - msgs ...sdk.Msg, -) (abci.ExecTxResult, error) { - txConfig := exampleApp.GetTxConfig() - tx, err := tx.PrepareCosmosTx( - ctx, - exampleApp, - tx.CosmosTxArgs{ - TxCfg: txConfig, - Priv: priv, - ChainID: ctx.ChainID(), - Gas: 10_000_000, - GasPrice: gasPrice, - Msgs: msgs, - }, - ) - if err != nil { - return abci.ExecTxResult{}, err - } - return BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) -} - -// DeliverEthTx generates and broadcasts a Cosmos Tx populated with MsgEthereumTx messages. -// If a private key is provided, it will attempt to sign all messages with the given private key, -// otherwise, it will assume the messages have already been signed. -func DeliverEthTx( - exampleApp *app.ExampleChain, - priv cryptotypes.PrivKey, - msgs ...sdk.Msg, -) (abci.ExecTxResult, error) { - txConfig := exampleApp.GetTxConfig() - - tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) - if err != nil { - return abci.ExecTxResult{}, err - } - res, err := BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) - if err != nil { - return res, err - } - - codec := exampleApp.AppCodec() - if _, err := CheckEthTxResponse(res, codec); err != nil { - return res, err - } - return res, nil -} - -// DeliverEthTxWithoutCheck generates and broadcasts a Cosmos Tx populated with MsgEthereumTx messages. -// If a private key is provided, it will attempt to sign all messages with the given private key, -// otherwise, it will assume the messages have already been signed. It does not check if the Eth tx is -// successful or not. -func DeliverEthTxWithoutCheck( - exampleApp *app.ExampleChain, - priv cryptotypes.PrivKey, - msgs ...sdk.Msg, -) (abci.ExecTxResult, error) { - txConfig := exampleApp.GetTxConfig() - - tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) - if err != nil { - return abci.ExecTxResult{}, err - } - - res, err := BroadcastTxBytes(exampleApp, txConfig.TxEncoder(), tx) - if err != nil { - return abci.ExecTxResult{}, err - } - - return res, nil -} - -// CheckTx checks a cosmos tx for a given set of msgs -func CheckTx( - ctx sdk.Context, - exampleApp *app.ExampleChain, - priv cryptotypes.PrivKey, - gasPrice *sdkmath.Int, - msgs ...sdk.Msg, -) (abci.ResponseCheckTx, error) { - txConfig := exampleApp.GetTxConfig() - - tx, err := tx.PrepareCosmosTx( - ctx, - exampleApp, - tx.CosmosTxArgs{ - TxCfg: txConfig, - Priv: priv, - ChainID: ctx.ChainID(), - GasPrice: gasPrice, - Gas: 10_000_000, - Msgs: msgs, - }, - ) - if err != nil { - return abci.ResponseCheckTx{}, err - } - return checkTxBytes(exampleApp, txConfig.TxEncoder(), tx) -} - -// CheckEthTx checks a Ethereum tx for a given set of msgs -func CheckEthTx( - exampleApp *app.ExampleChain, - priv cryptotypes.PrivKey, - msgs ...sdk.Msg, -) (abci.ResponseCheckTx, error) { - txConfig := exampleApp.GetTxConfig() - - tx, err := tx.PrepareEthTx(txConfig, priv, msgs...) - if err != nil { - return abci.ResponseCheckTx{}, err - } - return checkTxBytes(exampleApp, txConfig.TxEncoder(), tx) -} - -// BroadcastTxBytes encodes a transaction and calls DeliverTx on the app. -func BroadcastTxBytes(app *app.ExampleChain, txEncoder sdk.TxEncoder, tx sdk.Tx) (abci.ExecTxResult, error) { - // bz are bytes to be broadcasted over the network - bz, err := txEncoder(tx) - if err != nil { - return abci.ExecTxResult{}, err - } - - req := abci.RequestFinalizeBlock{Txs: [][]byte{bz}} - - res, err := app.BaseApp.FinalizeBlock(&req) - if err != nil { - return abci.ExecTxResult{}, err - } - if len(res.TxResults) != 1 { - return abci.ExecTxResult{}, fmt.Errorf("unexpected transaction results. Expected 1, got: %d", len(res.TxResults)) - } - txRes := res.TxResults[0] - if txRes.Code != 0 { - return abci.ExecTxResult{}, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "log: %s", txRes.Log) - } - - return *txRes, nil -} - -// commit is a private helper function that runs the EndBlocker logic, commits the changes, -// updates the header, runs the BeginBlocker function and returns the updated header -func commit(ctx sdk.Context, app *app.ExampleChain, t time.Duration, vs *cmttypes.ValidatorSet) (tmproto.Header, error) { - header := ctx.BlockHeader() - req := abci.RequestFinalizeBlock{Height: header.Height} - - if vs != nil { - res, err := app.FinalizeBlock(&req) - if err != nil { - return header, err - } - - nextVals, err := applyValSetChanges(vs, res.ValidatorUpdates) - if err != nil { - return header, err - } - header.ValidatorsHash = vs.Hash() - header.NextValidatorsHash = nextVals.Hash() - } else { - if _, err := app.EndBlocker(ctx); err != nil { - return header, err - } - } - - if _, err := app.Commit(); err != nil { - return header, err - } - - header.Height++ - header.Time = header.Time.Add(t) - header.AppHash = app.LastCommitID().Hash - - if _, err := app.BeginBlocker(ctx); err != nil { - return header, err - } - - return header, nil -} - -// checkTxBytes encodes a transaction and calls checkTx on the app. -func checkTxBytes(app *app.ExampleChain, txEncoder sdk.TxEncoder, tx sdk.Tx) (abci.ResponseCheckTx, error) { - bz, err := txEncoder(tx) - if err != nil { - return abci.ResponseCheckTx{}, err - } - - req := abci.RequestCheckTx{Tx: bz} - res, err := app.BaseApp.CheckTx(&req) - if err != nil { - return abci.ResponseCheckTx{}, err - } - - if res.Code != 0 { - return abci.ResponseCheckTx{}, errorsmod.Wrapf(errortypes.ErrInvalidRequest, res.Log) - } - - return *res, nil -} - -// applyValSetChanges takes in cmttypes.ValidatorSet and []abci.ValidatorUpdate and will return a new cmttypes.ValidatorSet which has the -// provided validator updates applied to the provided validator set. -func applyValSetChanges(valSet *cmttypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) (*cmttypes.ValidatorSet, error) { - updates, err := cmttypes.PB2TM.ValidatorUpdates(valUpdates) - if err != nil { - return nil, err - } - - // must copy since validator set will mutate with UpdateWithChangeSet - newVals := valSet.Copy() - err = newVals.UpdateWithChangeSet(updates) - if err != nil { - return nil, err - } - - return newVals, nil -} diff --git a/example_chain/testutil/contract.go b/example_chain/testutil/contract.go deleted file mode 100644 index e78717c5..00000000 --- a/example_chain/testutil/contract.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "fmt" - "math/big" - - "github.com/cosmos/gogoproto/proto" - - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/cosmos-sdk/codec" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - - evm "github.com/evmos/os/x/evm/types" - evmtypes "github.com/evmos/os/x/evm/types" - exampleapp "github.com/realiotech/realio-network/example_chain" - "github.com/realiotech/realio-network/testutil/tx" -) - -// ContractArgs are the params used for calling a smart contract. -type ContractArgs struct { - // Addr is the address of the contract to call. - Addr common.Address - // ABI is the ABI of the contract to call. - ABI abi.ABI - // MethodName is the name of the method to call. - MethodName string - // Args are the arguments to pass to the method. - Args []interface{} -} - -// ContractCallArgs is the arguments for calling a smart contract. -type ContractCallArgs struct { - // Contract are the contract-specific arguments required for the contract call. - Contract ContractArgs - // Nonce is the nonce to use for the transaction. - Nonce *big.Int - // Amount is the amount of the native denomination to send in the transaction. - Amount *big.Int - // GasLimit to use for the transaction - GasLimit uint64 - // PrivKey is the private key to be used for the transaction. - PrivKey cryptotypes.PrivKey -} - -// DeployContract deploys a contract with the provided private key, -// compiled contract data and constructor arguments -func DeployContract( - ctx sdk.Context, - app *exampleapp.ExampleChain, - priv cryptotypes.PrivKey, - queryClientEvm evm.QueryClient, - contract evm.CompiledContract, - constructorArgs ...interface{}, -) (common.Address, error) { - chainID := evmtypes.GetEthChainConfig().ChainID - from := common.BytesToAddress(priv.PubKey().Address().Bytes()) - nonce := app.EVMKeeper.GetNonce(ctx, from) - - ctorArgs, err := contract.ABI.Pack("", constructorArgs...) - if err != nil { - return common.Address{}, err - } - - data := append(contract.Bin, ctorArgs...) //nolint:gocritic - gas, err := tx.GasLimit(ctx, from, data, queryClientEvm) - if err != nil { - return common.Address{}, err - } - - baseFeeRes, err := queryClientEvm.BaseFee(ctx, &evmtypes.QueryBaseFeeRequest{}) - if err != nil { - return common.Address{}, err - } - - msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{ - ChainID: chainID, - Nonce: nonce, - GasLimit: gas, - GasFeeCap: baseFeeRes.BaseFee.BigInt(), - GasTipCap: big.NewInt(1), - Input: data, - Accesses: ðtypes.AccessList{}, - }) - msgEthereumTx.From = from.String() - - res, err := DeliverEthTx(app, priv, msgEthereumTx) - if err != nil { - return common.Address{}, err - } - - if _, err := CheckEthTxResponse(res, app.AppCodec()); err != nil { - return common.Address{}, err - } - - return crypto.CreateAddress(from, nonce), nil -} - -// DeployContractWithFactory deploys a contract using a contract factory -// with the provided factoryAddress -func DeployContractWithFactory( - ctx sdk.Context, - exampleApp *exampleapp.ExampleChain, - priv cryptotypes.PrivKey, - factoryAddress common.Address, -) (common.Address, abci.ExecTxResult, error) { - chainID := evmtypes.GetEthChainConfig().ChainID - from := common.BytesToAddress(priv.PubKey().Address().Bytes()) - factoryNonce := exampleApp.EVMKeeper.GetNonce(ctx, factoryAddress) - nonce := exampleApp.EVMKeeper.GetNonce(ctx, from) - - msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{ - ChainID: chainID, - Nonce: nonce, - To: &factoryAddress, - GasLimit: uint64(100000), - GasPrice: big.NewInt(1000000000), - }) - msgEthereumTx.From = from.String() - - res, err := DeliverEthTx(exampleApp, priv, msgEthereumTx) - if err != nil { - return common.Address{}, abci.ExecTxResult{}, err - } - - if _, err := CheckEthTxResponse(res, exampleApp.AppCodec()); err != nil { - return common.Address{}, abci.ExecTxResult{}, err - } - - return crypto.CreateAddress(factoryAddress, factoryNonce), res, err -} - -// CheckEthTxResponse checks that the transaction was executed successfully -func CheckEthTxResponse(r abci.ExecTxResult, cdc codec.Codec) ([]*evm.MsgEthereumTxResponse, error) { - if !r.IsOK() { - return nil, fmt.Errorf("tx failed. Code: %d, Logs: %s", r.Code, r.Log) - } - - var txData sdk.TxMsgData - if err := cdc.Unmarshal(r.Data, &txData); err != nil { - return nil, err - } - - if len(txData.MsgResponses) == 0 { - return nil, fmt.Errorf("no message responses found") - } - - responses := make([]*evm.MsgEthereumTxResponse, 0, len(txData.MsgResponses)) - for i := range txData.MsgResponses { - var res evm.MsgEthereumTxResponse - if err := proto.Unmarshal(txData.MsgResponses[i].Value, &res); err != nil { - return nil, err - } - - if res.Failed() { - return nil, fmt.Errorf("tx failed. VmError: %s", res.VmError) - } - responses = append(responses, &res) - } - - return responses, nil -} diff --git a/example_chain/testutil/eth_setup.go b/example_chain/testutil/eth_setup.go deleted file mode 100644 index a8d00f15..00000000 --- a/example_chain/testutil/eth_setup.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "encoding/json" - "time" - - evmostypes "github.com/evmos/os/types" - - "cosmossdk.io/log" - "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - cmtypes "github.com/cometbft/cometbft/types" - dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/testutil/mock" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - exampleapp "github.com/realiotech/realio-network/example_chain" -) - -// DefaultConsensusParams defines the default Tendermint consensus params used in -// Evmos testing. -var DefaultConsensusParams = &tmproto.ConsensusParams{ - Block: &tmproto.BlockParams{ - MaxBytes: 200000, - MaxGas: -1, // no limit - }, - Evidence: &tmproto.EvidenceParams{ - MaxAgeNumBlocks: 302400, - MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration - MaxBytes: 10000, - }, - Validator: &tmproto.ValidatorParams{ - PubKeyTypes: []string{ - cmtypes.ABCIPubKeyTypeEd25519, - }, - }, -} - -// EthDefaultConsensusParams defines the default Tendermint consensus params used in -// evmOS app testing. -// -// TODO: currently not used -var EthDefaultConsensusParams = &cmtypes.ConsensusParams{ - Block: cmtypes.BlockParams{ - MaxBytes: 200000, - MaxGas: -1, // no limit - }, - Evidence: cmtypes.EvidenceParams{ - MaxAgeNumBlocks: 302400, - MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration - MaxBytes: 10000, - }, - Validator: cmtypes.ValidatorParams{ - PubKeyTypes: []string{ - cmtypes.ABCIPubKeyTypeEd25519, - }, - }, -} - -// EthSetup initializes a new evmOS application. A Nop logger is set in ExampleChain. -func EthSetup(isCheckTx bool, chainID string, patchGenesis func(*exampleapp.ExampleChain, evmostypes.GenesisState) evmostypes.GenesisState) *exampleapp.ExampleChain { - return EthSetupWithDB(isCheckTx, chainID, patchGenesis, dbm.NewMemDB()) -} - -// EthSetupWithDB initializes a new ExampleChain. A Nop logger is set in ExampleChain. -func EthSetupWithDB(isCheckTx bool, chainID string, patchGenesis func(*exampleapp.ExampleChain, evmostypes.GenesisState) evmostypes.GenesisState, db dbm.DB) *exampleapp.ExampleChain { - app := exampleapp.NewExampleApp(log.NewNopLogger(), - db, - nil, - true, - simtestutil.NewAppOptionsWithFlagHome(exampleapp.DefaultNodeHome), - exampleapp.EvmosAppOptions, - baseapp.SetChainID(chainID), - ) - if !isCheckTx { - // init chain must be called to stop deliverState from being nil - genesisState := NewTestGenesisState(app) - if patchGenesis != nil { - genesisState = patchGenesis(app, genesisState) - } - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - - // Initialize the chain - app.InitChain( - &abci.RequestInitChain{ - ChainId: chainID, - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - } - - return app -} - -// NewTestGenesisState generate genesis state with single validator -// -// It is also setting up the EVM parameters to use sensible defaults. -// -// TODO: are these different genesis functions necessary or can they all be refactored into one? -// there's also other genesis state functions; some like app.DefaultGenesis() or others in test helpers only. -func NewTestGenesisState(app *exampleapp.ExampleChain) evmostypes.GenesisState { - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - if err != nil { - panic(err) - } - // create validator set with single validator - validator := cmtypes.NewValidator(pubKey, 1) - valSet := cmtypes.NewValidatorSet([]*cmtypes.Validator{validator}) - - // generate genesis account - senderPrivKey := secp256k1.GenPrivKey() - acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) - balance := banktypes.Balance{ - Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000000000000))), - } - - genesisState := app.DefaultGenesis() - return genesisStateWithValSet(app.AppCodec(), genesisState, valSet, []authtypes.GenesisAccount{acc}, balance) -} - -func genesisStateWithValSet(codec codec.Codec, genesisState evmostypes.GenesisState, - valSet *cmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, - balances ...banktypes.Balance, -) evmostypes.GenesisState { - // set genesis accounts - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) - genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) - - validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) - delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - - bondAmt := sdk.DefaultPowerReduction - - for _, val := range valSet.Validators { - pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) - if err != nil { - panic(err) - } - pkAny, err := codectypes.NewAnyWithValue(pk) - if err != nil { - panic(err) - } - validator := stakingtypes.Validator{ - OperatorAddress: sdk.ValAddress(val.Address).String(), - ConsensusPubkey: pkAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: bondAmt, - DelegatorShares: math.LegacyOneDec(), - Description: stakingtypes.Description{}, - UnbondingHeight: int64(0), - UnbondingTime: time.Unix(0, 0).UTC(), - Commission: stakingtypes.NewCommission(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec()), - MinSelfDelegation: math.ZeroInt(), - } - validators = append(validators, validator) - delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress().String(), val.Address.String(), math.LegacyOneDec())) - } - // set validators and delegations - stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) - genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis) - - totalSupply := sdk.NewCoins() - for _, b := range balances { - // add genesis acc tokens to total supply - totalSupply = totalSupply.Add(b.Coins...) - } - - for range delegations { - // add delegated tokens to total supply - totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)) - } - - // add bonded amount to bonded pool module account - balances = append(balances, banktypes.Balance{ - Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, - }) - - // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}, []banktypes.SendEnabled{}) - genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) - - return genesisState -} diff --git a/example_chain/testutil/fund.go b/example_chain/testutil/fund.go deleted file mode 100644 index d0efaba9..00000000 --- a/example_chain/testutil/fund.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - "github.com/evmos/os/testutil/constants" -) - -// FundAccount is a utility function that funds an account by minting and -// sending the coins to the address. -func FundAccount(ctx sdk.Context, bankKeeper bankkeeper.Keeper, addr sdk.AccAddress, amounts sdk.Coins) error { - if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { - return err - } - - return bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) -} - -// FundAccountWithBaseDenom is a utility function that uses the FundAccount function -// to fund an account with the default denomination. -// -// TODO: as per Freddy these methods should be replaced with a bank transfer from a main account, not by minting in the process -func FundAccountWithBaseDenom(ctx sdk.Context, bankKeeper bankkeeper.Keeper, addr sdk.AccAddress, amount int64) error { - coins := sdk.NewCoins( - sdk.NewCoin(constants.ExampleAttoDenom, math.NewInt(amount)), - ) - return FundAccount(ctx, bankKeeper, addr, coins) -} - -// FundModuleAccount is a utility function that funds a module account by -// minting and sending the coins to the address. -func FundModuleAccount(ctx sdk.Context, bankKeeper bankkeeper.Keeper, recipientMod string, amounts sdk.Coins) error { - if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { - return err - } - - return bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, recipientMod, amounts) -} diff --git a/example_chain/testutil/gas.go b/example_chain/testutil/gas.go deleted file mode 100644 index 5410c448..00000000 --- a/example_chain/testutil/gas.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "cosmossdk.io/math" -) - -var ( - // ExampleMinGasPrices defines 20B related to atto units as the minimum gas price value on the fee market module. - // See https://commonwealth.im/evmos/discussion/5073-global-min-gas-price-value-for-cosmos-sdk-and-evm-transaction-choosing-a-value for reference - ExampleMinGasPrices = math.LegacyNewDec(20_000_000_000) - - // ExampleMinGasMultiplier defines the min gas multiplier value on the fee market module. - // 50% of the leftover gas will be refunded - ExampleMinGasMultiplier = math.LegacyNewDecWithPrec(5, 1) -) diff --git a/example_chain/testutil/integration.go b/example_chain/testutil/integration.go deleted file mode 100644 index 33f2e15c..00000000 --- a/example_chain/testutil/integration.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package testutil - -import ( - "strconv" - - errorsmod "cosmossdk.io/errors" - "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" - govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/evmos/os/crypto/ethsecp256k1" - exampleapp "github.com/realiotech/realio-network/example_chain" -) - -// SubmitProposal delivers a submit proposal tx for a given gov content. -// Depending on the content type, the eventNum needs to specify submit_proposal -// event. -func SubmitProposal( - ctx sdk.Context, - appEvmos *exampleapp.ExampleChain, - pk *ethsecp256k1.PrivKey, - content govv1beta1.Content, - eventNum int, -) (id uint64, err error) { - accountAddress := sdk.AccAddress(pk.PubKey().Address().Bytes()) - stakeDenom := stakingtypes.DefaultParams().BondDenom - - deposit := sdk.NewCoins(sdk.NewCoin(stakeDenom, math.NewInt(100000000))) - msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, accountAddress) - if err != nil { - return id, err - } - res, err := DeliverTx(ctx, appEvmos, pk, nil, msg) - if err != nil { - return id, err - } - - submitEvent := res.GetEvents()[eventNum] - if submitEvent.Type != "submit_proposal" || submitEvent.Attributes[0].Key != "proposal_id" { - return id, errorsmod.Wrapf(errorsmod.Error{}, "eventNumber %d in SubmitProposal calls %s instead of submit_proposal", eventNum, submitEvent.Type) - } - - return strconv.ParseUint(submitEvent.Attributes[0].Value, 10, 64) -} - -// Delegate delivers a delegate tx -func Delegate( - ctx sdk.Context, - appEvmos *exampleapp.ExampleChain, - priv *ethsecp256k1.PrivKey, - delegateAmount sdk.Coin, - validator stakingtypes.Validator, -) (abci.ExecTxResult, error) { - accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes()) - - val, err := sdk.ValAddressFromBech32(validator.OperatorAddress) - if err != nil { - return abci.ExecTxResult{}, err - } - - delegateMsg := stakingtypes.NewMsgDelegate(accountAddress.String(), val.String(), delegateAmount) - return DeliverTx(ctx, appEvmos, priv, nil, delegateMsg) -} - -// Vote delivers a vote tx with the VoteOption "yes" -func Vote( - ctx sdk.Context, - appEvmos *exampleapp.ExampleChain, - priv *ethsecp256k1.PrivKey, - proposalID uint64, - voteOption govv1beta1.VoteOption, -) (abci.ExecTxResult, error) { - accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes()) - - voteMsg := govv1beta1.NewMsgVote(accountAddress, proposalID, voteOption) - return DeliverTx(ctx, appEvmos, priv, nil, voteMsg) -} diff --git a/testutil/integration/os/network/network.go b/testutil/integration/os/network/network.go index 5ea49b17..5ad88585 100644 --- a/testutil/integration/os/network/network.go +++ b/testutil/integration/os/network/network.go @@ -23,7 +23,7 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" gethparams "github.com/ethereum/go-ethereum/params" - chainutil "github.com/realiotech/realio-network/example_chain/testutil" + chainutil "github.com/evmos/os/example_chain/testutil" commonnetwork "github.com/evmos/os/testutil/integration/common/network" "github.com/evmos/os/types" erc20types "github.com/evmos/os/x/erc20/types" From 1b6c0ce57e522b91af43357b18fec6745655dd2d Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 10 Feb 2025 13:16:38 +0700 Subject: [PATCH 49/53] test transfer with freeze --- precompiles/erc20/tx.go | 6 ------ precompiles/erc20/tx_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index 72d082d5..dcd94d09 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -277,12 +277,6 @@ func (p *Precompile) burn( return nil, fmt.Errorf("sender is not token manager") } - // Check if from is freezed - freezed := p.assetKeep.IsFreezed(ctx, from) - if freezed { - return nil, fmt.Errorf("address %s already be freezed", from.String()) - } - burnFromAddr := sdk.AccAddress(from.Bytes()) coins := sdk.Coins{{Denom: p.denom, Amount: math.NewIntFromBigInt(amount)}} diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go index 8a9b87e4..f9a3e056 100644 --- a/precompiles/erc20/tx_test.go +++ b/precompiles/erc20/tx_test.go @@ -115,7 +115,7 @@ func (s *PrecompileTestSuite) TestTransfer() { } func (s *PrecompileTestSuite) TestTransferFrom() { - var ( + var ( ctx sdk.Context stDB *statedb.StateDB ) @@ -177,6 +177,17 @@ func (s *PrecompileTestSuite) TestTransferFrom() { true, ErrInsufficientAllowance.Error(), }, + { + "fail - owner was freezed", + func() []interface{} { + err := s.network.App.AssetKeeper.SetFreezeAddress(ctx, owner.Addr) + s.Require().NoError(err) + return []interface{}{owner.Addr, toAddr, big.NewInt(100)} + }, + func() {}, + true, + "already be freezed", + }, { "fail - not enough balance", func() []interface{} { @@ -218,6 +229,28 @@ func (s *PrecompileTestSuite) TestTransferFrom() { false, "", }, + { + "fail - spend on behalf of freezed account", + func() []interface{} { + expiration := time.Now().Add(time.Hour) + err := s.network.App.AuthzKeeper.SaveGrant( + ctx, + spender.AccAddr, + owner.AccAddr, + &banktypes.SendAuthorization{SpendLimit: sdk.Coins{sdk.Coin{Denom: tokenDenom, Amount: math.NewInt(300)}}}, + &expiration, + ) + s.Require().NoError(err, "failed to save grant") + + err = s.network.App.AssetKeeper.SetFreezeAddress(ctx, owner.Addr) + s.Require().NoError(err) + + return []interface{}{owner.Addr, toAddr, big.NewInt(100)} + }, + func() {}, + true, + "already be freezed", + }, { "pass - spend on behalf of own account", func() []interface{} { From c6c86fa6237c92bf9d4d1d20cfa17d960ded7275 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 10 Feb 2025 13:16:47 +0700 Subject: [PATCH 50/53] no need --- example_chain/activators.go | 16 ----- example_chain/config_testing.go | 100 -------------------------------- 2 files changed, 116 deletions(-) delete mode 100644 example_chain/activators.go delete mode 100644 example_chain/config_testing.go diff --git a/example_chain/activators.go b/example_chain/activators.go deleted file mode 100644 index fbcff013..00000000 --- a/example_chain/activators.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) -package example_chain - -import ( - "github.com/evmos/os/x/evm/core/vm" - "github.com/evmos/os/example_chain/eips" -) - -// evmosActivators defines a map of opcode modifiers associated -// with a key defining the corresponding EIP. -var evmosActivators = map[string]func(*vm.JumpTable){ - "evmos_0": eips.Enable0000, - "evmos_1": eips.Enable0001, - "evmos_2": eips.Enable0002, -} diff --git a/example_chain/config_testing.go b/example_chain/config_testing.go deleted file mode 100644 index 20ff9faf..00000000 --- a/example_chain/config_testing.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -//go:build test -// +build test - -package example_chain - -import ( - "fmt" - "strings" - - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - testconstants "github.com/evmos/os/testutil/constants" - evmtypes "github.com/evmos/os/x/evm/types" -) - -// ChainsCoinInfo is a map of the chain id and its corresponding EvmCoinInfo -// that allows initializing the app with different coin info based on the -// chain id -var ChainsCoinInfo = map[string]evmtypes.EvmCoinInfo{ - EighteenDecimalsChainID: { - Denom: ExampleChainDenom, - DisplayDenom: ExampleChainDenom, - Decimals: evmtypes.EighteenDecimals, - }, - SixDecimalsChainID: { - Denom: testconstants.ExampleMicroDenom, - DisplayDenom: testconstants.ExampleDisplayDenom, - Decimals: evmtypes.SixDecimals, - }, -} - -// EvmosOptionsFn defines a function type for setting app options specifically for -// the Evmos app. The function should receive the chainID and return an error if -// any. -type EvmosOptionsFn func(string) error - -// NoOpEvmosOptions is a no-op function that can be used when the app does not -// need any specific configuration. -func NoOpEvmosOptions(_ string) error { - return nil -} - -// EvmosAppOptions allows to setup the global configuration -// for the Evmos chain. -func EvmosAppOptions(chainID string) error { - // Split the revision height from the given chain ID - id := strings.Split(chainID, "-")[0] - coinInfo, found := ChainsCoinInfo[id] - if !found { - return fmt.Errorf("unknown chain id: %s", id) - } - - // set the base denom considering if its mainnet or testnet - if err := setBaseDenom(coinInfo); err != nil { - return err - } - - baseDenom, err := sdk.GetBaseDenom() - if err != nil { - return err - } - - ethCfg := evmtypes.DefaultChainConfig(chainID) - - configurator := evmtypes.NewEVMConfigurator() - // reset configuration to set the new one - configurator.ResetTestConfig() - err = configurator. - WithExtendedEips(evmosActivators). - WithChainConfig(ethCfg). - WithEVMCoinInfo(baseDenom, uint8(coinInfo.Decimals)). - Configure() - if err != nil { - return err - } - - return nil -} - -// setBaseDenom registers the display denom and base denom and sets the -// base denom for the chain. The function registered different values based on -// the EvmCoinInfo to allow different configurations in mainnet and testnet. -func setBaseDenom(ci evmtypes.EvmCoinInfo) (err error) { - // Defer setting the base denom, and capture any potential error from it. - // So when failing because the denom was already registered, we ignore it and set - // the corresponding denom to be base denom - defer func() { - err = sdk.SetBaseDenom(ci.Denom) - }() - if err := sdk.RegisterDenom(ci.DisplayDenom, math.LegacyOneDec()); err != nil { - return err - } - - // sdk.RegisterDenom will automatically overwrite the base denom when the - // new setBaseDenom() units are lower than the current base denom's units. - return sdk.RegisterDenom(ci.Denom, math.LegacyNewDecWithPrec(1, int64(ci.Decimals))) -} From 6b39b76b9f1e78d09531fb4ac3bcf2292927c303 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Mon, 10 Feb 2025 13:42:13 +0700 Subject: [PATCH 51/53] remove distributor --- proto/realionetwork/asset/v1/token.proto | 2 - proto/realionetwork/asset/v1/tx.proto | 3 - x/asset/types/msgs.go | 27 +-- x/asset/types/token.pb.go | 72 +++---- x/asset/types/tx.pb.go | 262 +++++------------------ 5 files changed, 83 insertions(+), 283 deletions(-) diff --git a/proto/realionetwork/asset/v1/token.proto b/proto/realionetwork/asset/v1/token.proto index 0e789be8..f7479397 100644 --- a/proto/realionetwork/asset/v1/token.proto +++ b/proto/realionetwork/asset/v1/token.proto @@ -39,6 +39,4 @@ enum Role { ROLE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "EmptyRole"]; // ROLE_MANAGER defines a token manager role. ROLE_MANAGER = 1 [(gogoproto.enumvalue_customname) = "ManagerRole"]; - // ROLE_DISTRIBUTOR defines a token distributor role. - ROLE_DISTRIBUTOR = 2 [(gogoproto.enumvalue_customname) = "DistributorRole"]; } \ No newline at end of file diff --git a/proto/realionetwork/asset/v1/tx.proto b/proto/realionetwork/asset/v1/tx.proto index 99e455e5..2c7111d7 100644 --- a/proto/realionetwork/asset/v1/tx.proto +++ b/proto/realionetwork/asset/v1/tx.proto @@ -29,7 +29,6 @@ message MsgCreateToken { string symbol = 4; string description = 5; repeated string managers = 6; - repeated string distributors = 7; bool allow_new_extensions = 8; repeated string extensions_list = 9; string max_supply = 10 [ @@ -49,7 +48,6 @@ message MsgAssignRoles { string token_id = 2; repeated string managers = 3; - repeated string distributors = 4; } message MsgAssignRolesResponse {} @@ -61,7 +59,6 @@ message MsgUnassignRoles { string token_id = 2; repeated string managers = 3; - repeated string distributors = 4; } message MsgUnassignRolesResponse {} diff --git a/x/asset/types/msgs.go b/x/asset/types/msgs.go index b1ee9b2e..6dfdfe15 100644 --- a/x/asset/types/msgs.go +++ b/x/asset/types/msgs.go @@ -16,7 +16,6 @@ func NewMsgCreateToken(issuer string, name string, symbol string, description st Description: description, Decimal: decimal, Managers: managers, - Distributors: distributors, ExtensionsList: extensionsList, AllowNewExtensions: allowNewExtensions, } @@ -34,21 +33,14 @@ func (msg *MsgCreateToken) ValidateBasic() error { } } - for _, distributor := range msg.Distributors { - _, err := sdk.AccAddressFromBech32(distributor) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) - } - } return nil } -func NewMsgAssignRoles(issuer string, tokenId string, managers []string, distributors []string) *MsgAssignRoles { +func NewMsgAssignRoles(issuer string, tokenId string, managers []string) *MsgAssignRoles { return &MsgAssignRoles{ Issuer: issuer, TokenId: tokenId, Managers: managers, - Distributors: distributors, } } @@ -65,22 +57,14 @@ func (msg *MsgAssignRoles) ValidateBasic() error { } } - for _, distributor := range msg.Distributors { - _, err := sdk.AccAddressFromBech32(distributor) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) - } - } - return ValidateTokenId(msg.TokenId) } -func NewMsgUnassignRoles(issuer string, tokenId string, managers []string, distributors []string) *MsgUnassignRoles { +func NewMsgUnassignRoles(issuer string, tokenId string, managers []string) *MsgUnassignRoles { return &MsgUnassignRoles{ Issuer: issuer, TokenId: tokenId, Managers: managers, - Distributors: distributors, } } @@ -97,12 +81,5 @@ func (msg *MsgUnassignRoles) ValidateBasic() error { } } - for _, distributor := range msg.Distributors { - _, err := sdk.AccAddressFromBech32(distributor) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid distributor address (%s): %s", distributor, err) - } - } - return ValidateTokenId(msg.TokenId) } diff --git a/x/asset/types/token.pb.go b/x/asset/types/token.pb.go index 4dd52904..7fa98f8d 100644 --- a/x/asset/types/token.pb.go +++ b/x/asset/types/token.pb.go @@ -31,20 +31,16 @@ const ( EmptyRole Role = 0 // ROLE_MANAGER defines a token manager role. ManagerRole Role = 1 - // ROLE_DISTRIBUTOR defines a token distributor role. - DistributorRole Role = 2 ) var Role_name = map[int32]string{ 0: "ROLE_UNSPECIFIED", 1: "ROLE_MANAGER", - 2: "ROLE_DISTRIBUTOR", } var Role_value = map[string]int32{ "ROLE_UNSPECIFIED": 0, "ROLE_MANAGER": 1, - "ROLE_DISTRIBUTOR": 2, } func (x Role) String() string { @@ -274,41 +270,39 @@ func init() { } var fileDescriptor_2f83138fc60a3176 = []byte{ - // 540 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xcf, 0x6e, 0xd3, 0x4c, - 0x14, 0xc5, 0xed, 0x36, 0x4d, 0x93, 0x49, 0xfb, 0x25, 0x9a, 0xaf, 0x54, 0xc6, 0x12, 0x8e, 0x09, - 0x0b, 0x02, 0x12, 0x36, 0x85, 0x2d, 0x9b, 0x84, 0x18, 0x64, 0x29, 0x4d, 0x2b, 0x27, 0xdd, 0xb0, - 0xb1, 0x26, 0xf1, 0x28, 0x19, 0xc5, 0xe3, 0xb1, 0x3c, 0x93, 0x7f, 0x2b, 0xb6, 0x28, 0x2b, 0x5e, - 0x20, 0x2b, 0x1e, 0x05, 0x09, 0x75, 0xd9, 0x25, 0x62, 0x51, 0xa1, 0xe4, 0x45, 0x50, 0xc6, 0x6e, - 0x0a, 0xdd, 0xdd, 0x73, 0xef, 0x6f, 0xae, 0x74, 0xee, 0x1c, 0x50, 0x4b, 0x30, 0x0a, 0x09, 0x8b, - 0xb0, 0x98, 0xb1, 0x64, 0x6c, 0x23, 0xce, 0xb1, 0xb0, 0xa7, 0x67, 0xb6, 0x60, 0x63, 0x1c, 0x59, - 0x71, 0xc2, 0x04, 0x83, 0xa7, 0xff, 0x30, 0x96, 0x64, 0xac, 0xe9, 0x99, 0x7e, 0x32, 0x64, 0x43, - 0x26, 0x11, 0x7b, 0x5b, 0xa5, 0x74, 0xed, 0xbb, 0x0a, 0x0e, 0x7a, 0xdb, 0xd7, 0xf0, 0x31, 0x28, - 0xc8, 0x35, 0x3e, 0x09, 0x34, 0xd5, 0x54, 0xeb, 0x45, 0xef, 0x50, 0x6a, 0x37, 0x80, 0xa7, 0x20, - 0x4f, 0x38, 0x9f, 0xe0, 0x44, 0xdb, 0x93, 0x83, 0x4c, 0x41, 0x08, 0x72, 0x11, 0xa2, 0x58, 0xdb, - 0x97, 0x5d, 0x59, 0x6f, 0x59, 0xbe, 0xa0, 0x7d, 0x16, 0x6a, 0xb9, 0x94, 0x4d, 0x15, 0xd4, 0xc0, - 0x61, 0x80, 0x07, 0x84, 0xa2, 0x50, 0x3b, 0x30, 0xd5, 0xfa, 0xb1, 0x77, 0x27, 0xa1, 0x09, 0x4a, - 0x01, 0xe6, 0x83, 0x84, 0xc4, 0x82, 0xb0, 0x48, 0xcb, 0xcb, 0x67, 0x7f, 0xb7, 0x60, 0x15, 0x94, - 0xf0, 0x94, 0xfa, 0x28, 0x08, 0x12, 0xcc, 0xb9, 0x56, 0x94, 0x04, 0xc0, 0x53, 0xda, 0x48, 0x3b, - 0xb5, 0x1f, 0x2a, 0x28, 0x4b, 0x17, 0xe7, 0x28, 0x42, 0x43, 0x4c, 0x71, 0x24, 0xa0, 0x0e, 0x0a, - 0x54, 0xaa, 0x84, 0x6b, 0xaa, 0xb9, 0x5f, 0x2f, 0x7a, 0x3b, 0x0d, 0x5f, 0x83, 0x13, 0x14, 0x86, - 0x6c, 0xe6, 0x47, 0x78, 0xe6, 0xe3, 0xb9, 0xc0, 0x11, 0x27, 0x2c, 0xe2, 0xd2, 0x5e, 0xc1, 0x83, - 0x72, 0xd6, 0xc1, 0x33, 0x67, 0x37, 0x81, 0xcf, 0x41, 0xf9, 0x9e, 0xf3, 0x43, 0xc2, 0x85, 0xb6, - 0x2f, 0x97, 0xfe, 0x77, 0xdf, 0x6e, 0x13, 0x2e, 0xe0, 0x3b, 0x00, 0x28, 0x9a, 0xfb, 0x7c, 0x12, - 0xc7, 0xe1, 0x22, 0xbd, 0x41, 0xf3, 0xc9, 0xf5, 0x6d, 0x55, 0xf9, 0x75, 0x5b, 0x7d, 0x34, 0x60, - 0x9c, 0x32, 0xce, 0x83, 0xb1, 0x45, 0x98, 0x4d, 0x91, 0x18, 0x59, 0x6e, 0x24, 0xbc, 0x22, 0x45, - 0xf3, 0xae, 0xe4, 0x6b, 0x97, 0xe0, 0xa8, 0x3b, 0x42, 0x09, 0xce, 0x8c, 0x3d, 0x74, 0xae, 0x3e, - 0x74, 0xbe, 0x05, 0x78, 0x30, 0xde, 0x01, 0xe9, 0xff, 0x00, 0x1e, 0x8c, 0x33, 0xe0, 0xe5, 0x67, - 0x90, 0xf3, 0x58, 0x88, 0xe1, 0x33, 0x50, 0xf1, 0x2e, 0xda, 0x8e, 0x7f, 0xd5, 0xe9, 0x5e, 0x3a, - 0xef, 0xdd, 0x0f, 0xae, 0xd3, 0xaa, 0x28, 0xfa, 0xf1, 0x72, 0x65, 0x16, 0x1d, 0x1a, 0x8b, 0x85, - 0x84, 0x9e, 0x82, 0x23, 0x09, 0x9d, 0x37, 0x3a, 0x8d, 0x8f, 0x8e, 0x57, 0x51, 0xf5, 0xf2, 0x72, - 0x65, 0x96, 0xd2, 0xab, 0x26, 0x12, 0x79, 0x91, 0xed, 0x69, 0xb9, 0xdd, 0x9e, 0xe7, 0x36, 0xaf, - 0x7a, 0x17, 0x5e, 0x65, 0x4f, 0xff, 0x7f, 0xb9, 0x32, 0xcb, 0x2d, 0xc2, 0x45, 0x42, 0xfa, 0x13, - 0xc1, 0x24, 0xaa, 0xe7, 0xbe, 0x7c, 0x33, 0x94, 0x66, 0xfb, 0x7a, 0x6d, 0xa8, 0x37, 0x6b, 0x43, - 0xfd, 0xbd, 0x36, 0xd4, 0xaf, 0x1b, 0x43, 0xb9, 0xd9, 0x18, 0xca, 0xcf, 0x8d, 0xa1, 0x7c, 0x7a, - 0x33, 0x24, 0x62, 0x34, 0xe9, 0x5b, 0x03, 0x46, 0xed, 0x34, 0xb4, 0x02, 0x0f, 0x46, 0x59, 0xf9, - 0xea, 0x2e, 0xe4, 0xf3, 0x2c, 0xe6, 0x62, 0x11, 0x63, 0xde, 0xcf, 0xcb, 0xd8, 0xbe, 0xfd, 0x13, - 0x00, 0x00, 0xff, 0xff, 0x22, 0xe2, 0x9c, 0xa3, 0x0a, 0x03, 0x00, 0x00, + // 509 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0x4f, 0x6f, 0xd3, 0x30, + 0x18, 0xc6, 0x63, 0xd6, 0x75, 0xad, 0xbb, 0xd1, 0xca, 0x1a, 0x53, 0xa8, 0x44, 0x1a, 0xca, 0x81, + 0x0a, 0x89, 0x84, 0xc1, 0x95, 0x4b, 0x07, 0x01, 0x55, 0xea, 0xca, 0x94, 0x8e, 0x0b, 0x97, 0xc8, + 0x6d, 0x5e, 0xb5, 0x56, 0xe3, 0x38, 0x8a, 0xdd, 0x7f, 0xdf, 0x00, 0xed, 0xc4, 0x17, 0xd8, 0x89, + 0x8f, 0x82, 0x84, 0x76, 0xdc, 0x11, 0x71, 0x98, 0x50, 0xfb, 0x45, 0x50, 0x9d, 0xac, 0x83, 0xdd, + 0xde, 0xe7, 0x79, 0x7f, 0xb6, 0xf4, 0xd8, 0x0f, 0x6e, 0xa6, 0x40, 0x23, 0x26, 0x62, 0x50, 0x73, + 0x91, 0x4e, 0x5c, 0x2a, 0x25, 0x28, 0x77, 0x76, 0xec, 0x2a, 0x31, 0x81, 0xd8, 0x49, 0x52, 0xa1, + 0x04, 0x39, 0xfa, 0x8f, 0x71, 0x34, 0xe3, 0xcc, 0x8e, 0xeb, 0x87, 0x23, 0x31, 0x12, 0x1a, 0x71, + 0x37, 0x53, 0x46, 0x37, 0x7f, 0x20, 0xbc, 0x7b, 0xbe, 0x39, 0x4d, 0x1e, 0xe3, 0x92, 0xbe, 0x26, + 0x60, 0xa1, 0x89, 0x6c, 0xd4, 0x2a, 0xfb, 0x7b, 0x5a, 0x77, 0x42, 0x72, 0x84, 0x8b, 0x4c, 0xca, + 0x29, 0xa4, 0xe6, 0x03, 0xbd, 0xc8, 0x15, 0x21, 0xb8, 0x10, 0x53, 0x0e, 0xe6, 0x8e, 0x76, 0xf5, + 0xbc, 0x61, 0xe5, 0x92, 0x0f, 0x44, 0x64, 0x16, 0x32, 0x36, 0x53, 0xc4, 0xc4, 0x7b, 0x21, 0x0c, + 0x19, 0xa7, 0x91, 0xb9, 0x6b, 0xa3, 0xd6, 0x81, 0x7f, 0x2b, 0x89, 0x8d, 0x2b, 0x21, 0xc8, 0x61, + 0xca, 0x12, 0xc5, 0x44, 0x6c, 0x16, 0xf5, 0xb1, 0x7f, 0x2d, 0xd2, 0xc0, 0x15, 0x98, 0xf1, 0x80, + 0x86, 0x61, 0x0a, 0x52, 0x9a, 0x65, 0x4d, 0x60, 0x98, 0xf1, 0x76, 0xe6, 0x34, 0x7f, 0x22, 0x5c, + 0xd5, 0x29, 0x4e, 0x69, 0x4c, 0x47, 0xc0, 0x21, 0x56, 0xa4, 0x8e, 0x4b, 0x5c, 0xab, 0x54, 0x9a, + 0xc8, 0xde, 0x69, 0x95, 0xfd, 0xad, 0x26, 0xaf, 0xf0, 0x21, 0x8d, 0x22, 0x31, 0x0f, 0x62, 0x98, + 0x07, 0xb0, 0x50, 0x10, 0x4b, 0x26, 0x62, 0xa9, 0xe3, 0x95, 0x7c, 0xa2, 0x77, 0x3d, 0x98, 0x7b, + 0xdb, 0x0d, 0x79, 0x8e, 0xab, 0x77, 0x5c, 0x10, 0x31, 0xa9, 0xcc, 0x1d, 0x7d, 0xe9, 0xc3, 0x3b, + 0xbb, 0xcb, 0xa4, 0x22, 0x6f, 0x31, 0xe6, 0x74, 0x11, 0xc8, 0x69, 0x92, 0x44, 0xcb, 0xec, 0x0d, + 0x4e, 0x9e, 0x5c, 0xdd, 0x34, 0x8c, 0xdf, 0x37, 0x8d, 0x47, 0x43, 0x21, 0xb9, 0x90, 0x32, 0x9c, + 0x38, 0x4c, 0xb8, 0x9c, 0xaa, 0xb1, 0xd3, 0x89, 0x95, 0x5f, 0xe6, 0x74, 0xd1, 0xd7, 0x7c, 0xf3, + 0x0c, 0xef, 0xf7, 0xc7, 0x34, 0x85, 0x3c, 0xd8, 0xfd, 0xe4, 0xe8, 0x7e, 0xf2, 0x0d, 0x20, 0xc3, + 0xc9, 0x16, 0xc8, 0xfe, 0x07, 0xcb, 0x70, 0x92, 0x03, 0x2f, 0xce, 0x71, 0xc1, 0x17, 0x11, 0x90, + 0x67, 0xb8, 0xe6, 0x7f, 0xea, 0x7a, 0xc1, 0xe7, 0x5e, 0xff, 0xcc, 0x7b, 0xd7, 0xf9, 0xd0, 0xf1, + 0xde, 0xd7, 0x8c, 0xfa, 0xc1, 0xc5, 0xa5, 0x5d, 0xf6, 0x78, 0xa2, 0x96, 0x1a, 0x7a, 0x8a, 0xf7, + 0x35, 0x74, 0xda, 0xee, 0xb5, 0x3f, 0x7a, 0x7e, 0x0d, 0xd5, 0xab, 0x17, 0x97, 0x76, 0x25, 0x7b, + 0xd5, 0x74, 0x83, 0xd4, 0x0b, 0x5f, 0xbf, 0x5b, 0xc6, 0x49, 0xf7, 0x6a, 0x65, 0xa1, 0xeb, 0x95, + 0x85, 0xfe, 0xac, 0x2c, 0xf4, 0x6d, 0x6d, 0x19, 0xd7, 0x6b, 0xcb, 0xf8, 0xb5, 0xb6, 0x8c, 0x2f, + 0xaf, 0x47, 0x4c, 0x8d, 0xa7, 0x03, 0x67, 0x28, 0xb8, 0x9b, 0x35, 0x51, 0xc1, 0x70, 0x9c, 0x8f, + 0x2f, 0x6f, 0x9b, 0xbb, 0xc8, 0xbb, 0xab, 0x96, 0x09, 0xc8, 0x41, 0x51, 0x77, 0xf1, 0xcd, 0xdf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x37, 0x0e, 0x9e, 0x07, 0xdf, 0x02, 0x00, 0x00, } func (m *Token) Marshal() (dAtA []byte, err error) { diff --git a/x/asset/types/tx.pb.go b/x/asset/types/tx.pb.go index 618241d3..751ecea0 100644 --- a/x/asset/types/tx.pb.go +++ b/x/asset/types/tx.pb.go @@ -39,7 +39,6 @@ type MsgCreateToken struct { Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` Managers []string `protobuf:"bytes,6,rep,name=managers,proto3" json:"managers,omitempty"` - Distributors []string `protobuf:"bytes,7,rep,name=distributors,proto3" json:"distributors,omitempty"` AllowNewExtensions bool `protobuf:"varint,8,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` ExtensionsList []string `protobuf:"bytes,9,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,10,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` @@ -120,13 +119,6 @@ func (m *MsgCreateToken) GetManagers() []string { return nil } -func (m *MsgCreateToken) GetDistributors() []string { - if m != nil { - return m.Distributors - } - return nil -} - func (m *MsgCreateToken) GetAllowNewExtensions() bool { if m != nil { return m.AllowNewExtensions @@ -187,10 +179,9 @@ func (m *MsgCreateTokenResponse) GetTokenId() string { type MsgAssignRoles struct { // issuer is the address that defines the token - Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` - TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` - Distributors []string `protobuf:"bytes,4,rep,name=distributors,proto3" json:"distributors,omitempty"` + Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` } func (m *MsgAssignRoles) Reset() { *m = MsgAssignRoles{} } @@ -247,13 +238,6 @@ func (m *MsgAssignRoles) GetManagers() []string { return nil } -func (m *MsgAssignRoles) GetDistributors() []string { - if m != nil { - return m.Distributors - } - return nil -} - type MsgAssignRolesResponse struct { } @@ -292,10 +276,9 @@ var xxx_messageInfo_MsgAssignRolesResponse proto.InternalMessageInfo type MsgUnassignRoles struct { // issuer is the address that defines the token - Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` - TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` - Distributors []string `protobuf:"bytes,4,rep,name=distributors,proto3" json:"distributors,omitempty"` + Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` } func (m *MsgUnassignRoles) Reset() { *m = MsgUnassignRoles{} } @@ -352,13 +335,6 @@ func (m *MsgUnassignRoles) GetManagers() []string { return nil } -func (m *MsgUnassignRoles) GetDistributors() []string { - if m != nil { - return m.Distributors - } - return nil -} - type MsgUnassignRolesResponse struct { } @@ -502,49 +478,48 @@ func init() { func init() { proto.RegisterFile("realionetwork/asset/v1/tx.proto", fileDescriptor_1cfda60866e68e13) } var fileDescriptor_1cfda60866e68e13 = []byte{ - // 672 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcd, 0x4e, 0xdb, 0x4c, - 0x14, 0x8d, 0x49, 0x08, 0xc9, 0x84, 0x9f, 0x4f, 0x23, 0x3e, 0x30, 0x56, 0x6b, 0x22, 0x57, 0x2a, - 0x11, 0x52, 0x6d, 0x7e, 0x76, 0x88, 0x4d, 0xa9, 0xba, 0x40, 0x82, 0xaa, 0x72, 0xdb, 0x4d, 0x37, - 0xd1, 0x24, 0x1e, 0x39, 0xa3, 0xd8, 0x1e, 0xcb, 0x77, 0x42, 0x92, 0x45, 0xa5, 0xaa, 0x4f, 0x80, - 0xfa, 0x24, 0xf4, 0x2d, 0x58, 0xb2, 0xac, 0xba, 0x40, 0x15, 0x2c, 0x78, 0x83, 0xae, 0x2b, 0x8f, - 0x9d, 0xc4, 0xa6, 0x24, 0x65, 0xd9, 0xdd, 0xdc, 0x7b, 0xcf, 0x9c, 0x73, 0xe6, 0xce, 0x9d, 0x41, - 0x9b, 0x11, 0x25, 0x1e, 0xe3, 0x01, 0x15, 0x7d, 0x1e, 0x75, 0x2d, 0x02, 0x40, 0x85, 0x75, 0xb6, - 0x6b, 0x89, 0x81, 0x19, 0x46, 0x5c, 0x70, 0xbc, 0x96, 0x03, 0x98, 0x12, 0x60, 0x9e, 0xed, 0x6a, - 0xab, 0x2e, 0x77, 0xb9, 0x84, 0x58, 0xf1, 0x2a, 0x41, 0x6b, 0xcf, 0xa6, 0xd0, 0x85, 0x24, 0x22, - 0x3e, 0xa4, 0x20, 0x63, 0x9a, 0x26, 0xef, 0xd2, 0x20, 0xc5, 0x6c, 0xb4, 0x39, 0xf8, 0x1c, 0x9a, - 0x89, 0x42, 0x12, 0xa4, 0xa5, 0xf5, 0x24, 0xb2, 0x7c, 0x70, 0xe3, 0x5d, 0x3e, 0xb8, 0x49, 0xc1, - 0xf8, 0x35, 0x87, 0x96, 0x4f, 0xc1, 0x7d, 0x15, 0x51, 0x22, 0xe8, 0xfb, 0x98, 0x0c, 0xaf, 0xa1, - 0x32, 0x03, 0xe8, 0xd1, 0x48, 0x55, 0xea, 0x4a, 0xa3, 0x6a, 0xa7, 0x11, 0xc6, 0xa8, 0x14, 0x10, - 0x9f, 0xaa, 0x73, 0x32, 0x2b, 0xd7, 0x58, 0x45, 0x0b, 0x0e, 0x6d, 0x33, 0x9f, 0x78, 0x6a, 0xb1, - 0xae, 0x34, 0x96, 0xec, 0x51, 0x18, 0xb3, 0xc0, 0xd0, 0x6f, 0x71, 0x4f, 0x2d, 0x25, 0x2c, 0x49, - 0x84, 0xeb, 0xa8, 0xe6, 0x50, 0x68, 0x47, 0x2c, 0x14, 0x8c, 0x07, 0xea, 0xbc, 0x2c, 0x66, 0x53, - 0x58, 0x43, 0x15, 0x9f, 0x04, 0xc4, 0xa5, 0x11, 0xa8, 0xe5, 0x7a, 0xb1, 0x51, 0xb5, 0xc7, 0x31, - 0x36, 0xd0, 0xa2, 0xc3, 0x40, 0x44, 0xac, 0xd5, 0x13, 0x3c, 0x02, 0x75, 0x41, 0xd6, 0x73, 0x39, - 0xbc, 0x83, 0x56, 0x89, 0xe7, 0xf1, 0x7e, 0x33, 0xa0, 0xfd, 0x26, 0x1d, 0x08, 0x1a, 0x00, 0xe3, - 0x01, 0xa8, 0x95, 0xba, 0xd2, 0xa8, 0xd8, 0x58, 0xd6, 0xde, 0xd0, 0xfe, 0xeb, 0x71, 0x05, 0x6f, - 0xa1, 0x95, 0x09, 0xae, 0xe9, 0x31, 0x10, 0x6a, 0x55, 0x12, 0x2f, 0x4f, 0xd2, 0x27, 0x0c, 0x04, - 0x3e, 0x44, 0xc8, 0x27, 0x83, 0x26, 0xf4, 0xc2, 0xd0, 0x1b, 0xaa, 0x28, 0xf6, 0x7e, 0xf4, 0xf4, - 0xf2, 0x7a, 0xb3, 0xf0, 0xe3, 0x7a, 0xf3, 0xff, 0xa4, 0xc5, 0xe0, 0x74, 0x4d, 0xc6, 0x2d, 0x9f, - 0x88, 0x8e, 0x79, 0x1c, 0x08, 0xbb, 0xea, 0x93, 0xc1, 0x3b, 0x89, 0x3f, 0xa8, 0x7d, 0xb9, 0xbb, - 0xd8, 0x4e, 0xbb, 0x69, 0xec, 0xa3, 0xb5, 0x7c, 0xdf, 0x6d, 0x0a, 0x21, 0x0f, 0x80, 0xe2, 0x0d, - 0x54, 0x91, 0xb7, 0xda, 0x64, 0x4e, 0x7a, 0x03, 0x0b, 0x32, 0x3e, 0x76, 0x8c, 0x73, 0x45, 0xde, - 0xd6, 0x4b, 0x00, 0xe6, 0x06, 0x36, 0xf7, 0x28, 0x4c, 0xbd, 0xad, 0x2c, 0xcb, 0x5c, 0x8e, 0x25, - 0xd7, 0xe0, 0xe2, 0x5f, 0x1a, 0x5c, 0xfa, 0xb3, 0xc1, 0xf9, 0x73, 0xa8, 0xf2, 0x1c, 0x19, 0x47, - 0xa3, 0x73, 0x18, 0x5f, 0x15, 0xf4, 0xdf, 0x29, 0xb8, 0x1f, 0x02, 0xf2, 0x0f, 0xd9, 0xd5, 0x90, - 0x7a, 0xdf, 0xd3, 0xd8, 0xf0, 0x27, 0xb4, 0x12, 0xd7, 0x42, 0x87, 0x08, 0xfa, 0x56, 0x3e, 0x3e, - 0xfc, 0x04, 0x55, 0x49, 0x4f, 0x74, 0x78, 0xc4, 0xc4, 0x30, 0x75, 0x3c, 0x49, 0xe0, 0x43, 0x54, - 0x4e, 0x1e, 0xa9, 0xb4, 0x5c, 0xdb, 0xd3, 0xcd, 0x87, 0x1f, 0xbe, 0x99, 0xb0, 0x1d, 0x95, 0xe2, - 0x51, 0xb1, 0xd3, 0x3d, 0x07, 0xcb, 0xb1, 0xaf, 0x09, 0x9b, 0xb1, 0x81, 0xd6, 0xef, 0xc9, 0x8f, - 0x9c, 0xed, 0x7d, 0x2b, 0xa2, 0xe2, 0x29, 0xb8, 0xb8, 0x83, 0x16, 0x73, 0xf6, 0xb6, 0xa6, 0x09, - 0xde, 0x23, 0xd2, 0xac, 0x47, 0x02, 0xc7, 0x43, 0x48, 0x51, 0x2d, 0xfb, 0x27, 0x3c, 0x9f, 0xb1, - 0x3f, 0x83, 0xd3, 0xcc, 0xc7, 0xe1, 0xb2, 0x32, 0xd9, 0x61, 0x9e, 0x25, 0x93, 0xc1, 0xcd, 0x94, - 0x79, 0x60, 0x14, 0x71, 0x17, 0x2d, 0xe5, 0xc7, 0xb0, 0x31, 0xab, 0x1f, 0x59, 0xa4, 0xb6, 0xf3, - 0x58, 0xe4, 0x48, 0x4c, 0x9b, 0xff, 0x7c, 0x77, 0xb1, 0xad, 0x1c, 0x9d, 0x5c, 0xde, 0xe8, 0xca, - 0xd5, 0x8d, 0xae, 0xfc, 0xbc, 0xd1, 0x95, 0xf3, 0x5b, 0xbd, 0x70, 0x75, 0xab, 0x17, 0xbe, 0xdf, - 0xea, 0x85, 0x8f, 0x7b, 0x2e, 0x13, 0x9d, 0x5e, 0xcb, 0x6c, 0x73, 0xdf, 0x4a, 0xc8, 0x05, 0x6d, - 0x77, 0xd2, 0xe5, 0x8b, 0xd1, 0x17, 0x3f, 0x48, 0x3f, 0x79, 0x31, 0x0c, 0x29, 0xb4, 0xca, 0xf2, - 0xbb, 0xde, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x50, 0x6a, 0x7b, 0x32, 0x7c, 0x06, 0x00, 0x00, + // 644 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0x4d, 0x4b, 0x1b, 0x41, + 0x18, 0xce, 0x1a, 0x8d, 0xc9, 0xa4, 0x6a, 0x19, 0xac, 0xae, 0x4b, 0xbb, 0x86, 0x14, 0x6a, 0x10, + 0xba, 0xeb, 0xc7, 0x4d, 0xbc, 0xd4, 0xd2, 0x83, 0xa0, 0xa5, 0x6c, 0xdb, 0x4b, 0x2f, 0x61, 0x4c, + 0x86, 0xcd, 0x90, 0x9d, 0x99, 0x65, 0xdf, 0x89, 0x49, 0x0e, 0x85, 0xd2, 0x5f, 0xd0, 0x9f, 0x62, + 0xff, 0x85, 0x47, 0xe9, 0xa9, 0xf4, 0x20, 0x45, 0x0f, 0xfe, 0x8d, 0xb2, 0xb3, 0x9b, 0x64, 0x57, + 0x4c, 0xf0, 0xd4, 0xdb, 0xbc, 0xf3, 0x3e, 0xf3, 0x3c, 0x0f, 0xef, 0xc7, 0xa0, 0xcd, 0x88, 0x92, + 0x80, 0x49, 0x41, 0x55, 0x5f, 0x46, 0x5d, 0x97, 0x00, 0x50, 0xe5, 0x9e, 0xef, 0xba, 0x6a, 0xe0, + 0x84, 0x91, 0x54, 0x12, 0xaf, 0xe5, 0x00, 0x8e, 0x06, 0x38, 0xe7, 0xbb, 0xd6, 0xaa, 0x2f, 0x7d, + 0xa9, 0x21, 0x6e, 0x7c, 0x4a, 0xd0, 0xd6, 0xcb, 0x29, 0x74, 0x21, 0x89, 0x08, 0x87, 0x14, 0x54, + 0x9f, 0xa6, 0x29, 0xbb, 0x54, 0xa4, 0x98, 0x8d, 0x96, 0x04, 0x2e, 0xa1, 0x99, 0x28, 0x24, 0x41, + 0x9a, 0x5a, 0x4f, 0x22, 0x97, 0x83, 0x1f, 0xbf, 0xe2, 0xe0, 0x27, 0x89, 0xfa, 0xaf, 0x39, 0xb4, + 0x7c, 0x0a, 0xfe, 0xdb, 0x88, 0x12, 0x45, 0x3f, 0xc5, 0x64, 0x78, 0x0d, 0x95, 0x18, 0x40, 0x8f, + 0x46, 0xa6, 0x51, 0x33, 0x1a, 0x15, 0x2f, 0x8d, 0x30, 0x46, 0xf3, 0x82, 0x70, 0x6a, 0xce, 0xe9, + 0x5b, 0x7d, 0xc6, 0x26, 0x5a, 0x6c, 0xd3, 0x16, 0xe3, 0x24, 0x30, 0x8b, 0x35, 0xa3, 0xb1, 0xe4, + 0x8d, 0xc2, 0x98, 0x05, 0x86, 0xfc, 0x4c, 0x06, 0xe6, 0x7c, 0xc2, 0x92, 0x44, 0xb8, 0x86, 0xaa, + 0x6d, 0x0a, 0xad, 0x88, 0x85, 0x8a, 0x49, 0x61, 0x2e, 0xe8, 0x64, 0xf6, 0x0a, 0x5b, 0xa8, 0xcc, + 0x89, 0x20, 0x3e, 0x8d, 0xc0, 0x2c, 0xd5, 0x8a, 0x8d, 0x8a, 0x37, 0x8e, 0xf1, 0x0e, 0x5a, 0x25, + 0x41, 0x20, 0xfb, 0x4d, 0x41, 0xfb, 0x4d, 0x3a, 0x50, 0x54, 0x00, 0x93, 0x02, 0xcc, 0x72, 0xcd, + 0x68, 0x94, 0x3d, 0xac, 0x73, 0xef, 0x69, 0xff, 0xdd, 0x38, 0x83, 0xb7, 0xd0, 0xca, 0x04, 0xd7, + 0x0c, 0x18, 0x28, 0xb3, 0xa2, 0x49, 0x97, 0x27, 0xd7, 0x27, 0x0c, 0x14, 0x3e, 0x44, 0x88, 0x93, + 0x41, 0x13, 0x7a, 0x61, 0x18, 0x0c, 0x4d, 0x14, 0xfb, 0x3a, 0x7a, 0x71, 0x79, 0xbd, 0x59, 0xf8, + 0x73, 0xbd, 0xf9, 0x2c, 0x29, 0x1f, 0xb4, 0xbb, 0x0e, 0x93, 0x2e, 0x27, 0xaa, 0xe3, 0x1c, 0x0b, + 0xe5, 0x55, 0x38, 0x19, 0x7c, 0xd4, 0xf8, 0x83, 0xea, 0xf7, 0xbb, 0x8b, 0xed, 0xb4, 0x52, 0xf5, + 0x7d, 0xb4, 0x96, 0xaf, 0xa9, 0x47, 0x21, 0x94, 0x02, 0x28, 0xde, 0x40, 0x65, 0xdd, 0xb1, 0x26, + 0x6b, 0xa7, 0xd5, 0x5d, 0xd4, 0xf1, 0x71, 0xbb, 0x1e, 0xe8, 0x46, 0xbc, 0x01, 0x60, 0xbe, 0xf0, + 0x64, 0x40, 0x61, 0x6a, 0x23, 0xb2, 0x24, 0x73, 0x39, 0x92, 0x5c, 0xed, 0x8a, 0xf9, 0xda, 0xe5, + 0x2d, 0x9a, 0xda, 0x62, 0x46, 0x6d, 0x64, 0xb1, 0x2e, 0xd0, 0xd3, 0x53, 0xf0, 0x3f, 0x0b, 0xf2, + 0x9f, 0x9c, 0x58, 0xc8, 0xbc, 0xaf, 0x37, 0xf6, 0xf2, 0x15, 0xad, 0xc4, 0xb9, 0xb0, 0x4d, 0x14, + 0xfd, 0xa0, 0xd7, 0x01, 0x3f, 0x47, 0x15, 0xd2, 0x53, 0x1d, 0x19, 0x31, 0x35, 0x4c, 0xdd, 0x4c, + 0x2e, 0xf0, 0x21, 0x2a, 0x25, 0x6b, 0xa3, 0xed, 0x54, 0xf7, 0x6c, 0xe7, 0xe1, 0x55, 0x74, 0x12, + 0xb6, 0xa3, 0xf9, 0xb8, 0xc1, 0x5e, 0xfa, 0xe6, 0x60, 0x39, 0xf6, 0x35, 0x61, 0xab, 0x6f, 0xa0, + 0xf5, 0x7b, 0xf2, 0x23, 0x67, 0x7b, 0x3f, 0x8b, 0xa8, 0x78, 0x0a, 0x3e, 0xee, 0xa0, 0x27, 0x39, + 0x7b, 0x5b, 0xd3, 0x04, 0xef, 0x11, 0x59, 0xee, 0x23, 0x81, 0xe3, 0xd1, 0xa1, 0xa8, 0x9a, 0xdd, + 0xd2, 0x57, 0x33, 0xde, 0x67, 0x70, 0x96, 0xf3, 0x38, 0x5c, 0x56, 0x26, 0x3b, 0x83, 0xb3, 0x64, + 0x32, 0xb8, 0x99, 0x32, 0x0f, 0x4c, 0x19, 0xee, 0xa2, 0xa5, 0xfc, 0x88, 0x35, 0x66, 0xd5, 0x23, + 0x8b, 0xb4, 0x76, 0x1e, 0x8b, 0x1c, 0x89, 0x59, 0x0b, 0xdf, 0xee, 0x2e, 0xb6, 0x8d, 0xa3, 0x93, + 0xcb, 0x1b, 0xdb, 0xb8, 0xba, 0xb1, 0x8d, 0xbf, 0x37, 0xb6, 0xf1, 0xe3, 0xd6, 0x2e, 0x5c, 0xdd, + 0xda, 0x85, 0xdf, 0xb7, 0x76, 0xe1, 0xcb, 0x9e, 0xcf, 0x54, 0xa7, 0x77, 0xe6, 0xb4, 0x24, 0x77, + 0x13, 0x72, 0x45, 0x5b, 0x9d, 0xf4, 0xf8, 0x7a, 0xf4, 0xe9, 0x0e, 0xd2, 0x6f, 0x57, 0x0d, 0x43, + 0x0a, 0x67, 0x25, 0xfd, 0x81, 0xee, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x66, 0xbc, 0x27, + 0x0e, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -786,15 +761,6 @@ func (m *MsgCreateToken) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x40 } - if len(m.Distributors) > 0 { - for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Distributors[iNdEx]) - copy(dAtA[i:], m.Distributors[iNdEx]) - i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) - i-- - dAtA[i] = 0x3a - } - } if len(m.Managers) > 0 { for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Managers[iNdEx]) @@ -890,15 +856,6 @@ func (m *MsgAssignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Distributors) > 0 { - for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Distributors[iNdEx]) - copy(dAtA[i:], m.Distributors[iNdEx]) - i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) - i-- - dAtA[i] = 0x22 - } - } if len(m.Managers) > 0 { for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Managers[iNdEx]) @@ -968,15 +925,6 @@ func (m *MsgUnassignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Distributors) > 0 { - for iNdEx := len(m.Distributors) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Distributors[iNdEx]) - copy(dAtA[i:], m.Distributors[iNdEx]) - i = encodeVarintTx(dAtA, i, uint64(len(m.Distributors[iNdEx]))) - i-- - dAtA[i] = 0x22 - } - } if len(m.Managers) > 0 { for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Managers[iNdEx]) @@ -1131,12 +1079,6 @@ func (m *MsgCreateToken) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if len(m.Distributors) > 0 { - for _, s := range m.Distributors { - l = len(s) - n += 1 + l + sovTx(uint64(l)) - } - } if m.AllowNewExtensions { n += 2 } @@ -1184,12 +1126,6 @@ func (m *MsgAssignRoles) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if len(m.Distributors) > 0 { - for _, s := range m.Distributors { - l = len(s) - n += 1 + l + sovTx(uint64(l)) - } - } return n } @@ -1222,12 +1158,6 @@ func (m *MsgUnassignRoles) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if len(m.Distributors) > 0 { - for _, s := range m.Distributors { - l = len(s) - n += 1 + l + sovTx(uint64(l)) - } - } return n } @@ -1478,38 +1408,6 @@ func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { } m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex case 8: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field AllowNewExtensions", wireType) @@ -1824,38 +1722,6 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { } m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -2052,38 +1918,6 @@ func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { } m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Distributors", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Distributors = append(m.Distributors, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 984fdc2f905aca3fef4bd7f3720fe463738fc621 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Wed, 12 Feb 2025 21:59:21 +0700 Subject: [PATCH 52/53] using addr as []byte --- precompiles/erc20/tx.go | 6 +- precompiles/erc20/tx_test.go | 8 +- precompiles/erc20/types.go | 20 ++ proto/realionetwork/asset/v1/token.proto | 9 +- proto/realionetwork/asset/v1/tx.proto | 12 +- x/asset/keeper/keeper.go | 22 +- x/asset/keeper/msg_server.go | 34 +-- x/asset/types/msgs.go | 67 +---- x/asset/types/token.go | 4 +- x/asset/types/token.pb.go | 326 ++++------------------- x/asset/types/tx.pb.go | 224 ++++++++-------- 11 files changed, 242 insertions(+), 490 deletions(-) diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index dcd94d09..40457080 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -184,7 +184,7 @@ func (p *Precompile) mint( ) (data []byte, err error) { minter := contract.CallerAddress - havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter.Bytes()) fmt.Println("have perm", havePerm, err) if err != nil || !havePerm { return nil, fmt.Errorf("sender is not token manager") @@ -272,7 +272,7 @@ func (p *Precompile) burn( ) (data []byte, err error) { minter := contract.CallerAddress - havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter) + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, minter.Bytes()) if err != nil || !havePerm { return nil, fmt.Errorf("sender is not token manager") } @@ -329,7 +329,7 @@ func (p *Precompile) freeze( ) (data []byte, err error) { sender := contract.CallerAddress - havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, sender) + havePerm, err := p.assetKeep.IsTokenManager(ctx, p.denom, sender.Bytes()) if err != nil || !havePerm { return nil, fmt.Errorf("sender is not token manager") } diff --git a/precompiles/erc20/tx_test.go b/precompiles/erc20/tx_test.go index f9a3e056..e8924a6f 100644 --- a/precompiles/erc20/tx_test.go +++ b/precompiles/erc20/tx_test.go @@ -391,7 +391,7 @@ func (s *PrecompileTestSuite) TestMint() { ctx, s.tokenDenom, assettypes.TokenManagement{ - Managers: []string{sender.AccAddr.String()}, + Managers: [][]byte{sender.AccAddr}, ExtensionsList: []string{"mint"}, MaxSupply: maxSupply, }, @@ -493,7 +493,7 @@ func (s *PrecompileTestSuite) TestBurn() { ctx, s.tokenDenom, assettypes.TokenManagement{ - Managers: []string{sender.AccAddr.String()}, + Managers: [][]byte{sender.AccAddr}, ExtensionsList: []string{"mint"}, MaxSupply: maxSupply, }, @@ -615,7 +615,7 @@ func (s *PrecompileTestSuite) TestBurnFrom() { ctx, s.tokenDenom, assettypes.TokenManagement{ - Managers: []string{sender.AccAddr.String()}, + Managers: [][]byte{sender.AccAddr}, ExtensionsList: []string{"mint"}, MaxSupply: maxSupply, }, @@ -706,7 +706,7 @@ func (s *PrecompileTestSuite) TestFreeze() { ctx, s.tokenDenom, assettypes.TokenManagement{ - Managers: []string{sender.AccAddr.String()}, + Managers: [][]byte{sender.AccAddr}, ExtensionsList: []string{"mint"}, }, ) diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index fc6d37ab..d95deafc 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -221,4 +221,24 @@ func ParseFreezeArgs(args []interface{}) ( return to, nil } +func ParseGrantRoleArgs(args []interface{}) ( + from common.Address, role int32, err error, +) { + if len(args) != 2 { + return common.Address{}, 0, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + role, ok := args[0].(int32) + if !ok { + return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) + } + + to, ok := args[0].(common.Address) + if !ok { + return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) + } + + return to, role, nil +} + diff --git a/proto/realionetwork/asset/v1/token.proto b/proto/realionetwork/asset/v1/token.proto index f7479397..31e70c1d 100644 --- a/proto/realionetwork/asset/v1/token.proto +++ b/proto/realionetwork/asset/v1/token.proto @@ -8,7 +8,7 @@ option go_package = "github.com/realiotech/realio-network/x/asset/types"; // Token represents an asset in the module message Token { string token_id = 1; - string issuer = 2; + bytes issuer = 2; string name = 3; string symbol = 4; uint32 decimal = 5; @@ -18,7 +18,7 @@ message Token { // TokenManagement represents the asset manager's execute functions. message TokenManagement { - repeated string managers = 1; + repeated bytes managers = 1; bool allow_new_extensions = 2; repeated string extensions_list = 3; string max_supply = 4 [ @@ -27,11 +27,6 @@ message TokenManagement { ]; } -message ShareAddress { - string evm_address = 1; - string sdk_address = 2; -} - enum Role { option (gogoproto.goproto_enum_prefix) = false; diff --git a/proto/realionetwork/asset/v1/tx.proto b/proto/realionetwork/asset/v1/tx.proto index 2c7111d7..67539522 100644 --- a/proto/realionetwork/asset/v1/tx.proto +++ b/proto/realionetwork/asset/v1/tx.proto @@ -22,13 +22,13 @@ service Msg { message MsgCreateToken { option (cosmos.msg.v1.signer) = "issuer"; // issuer is the address that defines the token - string issuer = 1; + bytes issuer = 1; string name = 2; uint32 decimal = 3; string symbol = 4; string description = 5; - repeated string managers = 6; + repeated bytes managers = 6; bool allow_new_extensions = 8; repeated string extensions_list = 9; string max_supply = 10 [ @@ -44,10 +44,10 @@ message MsgCreateTokenResponse { message MsgAssignRoles { option (cosmos.msg.v1.signer) = "issuer"; // issuer is the address that defines the token - string issuer = 1; + bytes issuer = 1; string token_id = 2; - repeated string managers = 3; + repeated bytes managers = 3; } message MsgAssignRolesResponse {} @@ -55,10 +55,10 @@ message MsgAssignRolesResponse {} message MsgUnassignRoles { option (cosmos.msg.v1.signer) = "issuer"; // issuer is the address that defines the token - string issuer = 1; + bytes issuer = 1; string token_id = 2; - repeated string managers = 3; + bytes managers = 3; } message MsgUnassignRolesResponse {} diff --git a/x/asset/keeper/keeper.go b/x/asset/keeper/keeper.go index ed33df9b..495c5237 100644 --- a/x/asset/keeper/keeper.go +++ b/x/asset/keeper/keeper.go @@ -30,7 +30,7 @@ type Keeper struct { Params collections.Item[types.Params] Token collections.Map[string, types.Token] TokenManagement collections.Map[string, types.TokenManagement] - WhitelistAddresses collections.Map[string, bool] + WhitelistAddresses collections.Map[[]byte, bool] FreezeAddresses collections.Map[[]byte, bool] } @@ -54,7 +54,7 @@ func NewKeeper( Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), Token: collections.NewMap(sb, types.TokenKey, "token", collections.StringKey, codec.CollValue[types.Token](cdc)), TokenManagement: collections.NewMap(sb, types.TokenManagementKey, "token_management", collections.StringKey, codec.CollValue[types.TokenManagement](cdc)), - WhitelistAddresses: collections.NewMap(sb, types.WhitelistAddressesKey, "whitelist_addresses", collections.StringKey, collections.BoolValue), + WhitelistAddresses: collections.NewMap(sb, types.WhitelistAddressesKey, "whitelist_addresses", collections.BytesKey, collections.BoolValue), FreezeAddresses: collections.NewMap(sb, types.FreezeAddressesKey, "freeze_addresses", collections.BytesKey, collections.BoolValue), } @@ -71,7 +71,7 @@ func (k Keeper) Logger(ctx context.Context) log.Logger { return sdkCtx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -func (k Keeper) GetWhitelistAddress(ctx context.Context, address string) bool { +func (k Keeper) GetWhitelistAddress(ctx context.Context, address []byte) bool { found, err := k.WhitelistAddresses.Get(ctx, address) if err != nil { return false @@ -103,14 +103,14 @@ func (k Keeper) GetParams(ctx context.Context) (types.Params, error) { return k.Params.Get(ctx) } -func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr common.Address) (bool, error) { +func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr []byte) (bool, error) { exist := false tm, err := k.TokenManagement.Get(ctx, tokenId) if err != nil { return false, err } for _, manager := range tm.Managers { - if bytes.Equal(addr.Bytes(), sdk.MustAccAddressFromBech32(manager).Bytes()) { + if bytes.Equal(addr, manager) { exist = true break } @@ -118,6 +118,18 @@ func (k Keeper) IsTokenManager(ctx context.Context, tokenId string, addr common. return exist, nil } +func (k Keeper) IsTokenOwner(ctx context.Context, tokenId string, addr []byte) (bool, error) { + token, err := k.Token.Get(ctx, tokenId) + if err != nil { + return false, err + } + + if bytes.Equal(token.Issuer, addr) { + return true, nil + } + return false, nil +} + func (k Keeper) IsFreezed(ctx context.Context, addr common.Address) bool { exist, err := k.FreezeAddresses.Get(ctx, addr.Bytes()) if err != nil { diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index b7227a3c..f187f44b 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -1,9 +1,9 @@ package keeper import ( + "bytes" "context" "fmt" - "slices" "strings" errorsmod "cosmossdk.io/errors" @@ -12,8 +12,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/realiotech/realio-network/x/asset/types" "github.com/ethereum/go-ethereum/common" + "github.com/realiotech/realio-network/x/asset/types" ) type msgServer struct { @@ -32,10 +32,6 @@ var _ types.MsgServer = msgServer{} func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) (*types.MsgCreateTokenResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := msg.ValidateBasic(); err != nil { - return nil, err - } - if !ms.GetWhitelistAddress(ctx, msg.Issuer) { return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not in whitelisted addresses") } @@ -73,7 +69,7 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) sdk.NewEvent( types.EventTypeTokenCreated, sdk.NewAttribute(types.AttributeKeyTokenId, tokenId), - sdk.NewAttribute(types.AttributeKeyAddress, msg.Issuer), + sdk.NewAttribute(types.AttributeKeyAddress, sdk.AccAddress(msg.Issuer).String()), ), ) @@ -85,16 +81,12 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) (*types.MsgAssignRolesResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := msg.ValidateBasic(); err != nil { - return nil, err - } - token, err := ms.Token.Get(ctx, msg.TokenId) if err != nil { return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) } - if msg.Issuer != token.Issuer { + if !bytes.Equal(msg.Issuer, token.Issuer) { return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") } @@ -103,8 +95,7 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) } newManagers := append(tokenManagement.Managers, msg.Managers...) - slices.Sort(newManagers) - tokenManagement.Managers = slices.Compact(newManagers) + tokenManagement.Managers = newManagers err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) if err != nil { @@ -124,16 +115,12 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) func (ms msgServer) UnassignRoles(ctx context.Context, msg *types.MsgUnassignRoles) (*types.MsgUnassignRolesResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := msg.ValidateBasic(); err != nil { - return nil, err - } - token, err := ms.Token.Get(ctx, msg.TokenId) if err != nil { return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) } - if msg.Issuer != token.Issuer { + if !bytes.Equal(msg.Issuer, token.Issuer) { return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") } @@ -141,9 +128,12 @@ func (ms msgServer) UnassignRoles(ctx context.Context, msg *types.MsgUnassignRol if err != nil { return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) } - tokenManagement.Managers = slices.DeleteFunc(tokenManagement.Managers, func(manager string) bool { - return slices.Contains(msg.Managers, manager) - }) + managers := tokenManagement.Managers + for i, b := range managers { + if bytes.Equal(b, msg.Managers) { + tokenManagement.Managers = append(managers[:i], managers[i+1:]...) + } + } err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) if err != nil { diff --git a/x/asset/types/msgs.go b/x/asset/types/msgs.go index 6dfdfe15..3a8ceef7 100644 --- a/x/asset/types/msgs.go +++ b/x/asset/types/msgs.go @@ -1,14 +1,12 @@ package types import ( - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ sdk.Msg = &MsgCreateToken{} -func NewMsgCreateToken(issuer string, name string, symbol string, description string, decimal uint32, managers, distributors, extensionsList []string, allowNewExtensions bool) *MsgCreateToken { +func NewMsgCreateToken(issuer []byte, name string, symbol string, description string, decimal uint32, managers [][]byte, extensionsList []string, allowNewExtensions bool) *MsgCreateToken { return &MsgCreateToken{ Issuer: issuer, Name: name, @@ -21,65 +19,18 @@ func NewMsgCreateToken(issuer string, name string, symbol string, description st } } -func (msg *MsgCreateToken) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Issuer) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) - } - for _, manager := range msg.Managers { - _, err := sdk.AccAddressFromBech32(manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) - } - } - - return nil -} - -func NewMsgAssignRoles(issuer string, tokenId string, managers []string) *MsgAssignRoles { +func NewMsgAssignRoles(issuer []byte, tokenId string, managers [][]byte) *MsgAssignRoles { return &MsgAssignRoles{ - Issuer: issuer, - TokenId: tokenId, - Managers: managers, + Issuer: issuer, + TokenId: tokenId, + Managers: managers, } } -func (msg *MsgAssignRoles) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Issuer) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) - } - - for _, manager := range msg.Managers { - _, err := sdk.AccAddressFromBech32(manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) - } - } - - return ValidateTokenId(msg.TokenId) -} - -func NewMsgUnassignRoles(issuer string, tokenId string, managers []string) *MsgUnassignRoles { +func NewMsgUnassignRoles(issuer []byte, tokenId string, managers []byte) *MsgUnassignRoles { return &MsgUnassignRoles{ - Issuer: issuer, - TokenId: tokenId, - Managers: managers, - } -} - -func (msg *MsgUnassignRoles) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Issuer) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid issuer address (%s)", err) - } - - for _, manager := range msg.Managers { - _, err := sdk.AccAddressFromBech32(manager) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid manager address (%s): %s", manager, err) - } + Issuer: issuer, + TokenId: tokenId, + Managers: managers, } - - return ValidateTokenId(msg.TokenId) } diff --git a/x/asset/types/token.go b/x/asset/types/token.go index 660caf5f..e1d040e8 100644 --- a/x/asset/types/token.go +++ b/x/asset/types/token.go @@ -9,7 +9,7 @@ import ( ) // NewToken creates a new Token instance -func NewToken(id, name string, decimal uint32, description string, symbol string, issuer string, evmAddress string) Token { +func NewToken(id, name string, decimal uint32, description string, symbol string, issuer []byte, evmAddress string) Token { return Token{ TokenId: id, Name: name, @@ -21,7 +21,7 @@ func NewToken(id, name string, decimal uint32, description string, symbol string } } -func NewTokenManagement(managers []string, allowNewExtension bool, extensionList []string, maxSupply math.Int) TokenManagement { +func NewTokenManagement(managers [][]byte, allowNewExtension bool, extensionList []string, maxSupply math.Int) TokenManagement { return TokenManagement{ Managers: managers, AllowNewExtensions: allowNewExtension, diff --git a/x/asset/types/token.pb.go b/x/asset/types/token.pb.go index 7fa98f8d..bad0898f 100644 --- a/x/asset/types/token.pb.go +++ b/x/asset/types/token.pb.go @@ -54,7 +54,7 @@ func (Role) EnumDescriptor() ([]byte, []int) { // Token represents an asset in the module type Token struct { TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + Issuer []byte `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` Decimal uint32 `protobuf:"varint,5,opt,name=decimal,proto3" json:"decimal,omitempty"` @@ -102,11 +102,11 @@ func (m *Token) GetTokenId() string { return "" } -func (m *Token) GetIssuer() string { +func (m *Token) GetIssuer() []byte { if m != nil { return m.Issuer } - return "" + return nil } func (m *Token) GetName() string { @@ -146,7 +146,7 @@ func (m *Token) GetEvmAddress() string { // TokenManagement represents the asset manager's execute functions. type TokenManagement struct { - Managers []string `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` + Managers [][]byte `protobuf:"bytes,1,rep,name=managers,proto3" json:"managers,omitempty"` AllowNewExtensions bool `protobuf:"varint,2,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` ExtensionsList []string `protobuf:"bytes,3,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` @@ -185,7 +185,7 @@ func (m *TokenManagement) XXX_DiscardUnknown() { var xxx_messageInfo_TokenManagement proto.InternalMessageInfo -func (m *TokenManagement) GetManagers() []string { +func (m *TokenManagement) GetManagers() [][]byte { if m != nil { return m.Managers } @@ -206,63 +206,10 @@ func (m *TokenManagement) GetExtensionsList() []string { return nil } -type ShareAddress struct { - EvmAddress string `protobuf:"bytes,1,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` - SdkAddress string `protobuf:"bytes,2,opt,name=sdk_address,json=sdkAddress,proto3" json:"sdk_address,omitempty"` -} - -func (m *ShareAddress) Reset() { *m = ShareAddress{} } -func (m *ShareAddress) String() string { return proto.CompactTextString(m) } -func (*ShareAddress) ProtoMessage() {} -func (*ShareAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_2f83138fc60a3176, []int{2} -} -func (m *ShareAddress) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ShareAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ShareAddress.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ShareAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShareAddress.Merge(m, src) -} -func (m *ShareAddress) XXX_Size() int { - return m.Size() -} -func (m *ShareAddress) XXX_DiscardUnknown() { - xxx_messageInfo_ShareAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_ShareAddress proto.InternalMessageInfo - -func (m *ShareAddress) GetEvmAddress() string { - if m != nil { - return m.EvmAddress - } - return "" -} - -func (m *ShareAddress) GetSdkAddress() string { - if m != nil { - return m.SdkAddress - } - return "" -} - func init() { proto.RegisterEnum("realionetwork.asset.v1.Role", Role_name, Role_value) proto.RegisterType((*Token)(nil), "realionetwork.asset.v1.Token") proto.RegisterType((*TokenManagement)(nil), "realionetwork.asset.v1.TokenManagement") - proto.RegisterType((*ShareAddress)(nil), "realionetwork.asset.v1.ShareAddress") } func init() { @@ -270,39 +217,38 @@ func init() { } var fileDescriptor_2f83138fc60a3176 = []byte{ - // 509 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0xc6, 0x63, 0xd6, 0x75, 0xad, 0xbb, 0xd1, 0xca, 0x1a, 0x53, 0xa8, 0x44, 0x1a, 0xca, 0x81, - 0x0a, 0x89, 0x84, 0xc1, 0x95, 0x4b, 0x07, 0x01, 0x55, 0xea, 0xca, 0x94, 0x8e, 0x0b, 0x97, 0xc8, - 0x6d, 0x5e, 0xb5, 0x56, 0xe3, 0x38, 0x8a, 0xdd, 0x7f, 0xdf, 0x00, 0xed, 0xc4, 0x17, 0xd8, 0x89, - 0x8f, 0x82, 0x84, 0x76, 0xdc, 0x11, 0x71, 0x98, 0x50, 0xfb, 0x45, 0x50, 0x9d, 0xac, 0x83, 0xdd, - 0xde, 0xe7, 0x79, 0x7f, 0xb6, 0xf4, 0xd8, 0x0f, 0x6e, 0xa6, 0x40, 0x23, 0x26, 0x62, 0x50, 0x73, - 0x91, 0x4e, 0x5c, 0x2a, 0x25, 0x28, 0x77, 0x76, 0xec, 0x2a, 0x31, 0x81, 0xd8, 0x49, 0x52, 0xa1, - 0x04, 0x39, 0xfa, 0x8f, 0x71, 0x34, 0xe3, 0xcc, 0x8e, 0xeb, 0x87, 0x23, 0x31, 0x12, 0x1a, 0x71, - 0x37, 0x53, 0x46, 0x37, 0x7f, 0x20, 0xbc, 0x7b, 0xbe, 0x39, 0x4d, 0x1e, 0xe3, 0x92, 0xbe, 0x26, - 0x60, 0xa1, 0x89, 0x6c, 0xd4, 0x2a, 0xfb, 0x7b, 0x5a, 0x77, 0x42, 0x72, 0x84, 0x8b, 0x4c, 0xca, - 0x29, 0xa4, 0xe6, 0x03, 0xbd, 0xc8, 0x15, 0x21, 0xb8, 0x10, 0x53, 0x0e, 0xe6, 0x8e, 0x76, 0xf5, - 0xbc, 0x61, 0xe5, 0x92, 0x0f, 0x44, 0x64, 0x16, 0x32, 0x36, 0x53, 0xc4, 0xc4, 0x7b, 0x21, 0x0c, - 0x19, 0xa7, 0x91, 0xb9, 0x6b, 0xa3, 0xd6, 0x81, 0x7f, 0x2b, 0x89, 0x8d, 0x2b, 0x21, 0xc8, 0x61, - 0xca, 0x12, 0xc5, 0x44, 0x6c, 0x16, 0xf5, 0xb1, 0x7f, 0x2d, 0xd2, 0xc0, 0x15, 0x98, 0xf1, 0x80, - 0x86, 0x61, 0x0a, 0x52, 0x9a, 0x65, 0x4d, 0x60, 0x98, 0xf1, 0x76, 0xe6, 0x34, 0x7f, 0x22, 0x5c, - 0xd5, 0x29, 0x4e, 0x69, 0x4c, 0x47, 0xc0, 0x21, 0x56, 0xa4, 0x8e, 0x4b, 0x5c, 0xab, 0x54, 0x9a, - 0xc8, 0xde, 0x69, 0x95, 0xfd, 0xad, 0x26, 0xaf, 0xf0, 0x21, 0x8d, 0x22, 0x31, 0x0f, 0x62, 0x98, - 0x07, 0xb0, 0x50, 0x10, 0x4b, 0x26, 0x62, 0xa9, 0xe3, 0x95, 0x7c, 0xa2, 0x77, 0x3d, 0x98, 0x7b, - 0xdb, 0x0d, 0x79, 0x8e, 0xab, 0x77, 0x5c, 0x10, 0x31, 0xa9, 0xcc, 0x1d, 0x7d, 0xe9, 0xc3, 0x3b, - 0xbb, 0xcb, 0xa4, 0x22, 0x6f, 0x31, 0xe6, 0x74, 0x11, 0xc8, 0x69, 0x92, 0x44, 0xcb, 0xec, 0x0d, - 0x4e, 0x9e, 0x5c, 0xdd, 0x34, 0x8c, 0xdf, 0x37, 0x8d, 0x47, 0x43, 0x21, 0xb9, 0x90, 0x32, 0x9c, - 0x38, 0x4c, 0xb8, 0x9c, 0xaa, 0xb1, 0xd3, 0x89, 0x95, 0x5f, 0xe6, 0x74, 0xd1, 0xd7, 0x7c, 0xf3, - 0x0c, 0xef, 0xf7, 0xc7, 0x34, 0x85, 0x3c, 0xd8, 0xfd, 0xe4, 0xe8, 0x7e, 0xf2, 0x0d, 0x20, 0xc3, - 0xc9, 0x16, 0xc8, 0xfe, 0x07, 0xcb, 0x70, 0x92, 0x03, 0x2f, 0xce, 0x71, 0xc1, 0x17, 0x11, 0x90, - 0x67, 0xb8, 0xe6, 0x7f, 0xea, 0x7a, 0xc1, 0xe7, 0x5e, 0xff, 0xcc, 0x7b, 0xd7, 0xf9, 0xd0, 0xf1, - 0xde, 0xd7, 0x8c, 0xfa, 0xc1, 0xc5, 0xa5, 0x5d, 0xf6, 0x78, 0xa2, 0x96, 0x1a, 0x7a, 0x8a, 0xf7, - 0x35, 0x74, 0xda, 0xee, 0xb5, 0x3f, 0x7a, 0x7e, 0x0d, 0xd5, 0xab, 0x17, 0x97, 0x76, 0x25, 0x7b, - 0xd5, 0x74, 0x83, 0xd4, 0x0b, 0x5f, 0xbf, 0x5b, 0xc6, 0x49, 0xf7, 0x6a, 0x65, 0xa1, 0xeb, 0x95, - 0x85, 0xfe, 0xac, 0x2c, 0xf4, 0x6d, 0x6d, 0x19, 0xd7, 0x6b, 0xcb, 0xf8, 0xb5, 0xb6, 0x8c, 0x2f, - 0xaf, 0x47, 0x4c, 0x8d, 0xa7, 0x03, 0x67, 0x28, 0xb8, 0x9b, 0x35, 0x51, 0xc1, 0x70, 0x9c, 0x8f, - 0x2f, 0x6f, 0x9b, 0xbb, 0xc8, 0xbb, 0xab, 0x96, 0x09, 0xc8, 0x41, 0x51, 0x77, 0xf1, 0xcd, 0xdf, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x37, 0x0e, 0x9e, 0x07, 0xdf, 0x02, 0x00, 0x00, + // 487 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x92, 0xcf, 0x6e, 0xd3, 0x4c, + 0x14, 0xc5, 0x3d, 0x5f, 0xd2, 0x34, 0x99, 0xa4, 0x5f, 0xa2, 0x51, 0xa9, 0x4c, 0x24, 0x1c, 0x13, + 0x16, 0x44, 0x48, 0xd8, 0x14, 0xb6, 0x6c, 0x52, 0x30, 0x28, 0x52, 0x1a, 0x90, 0x5b, 0x36, 0x6c, + 0xac, 0x49, 0x7c, 0x95, 0x8c, 0xe2, 0x99, 0xb1, 0x3c, 0x93, 0x7f, 0x6f, 0x80, 0xba, 0xe2, 0x05, + 0xba, 0xe2, 0x51, 0x90, 0x50, 0x97, 0x5d, 0x22, 0x16, 0x15, 0x4a, 0x5e, 0x04, 0x65, 0x9c, 0xb6, + 0xb0, 0x3b, 0xe7, 0xcc, 0xef, 0x8e, 0x74, 0xaf, 0x0e, 0x6e, 0x67, 0x40, 0x13, 0x26, 0x05, 0xe8, + 0x85, 0xcc, 0xa6, 0x3e, 0x55, 0x0a, 0xb4, 0x3f, 0x3f, 0xf6, 0xb5, 0x9c, 0x82, 0xf0, 0xd2, 0x4c, + 0x6a, 0x49, 0x8e, 0xfe, 0x61, 0x3c, 0xc3, 0x78, 0xf3, 0xe3, 0xe6, 0xe1, 0x58, 0x8e, 0xa5, 0x41, + 0xfc, 0xad, 0xca, 0xe9, 0xf6, 0x77, 0x84, 0xf7, 0xce, 0xb7, 0xd3, 0xe4, 0x21, 0x2e, 0x9b, 0x6f, + 0x22, 0x16, 0xdb, 0xc8, 0x45, 0x9d, 0x4a, 0xb8, 0x6f, 0x7c, 0x2f, 0x26, 0x47, 0xb8, 0xc4, 0x94, + 0x9a, 0x41, 0x66, 0xff, 0xe7, 0xa2, 0x4e, 0x2d, 0xdc, 0x39, 0x42, 0x70, 0x51, 0x50, 0x0e, 0x76, + 0xc1, 0xe0, 0x46, 0x6f, 0x59, 0xb5, 0xe2, 0x43, 0x99, 0xd8, 0x45, 0x93, 0xee, 0x1c, 0xb1, 0xf1, + 0x7e, 0x0c, 0x23, 0xc6, 0x69, 0x62, 0xef, 0xb9, 0xa8, 0x73, 0x10, 0xde, 0x5a, 0xe2, 0xe2, 0x6a, + 0x0c, 0x6a, 0x94, 0xb1, 0x54, 0x33, 0x29, 0xec, 0x92, 0x19, 0xfb, 0x3b, 0x22, 0x2d, 0x5c, 0x85, + 0x39, 0x8f, 0x68, 0x1c, 0x67, 0xa0, 0x94, 0x5d, 0x31, 0x04, 0x86, 0x39, 0xef, 0xe6, 0x49, 0xfb, + 0x07, 0xc2, 0x75, 0xb3, 0xc5, 0x29, 0x15, 0x74, 0x0c, 0x1c, 0x84, 0x26, 0x4d, 0x5c, 0xe6, 0xc6, + 0x65, 0xca, 0x46, 0x6e, 0xa1, 0x53, 0x0b, 0xef, 0x3c, 0x79, 0x81, 0x0f, 0x69, 0x92, 0xc8, 0x45, + 0x24, 0x60, 0x11, 0xc1, 0x52, 0x83, 0x50, 0x4c, 0x0a, 0x65, 0xd6, 0x2b, 0x87, 0xc4, 0xbc, 0x0d, + 0x60, 0x11, 0xdc, 0xbd, 0x90, 0xa7, 0xb8, 0x7e, 0xcf, 0x45, 0x09, 0x53, 0xda, 0x2e, 0xb8, 0x85, + 0x4e, 0x25, 0xfc, 0xff, 0x3e, 0xee, 0x33, 0xa5, 0xc9, 0x6b, 0x8c, 0x39, 0x5d, 0x46, 0x6a, 0x96, + 0xa6, 0xc9, 0x2a, 0xbf, 0xc1, 0xc9, 0xa3, 0xab, 0x9b, 0x96, 0xf5, 0xeb, 0xa6, 0xf5, 0x60, 0x24, + 0x15, 0x97, 0x4a, 0xc5, 0x53, 0x8f, 0x49, 0x9f, 0x53, 0x3d, 0xf1, 0x7a, 0x42, 0x87, 0x15, 0x4e, + 0x97, 0x67, 0x86, 0x7f, 0x76, 0x8e, 0x8b, 0xa1, 0x4c, 0x80, 0x3c, 0xc1, 0x8d, 0xf0, 0x43, 0x3f, + 0x88, 0x3e, 0x0d, 0xce, 0x3e, 0x06, 0x6f, 0x7a, 0xef, 0x7a, 0xc1, 0xdb, 0x86, 0xd5, 0x3c, 0xb8, + 0xb8, 0x74, 0x2b, 0x01, 0x4f, 0xf5, 0xca, 0x40, 0x8f, 0x71, 0xcd, 0x40, 0xa7, 0xdd, 0x41, 0xf7, + 0x7d, 0x10, 0x36, 0x50, 0xb3, 0x7e, 0x71, 0xe9, 0x56, 0xf3, 0x1b, 0x64, 0x5b, 0xa4, 0x59, 0xfc, + 0xf2, 0xcd, 0xb1, 0x4e, 0xfa, 0x57, 0x6b, 0x07, 0x5d, 0xaf, 0x1d, 0xf4, 0x7b, 0xed, 0xa0, 0xaf, + 0x1b, 0xc7, 0xba, 0xde, 0x38, 0xd6, 0xcf, 0x8d, 0x63, 0x7d, 0x7e, 0x39, 0x66, 0x7a, 0x32, 0x1b, + 0x7a, 0x23, 0xc9, 0xfd, 0xbc, 0x37, 0x1a, 0x46, 0x93, 0x9d, 0x7c, 0x7e, 0xdb, 0xb3, 0xe5, 0xae, + 0x69, 0x7a, 0x95, 0x82, 0x1a, 0x96, 0x4c, 0x73, 0x5e, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, 0x56, + 0xd0, 0x21, 0xe1, 0x8d, 0x02, 0x00, 0x00, } func (m *Token) Marshal() (dAtA []byte, err error) { @@ -436,43 +382,6 @@ func (m *TokenManagement) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ShareAddress) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ShareAddress) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ShareAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.SdkAddress) > 0 { - i -= len(m.SdkAddress) - copy(dAtA[i:], m.SdkAddress) - i = encodeVarintToken(dAtA, i, uint64(len(m.SdkAddress))) - i-- - dAtA[i] = 0x12 - } - if len(m.EvmAddress) > 0 { - i -= len(m.EvmAddress) - copy(dAtA[i:], m.EvmAddress) - i = encodeVarintToken(dAtA, i, uint64(len(m.EvmAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintToken(dAtA []byte, offset int, v uint64) int { offset -= sovToken(v) base := offset @@ -527,8 +436,8 @@ func (m *TokenManagement) Size() (n int) { var l int _ = l if len(m.Managers) > 0 { - for _, s := range m.Managers { - l = len(s) + for _, b := range m.Managers { + l = len(b) n += 1 + l + sovToken(uint64(l)) } } @@ -546,23 +455,6 @@ func (m *TokenManagement) Size() (n int) { return n } -func (m *ShareAddress) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.EvmAddress) - if l > 0 { - n += 1 + l + sovToken(uint64(l)) - } - l = len(m.SdkAddress) - if l > 0 { - n += 1 + l + sovToken(uint64(l)) - } - return n -} - func sovToken(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -634,7 +526,7 @@ func (m *Token) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowToken @@ -644,23 +536,25 @@ func (m *Token) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthToken } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthToken } if postIndex > l { return io.ErrUnexpectedEOF } - m.Issuer = string(dAtA[iNdEx:postIndex]) + m.Issuer = append(m.Issuer[:0], dAtA[iNdEx:postIndex]...) + if m.Issuer == nil { + m.Issuer = []byte{} + } iNdEx = postIndex case 3: if wireType != 2 { @@ -863,7 +757,7 @@ func (m *TokenManagement) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowToken @@ -873,23 +767,23 @@ func (m *TokenManagement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthToken } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthToken } if postIndex > l { return io.ErrUnexpectedEOF } - m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + m.Managers = append(m.Managers, make([]byte, postIndex-iNdEx)) + copy(m.Managers[len(m.Managers)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 0 { @@ -998,120 +892,6 @@ func (m *TokenManagement) Unmarshal(dAtA []byte) error { } return nil } -func (m *ShareAddress) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowToken - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ShareAddress: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ShareAddress: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EvmAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowToken - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthToken - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthToken - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.EvmAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SdkAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowToken - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthToken - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthToken - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SdkAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipToken(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthToken - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipToken(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/asset/types/tx.pb.go b/x/asset/types/tx.pb.go index 751ecea0..27f34ac0 100644 --- a/x/asset/types/tx.pb.go +++ b/x/asset/types/tx.pb.go @@ -33,12 +33,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type MsgCreateToken struct { // issuer is the address that defines the token - Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + Issuer []byte `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Decimal uint32 `protobuf:"varint,3,opt,name=decimal,proto3" json:"decimal,omitempty"` Symbol string `protobuf:"bytes,4,opt,name=symbol,proto3" json:"symbol,omitempty"` Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` - Managers []string `protobuf:"bytes,6,rep,name=managers,proto3" json:"managers,omitempty"` + Managers [][]byte `protobuf:"bytes,6,rep,name=managers,proto3" json:"managers,omitempty"` AllowNewExtensions bool `protobuf:"varint,8,opt,name=allow_new_extensions,json=allowNewExtensions,proto3" json:"allow_new_extensions,omitempty"` ExtensionsList []string `protobuf:"bytes,9,rep,name=extensions_list,json=extensionsList,proto3" json:"extensions_list,omitempty"` MaxSupply cosmossdk_io_math.Int `protobuf:"bytes,10,opt,name=max_supply,json=maxSupply,proto3,customtype=cosmossdk.io/math.Int" json:"max_supply"` @@ -77,11 +77,11 @@ func (m *MsgCreateToken) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateToken proto.InternalMessageInfo -func (m *MsgCreateToken) GetIssuer() string { +func (m *MsgCreateToken) GetIssuer() []byte { if m != nil { return m.Issuer } - return "" + return nil } func (m *MsgCreateToken) GetName() string { @@ -112,7 +112,7 @@ func (m *MsgCreateToken) GetDescription() string { return "" } -func (m *MsgCreateToken) GetManagers() []string { +func (m *MsgCreateToken) GetManagers() [][]byte { if m != nil { return m.Managers } @@ -179,9 +179,9 @@ func (m *MsgCreateTokenResponse) GetTokenId() string { type MsgAssignRoles struct { // issuer is the address that defines the token - Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + Issuer []byte `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` + Managers [][]byte `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` } func (m *MsgAssignRoles) Reset() { *m = MsgAssignRoles{} } @@ -217,11 +217,11 @@ func (m *MsgAssignRoles) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAssignRoles proto.InternalMessageInfo -func (m *MsgAssignRoles) GetIssuer() string { +func (m *MsgAssignRoles) GetIssuer() []byte { if m != nil { return m.Issuer } - return "" + return nil } func (m *MsgAssignRoles) GetTokenId() string { @@ -231,7 +231,7 @@ func (m *MsgAssignRoles) GetTokenId() string { return "" } -func (m *MsgAssignRoles) GetManagers() []string { +func (m *MsgAssignRoles) GetManagers() [][]byte { if m != nil { return m.Managers } @@ -276,9 +276,9 @@ var xxx_messageInfo_MsgAssignRolesResponse proto.InternalMessageInfo type MsgUnassignRoles struct { // issuer is the address that defines the token - Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` - TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Managers []string `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` + Issuer []byte `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []byte `protobuf:"bytes,3,opt,name=managers,proto3" json:"managers,omitempty"` } func (m *MsgUnassignRoles) Reset() { *m = MsgUnassignRoles{} } @@ -314,11 +314,11 @@ func (m *MsgUnassignRoles) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUnassignRoles proto.InternalMessageInfo -func (m *MsgUnassignRoles) GetIssuer() string { +func (m *MsgUnassignRoles) GetIssuer() []byte { if m != nil { return m.Issuer } - return "" + return nil } func (m *MsgUnassignRoles) GetTokenId() string { @@ -328,7 +328,7 @@ func (m *MsgUnassignRoles) GetTokenId() string { return "" } -func (m *MsgUnassignRoles) GetManagers() []string { +func (m *MsgUnassignRoles) GetManagers() []byte { if m != nil { return m.Managers } @@ -478,48 +478,48 @@ func init() { func init() { proto.RegisterFile("realionetwork/asset/v1/tx.proto", fileDescriptor_1cfda60866e68e13) } var fileDescriptor_1cfda60866e68e13 = []byte{ - // 644 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0x4d, 0x4b, 0x1b, 0x41, - 0x18, 0xce, 0x1a, 0x8d, 0xc9, 0xa4, 0x6a, 0x19, 0xac, 0xae, 0x4b, 0xbb, 0x86, 0x14, 0x6a, 0x10, - 0xba, 0xeb, 0xc7, 0x4d, 0xbc, 0xd4, 0xd2, 0x83, 0xa0, 0xa5, 0x6c, 0xdb, 0x4b, 0x2f, 0x61, 0x4c, - 0x86, 0xcd, 0x90, 0x9d, 0x99, 0x65, 0xdf, 0x89, 0x49, 0x0e, 0x85, 0xd2, 0x5f, 0xd0, 0x9f, 0x62, - 0xff, 0x85, 0x47, 0xe9, 0xa9, 0xf4, 0x20, 0x45, 0x0f, 0xfe, 0x8d, 0xb2, 0xb3, 0x9b, 0x64, 0x57, - 0x4c, 0xf0, 0xd4, 0xdb, 0xbc, 0xf3, 0x3e, 0xf3, 0x3c, 0x0f, 0xef, 0xc7, 0xa0, 0xcd, 0x88, 0x92, - 0x80, 0x49, 0x41, 0x55, 0x5f, 0x46, 0x5d, 0x97, 0x00, 0x50, 0xe5, 0x9e, 0xef, 0xba, 0x6a, 0xe0, - 0x84, 0x91, 0x54, 0x12, 0xaf, 0xe5, 0x00, 0x8e, 0x06, 0x38, 0xe7, 0xbb, 0xd6, 0xaa, 0x2f, 0x7d, - 0xa9, 0x21, 0x6e, 0x7c, 0x4a, 0xd0, 0xd6, 0xcb, 0x29, 0x74, 0x21, 0x89, 0x08, 0x87, 0x14, 0x54, - 0x9f, 0xa6, 0x29, 0xbb, 0x54, 0xa4, 0x98, 0x8d, 0x96, 0x04, 0x2e, 0xa1, 0x99, 0x28, 0x24, 0x41, - 0x9a, 0x5a, 0x4f, 0x22, 0x97, 0x83, 0x1f, 0xbf, 0xe2, 0xe0, 0x27, 0x89, 0xfa, 0xaf, 0x39, 0xb4, - 0x7c, 0x0a, 0xfe, 0xdb, 0x88, 0x12, 0x45, 0x3f, 0xc5, 0x64, 0x78, 0x0d, 0x95, 0x18, 0x40, 0x8f, - 0x46, 0xa6, 0x51, 0x33, 0x1a, 0x15, 0x2f, 0x8d, 0x30, 0x46, 0xf3, 0x82, 0x70, 0x6a, 0xce, 0xe9, - 0x5b, 0x7d, 0xc6, 0x26, 0x5a, 0x6c, 0xd3, 0x16, 0xe3, 0x24, 0x30, 0x8b, 0x35, 0xa3, 0xb1, 0xe4, - 0x8d, 0xc2, 0x98, 0x05, 0x86, 0xfc, 0x4c, 0x06, 0xe6, 0x7c, 0xc2, 0x92, 0x44, 0xb8, 0x86, 0xaa, - 0x6d, 0x0a, 0xad, 0x88, 0x85, 0x8a, 0x49, 0x61, 0x2e, 0xe8, 0x64, 0xf6, 0x0a, 0x5b, 0xa8, 0xcc, - 0x89, 0x20, 0x3e, 0x8d, 0xc0, 0x2c, 0xd5, 0x8a, 0x8d, 0x8a, 0x37, 0x8e, 0xf1, 0x0e, 0x5a, 0x25, - 0x41, 0x20, 0xfb, 0x4d, 0x41, 0xfb, 0x4d, 0x3a, 0x50, 0x54, 0x00, 0x93, 0x02, 0xcc, 0x72, 0xcd, - 0x68, 0x94, 0x3d, 0xac, 0x73, 0xef, 0x69, 0xff, 0xdd, 0x38, 0x83, 0xb7, 0xd0, 0xca, 0x04, 0xd7, - 0x0c, 0x18, 0x28, 0xb3, 0xa2, 0x49, 0x97, 0x27, 0xd7, 0x27, 0x0c, 0x14, 0x3e, 0x44, 0x88, 0x93, - 0x41, 0x13, 0x7a, 0x61, 0x18, 0x0c, 0x4d, 0x14, 0xfb, 0x3a, 0x7a, 0x71, 0x79, 0xbd, 0x59, 0xf8, - 0x73, 0xbd, 0xf9, 0x2c, 0x29, 0x1f, 0xb4, 0xbb, 0x0e, 0x93, 0x2e, 0x27, 0xaa, 0xe3, 0x1c, 0x0b, - 0xe5, 0x55, 0x38, 0x19, 0x7c, 0xd4, 0xf8, 0x83, 0xea, 0xf7, 0xbb, 0x8b, 0xed, 0xb4, 0x52, 0xf5, - 0x7d, 0xb4, 0x96, 0xaf, 0xa9, 0x47, 0x21, 0x94, 0x02, 0x28, 0xde, 0x40, 0x65, 0xdd, 0xb1, 0x26, - 0x6b, 0xa7, 0xd5, 0x5d, 0xd4, 0xf1, 0x71, 0xbb, 0x1e, 0xe8, 0x46, 0xbc, 0x01, 0x60, 0xbe, 0xf0, - 0x64, 0x40, 0x61, 0x6a, 0x23, 0xb2, 0x24, 0x73, 0x39, 0x92, 0x5c, 0xed, 0x8a, 0xf9, 0xda, 0xe5, - 0x2d, 0x9a, 0xda, 0x62, 0x46, 0x6d, 0x64, 0xb1, 0x2e, 0xd0, 0xd3, 0x53, 0xf0, 0x3f, 0x0b, 0xf2, - 0x9f, 0x9c, 0x58, 0xc8, 0xbc, 0xaf, 0x37, 0xf6, 0xf2, 0x15, 0xad, 0xc4, 0xb9, 0xb0, 0x4d, 0x14, - 0xfd, 0xa0, 0xd7, 0x01, 0x3f, 0x47, 0x15, 0xd2, 0x53, 0x1d, 0x19, 0x31, 0x35, 0x4c, 0xdd, 0x4c, - 0x2e, 0xf0, 0x21, 0x2a, 0x25, 0x6b, 0xa3, 0xed, 0x54, 0xf7, 0x6c, 0xe7, 0xe1, 0x55, 0x74, 0x12, - 0xb6, 0xa3, 0xf9, 0xb8, 0xc1, 0x5e, 0xfa, 0xe6, 0x60, 0x39, 0xf6, 0x35, 0x61, 0xab, 0x6f, 0xa0, - 0xf5, 0x7b, 0xf2, 0x23, 0x67, 0x7b, 0x3f, 0x8b, 0xa8, 0x78, 0x0a, 0x3e, 0xee, 0xa0, 0x27, 0x39, - 0x7b, 0x5b, 0xd3, 0x04, 0xef, 0x11, 0x59, 0xee, 0x23, 0x81, 0xe3, 0xd1, 0xa1, 0xa8, 0x9a, 0xdd, - 0xd2, 0x57, 0x33, 0xde, 0x67, 0x70, 0x96, 0xf3, 0x38, 0x5c, 0x56, 0x26, 0x3b, 0x83, 0xb3, 0x64, - 0x32, 0xb8, 0x99, 0x32, 0x0f, 0x4c, 0x19, 0xee, 0xa2, 0xa5, 0xfc, 0x88, 0x35, 0x66, 0xd5, 0x23, - 0x8b, 0xb4, 0x76, 0x1e, 0x8b, 0x1c, 0x89, 0x59, 0x0b, 0xdf, 0xee, 0x2e, 0xb6, 0x8d, 0xa3, 0x93, - 0xcb, 0x1b, 0xdb, 0xb8, 0xba, 0xb1, 0x8d, 0xbf, 0x37, 0xb6, 0xf1, 0xe3, 0xd6, 0x2e, 0x5c, 0xdd, - 0xda, 0x85, 0xdf, 0xb7, 0x76, 0xe1, 0xcb, 0x9e, 0xcf, 0x54, 0xa7, 0x77, 0xe6, 0xb4, 0x24, 0x77, - 0x13, 0x72, 0x45, 0x5b, 0x9d, 0xf4, 0xf8, 0x7a, 0xf4, 0xe9, 0x0e, 0xd2, 0x6f, 0x57, 0x0d, 0x43, - 0x0a, 0x67, 0x25, 0xfd, 0x81, 0xee, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x66, 0xbc, 0x27, - 0x0e, 0x06, 0x00, 0x00, + // 656 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x4e, 0xdb, 0x4c, + 0x14, 0x8d, 0x09, 0x84, 0x64, 0xc2, 0xcf, 0xa7, 0x11, 0x1f, 0x18, 0xab, 0x35, 0x56, 0x2a, 0x15, + 0x0b, 0xa9, 0x36, 0x3f, 0x3b, 0xc4, 0xa6, 0x54, 0x5d, 0x20, 0x41, 0x55, 0xb9, 0xed, 0xa6, 0x9b, + 0x68, 0x48, 0x46, 0xce, 0x28, 0xf6, 0x8c, 0xe5, 0x3b, 0x21, 0xc9, 0xa2, 0x52, 0xd5, 0x27, 0xe8, + 0xa3, 0xd0, 0xb7, 0x60, 0x89, 0xba, 0xaa, 0xba, 0x40, 0x15, 0x2c, 0x78, 0x8d, 0xca, 0x63, 0x27, + 0xb1, 0x11, 0x89, 0x58, 0x74, 0x37, 0x77, 0xee, 0x99, 0x73, 0x8e, 0xce, 0xcc, 0x1d, 0xb4, 0x15, + 0x53, 0x12, 0x30, 0xc1, 0xa9, 0xec, 0x8b, 0xb8, 0xeb, 0x12, 0x00, 0x2a, 0xdd, 0x8b, 0x3d, 0x57, + 0x0e, 0x9c, 0x28, 0x16, 0x52, 0xe0, 0xf5, 0x02, 0xc0, 0x51, 0x00, 0xe7, 0x62, 0xcf, 0x58, 0xf3, + 0x85, 0x2f, 0x14, 0xc4, 0x4d, 0x56, 0x29, 0xda, 0x78, 0x31, 0x85, 0x2e, 0x22, 0x31, 0x09, 0x21, + 0x03, 0x35, 0xa6, 0x69, 0x8a, 0x2e, 0xe5, 0x19, 0x66, 0xb3, 0x25, 0x20, 0x14, 0xd0, 0x4c, 0x15, + 0xd2, 0x22, 0x6b, 0x6d, 0xa4, 0x95, 0x1b, 0x82, 0x9f, 0x9c, 0x0a, 0xc1, 0x4f, 0x1b, 0x8d, 0x9f, + 0x73, 0x68, 0xe5, 0x0c, 0xfc, 0x37, 0x31, 0x25, 0x92, 0x7e, 0x4c, 0xc8, 0xf0, 0x3a, 0xaa, 0x30, + 0x80, 0x1e, 0x8d, 0x75, 0xcd, 0xd2, 0xec, 0x25, 0x2f, 0xab, 0x30, 0x46, 0xf3, 0x9c, 0x84, 0x54, + 0x9f, 0xb3, 0x34, 0xbb, 0xe6, 0xa9, 0x35, 0xd6, 0xd1, 0x62, 0x9b, 0xb6, 0x58, 0x48, 0x02, 0xbd, + 0x6c, 0x69, 0xf6, 0xb2, 0x37, 0x2a, 0x13, 0x16, 0x18, 0x86, 0xe7, 0x22, 0xd0, 0xe7, 0x15, 0x3e, + 0xab, 0xb0, 0x85, 0xea, 0x6d, 0x0a, 0xad, 0x98, 0x45, 0x92, 0x09, 0xae, 0x2f, 0xa8, 0x66, 0x7e, + 0x0b, 0x1b, 0xa8, 0x1a, 0x12, 0x4e, 0x7c, 0x1a, 0x83, 0x5e, 0xb1, 0xca, 0xf6, 0x92, 0x37, 0xae, + 0xf1, 0x2e, 0x5a, 0x23, 0x41, 0x20, 0xfa, 0x4d, 0x4e, 0xfb, 0x4d, 0x3a, 0x90, 0x94, 0x03, 0x13, + 0x1c, 0xf4, 0xaa, 0xa5, 0xd9, 0x55, 0x0f, 0xab, 0xde, 0x3b, 0xda, 0x7f, 0x3b, 0xee, 0xe0, 0x6d, + 0xb4, 0x3a, 0xc1, 0x35, 0x03, 0x06, 0x52, 0xaf, 0x59, 0x65, 0xbb, 0xe6, 0xad, 0x4c, 0xb6, 0x4f, + 0x19, 0x48, 0x7c, 0x84, 0x50, 0x48, 0x06, 0x4d, 0xe8, 0x45, 0x51, 0x30, 0xd4, 0x51, 0xe2, 0xeb, + 0xf8, 0xf9, 0xd5, 0xcd, 0x56, 0xe9, 0xf7, 0xcd, 0xd6, 0xff, 0x69, 0x7c, 0xd0, 0xee, 0x3a, 0x4c, + 0xb8, 0x21, 0x91, 0x1d, 0xe7, 0x84, 0x4b, 0xaf, 0x16, 0x92, 0xc1, 0x07, 0x85, 0x3f, 0xac, 0x7f, + 0xbb, 0xbf, 0xdc, 0xc9, 0x92, 0x6a, 0x1c, 0xa0, 0xf5, 0x62, 0xa6, 0x1e, 0x85, 0x48, 0x70, 0xa0, + 0x78, 0x13, 0x55, 0xd5, 0x8d, 0x35, 0x59, 0x5b, 0xa5, 0x5b, 0xf3, 0x16, 0x55, 0x7d, 0xd2, 0x6e, + 0x04, 0xea, 0x22, 0x5e, 0x03, 0x30, 0x9f, 0x7b, 0x22, 0xa0, 0x30, 0xf5, 0x22, 0xf2, 0x24, 0x73, + 0x05, 0x92, 0x42, 0x76, 0xe5, 0x62, 0x76, 0x45, 0x8b, 0xba, 0xb2, 0x98, 0x53, 0x1b, 0x59, 0x6c, + 0x70, 0xf4, 0xdf, 0x19, 0xf8, 0x9f, 0x38, 0xf9, 0x97, 0x4e, 0xb4, 0xe9, 0x4e, 0x0c, 0xa4, 0x3f, + 0xd4, 0x1b, 0x7b, 0xf9, 0x82, 0x56, 0x93, 0x5e, 0xd4, 0x26, 0x92, 0xbe, 0x57, 0xe3, 0x80, 0x9f, + 0xa1, 0x1a, 0xe9, 0xc9, 0x8e, 0x88, 0x99, 0x1c, 0x66, 0x11, 0x4e, 0x36, 0xf0, 0x11, 0xaa, 0xa4, + 0x63, 0xa3, 0xec, 0xd4, 0xf7, 0x4d, 0xe7, 0xf1, 0x51, 0x74, 0x52, 0xb6, 0xe3, 0xf9, 0xe4, 0x82, + 0xbd, 0xec, 0xcc, 0xe1, 0x4a, 0xe2, 0x6b, 0xc2, 0xd6, 0xd8, 0x44, 0x1b, 0x0f, 0xe4, 0x47, 0xce, + 0xf6, 0x7f, 0x94, 0x51, 0xf9, 0x0c, 0x7c, 0xdc, 0x41, 0x4b, 0x05, 0x7b, 0xdb, 0xd3, 0x04, 0x1f, + 0x10, 0x19, 0xee, 0x13, 0x81, 0xe3, 0xa7, 0x43, 0x51, 0x3d, 0x3f, 0xa5, 0x2f, 0x67, 0x9c, 0xcf, + 0xe1, 0x0c, 0xe7, 0x69, 0xb8, 0xbc, 0x4c, 0xfe, 0x0d, 0xce, 0x92, 0xc9, 0xe1, 0x66, 0xca, 0x3c, + 0xf2, 0xca, 0x70, 0x17, 0x2d, 0x17, 0x9f, 0x98, 0x3d, 0x2b, 0x8f, 0x3c, 0xd2, 0xd8, 0x7d, 0x2a, + 0x72, 0x24, 0x66, 0x2c, 0x7c, 0xbd, 0xbf, 0xdc, 0xd1, 0x8e, 0x4f, 0xaf, 0x6e, 0x4d, 0xed, 0xfa, + 0xd6, 0xd4, 0xfe, 0xdc, 0x9a, 0xda, 0xf7, 0x3b, 0xb3, 0x74, 0x7d, 0x67, 0x96, 0x7e, 0xdd, 0x99, + 0xa5, 0xcf, 0xfb, 0x3e, 0x93, 0x9d, 0xde, 0xb9, 0xd3, 0x12, 0xa1, 0x9b, 0x92, 0x4b, 0xda, 0xea, + 0x64, 0xcb, 0x57, 0xa3, 0x4f, 0x77, 0x90, 0x7d, 0xbb, 0x72, 0x18, 0x51, 0x38, 0xaf, 0xa8, 0x0f, + 0xf4, 0xe0, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5a, 0xa7, 0x7c, 0xb3, 0x0e, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -926,13 +926,11 @@ func (m *MsgUnassignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if len(m.Managers) > 0 { - for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Managers[iNdEx]) - copy(dAtA[i:], m.Managers[iNdEx]) - i = encodeVarintTx(dAtA, i, uint64(len(m.Managers[iNdEx]))) - i-- - dAtA[i] = 0x1a - } + i -= len(m.Managers) + copy(dAtA[i:], m.Managers) + i = encodeVarintTx(dAtA, i, uint64(len(m.Managers))) + i-- + dAtA[i] = 0x1a } if len(m.TokenId) > 0 { i -= len(m.TokenId) @@ -1074,8 +1072,8 @@ func (m *MsgCreateToken) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } if len(m.Managers) > 0 { - for _, s := range m.Managers { - l = len(s) + for _, b := range m.Managers { + l = len(b) n += 1 + l + sovTx(uint64(l)) } } @@ -1121,8 +1119,8 @@ func (m *MsgAssignRoles) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } if len(m.Managers) > 0 { - for _, s := range m.Managers { - l = len(s) + for _, b := range m.Managers { + l = len(b) n += 1 + l + sovTx(uint64(l)) } } @@ -1152,11 +1150,9 @@ func (m *MsgUnassignRoles) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if len(m.Managers) > 0 { - for _, s := range m.Managers { - l = len(s) - n += 1 + l + sovTx(uint64(l)) - } + l = len(m.Managers) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) } return n } @@ -1233,7 +1229,7 @@ func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1243,23 +1239,25 @@ func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Issuer = string(dAtA[iNdEx:postIndex]) + m.Issuer = append(m.Issuer[:0], dAtA[iNdEx:postIndex]...) + if m.Issuer == nil { + m.Issuer = []byte{} + } iNdEx = postIndex case 2: if wireType != 2 { @@ -1380,7 +1378,7 @@ func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1390,23 +1388,23 @@ func (m *MsgCreateToken) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + m.Managers = append(m.Managers, make([]byte, postIndex-iNdEx)) + copy(m.Managers[len(m.Managers)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex case 8: if wireType != 0 { @@ -1630,7 +1628,7 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1640,23 +1638,25 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Issuer = string(dAtA[iNdEx:postIndex]) + m.Issuer = append(m.Issuer[:0], dAtA[iNdEx:postIndex]...) + if m.Issuer == nil { + m.Issuer = []byte{} + } iNdEx = postIndex case 2: if wireType != 2 { @@ -1694,7 +1694,7 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1704,23 +1704,23 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + m.Managers = append(m.Managers, make([]byte, postIndex-iNdEx)) + copy(m.Managers[len(m.Managers)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1826,7 +1826,7 @@ func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Issuer", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1836,23 +1836,25 @@ func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Issuer = string(dAtA[iNdEx:postIndex]) + m.Issuer = append(m.Issuer[:0], dAtA[iNdEx:postIndex]...) + if m.Issuer == nil { + m.Issuer = []byte{} + } iNdEx = postIndex case 2: if wireType != 2 { @@ -1890,7 +1892,7 @@ func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Managers", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1900,23 +1902,25 @@ func (m *MsgUnassignRoles) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Managers = append(m.Managers, string(dAtA[iNdEx:postIndex])) + m.Managers = append(m.Managers[:0], dAtA[iNdEx:postIndex]...) + if m.Managers == nil { + m.Managers = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex From 6139a5c8c7085002e481e9951ec17ac544a13fd6 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Thu, 13 Feb 2025 21:29:27 +0700 Subject: [PATCH 53/53] access control --- precompiles/erc20/IAccessControl.sol | 20 +++++ precompiles/erc20/access_control.go | 94 ++++++++++++++++++++++ precompiles/erc20/events.go | 59 +++++++++++++- precompiles/erc20/types.go | 23 +++++- proto/realionetwork/asset/v1/tx.proto | 2 +- x/asset/keeper/access_control.go | 53 +++++++++++++ x/asset/keeper/msg_server.go | 45 +---------- x/asset/types/msgs.go | 2 +- x/asset/types/tx.pb.go | 108 +++++++++++++------------- 9 files changed, 302 insertions(+), 104 deletions(-) create mode 100644 precompiles/erc20/IAccessControl.sol create mode 100644 precompiles/erc20/access_control.go create mode 100644 x/asset/keeper/access_control.go diff --git a/precompiles/erc20/IAccessControl.sol b/precompiles/erc20/IAccessControl.sol new file mode 100644 index 00000000..75f38e96 --- /dev/null +++ b/precompiles/erc20/IAccessControl.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IAccessControl { + + /** + * @dev Set role for an address + */ + function grantRole(bytes32 role, address addr) external returns (bool); + + /** + * @dev Unset role for an address + */ + function revokeRole(bytes32 role, address addr) external returns (bool); +} diff --git a/precompiles/erc20/access_control.go b/precompiles/erc20/access_control.go new file mode 100644 index 00000000..3224c810 --- /dev/null +++ b/precompiles/erc20/access_control.go @@ -0,0 +1,94 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package erc20 + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/os/x/evm/core/vm" + assettypes "github.com/realiotech/realio-network/x/asset/types" +) + +func (p *Precompile) GrantRole( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + to, role, err := ParseGrantRoleArgs(args) + if err != nil { + return nil, err + } + + return p.grantRole(ctx, contract, stateDB, method, to, role) +} + +func (p *Precompile) RevokeRole( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + to, role, err := ParseRevokeRoleArgs(args) + if err != nil { + return nil, err + } + + return p.grantRole(ctx, contract, stateDB, method, to, role) +} + +func (p *Precompile) grantRole( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + to common.Address, + role int32, +) (data []byte, err error) { + sender := contract.CallerAddress + + if role != int32(assettypes.ManagerRole) { + return nil, fmt.Errorf("only accept manager role") + } + err = p.assetKeep.GrantRole(ctx, p.denom, sender.Bytes(), to.Bytes()) + if err != nil { + return nil, err + } + + if err = p.EmitGrantRoleEvent(ctx, stateDB, sender, to, role); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +func (p *Precompile) revokeRole( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + to common.Address, + role int32, +) (data []byte, err error) { + sender := contract.CallerAddress + + if role != int32(assettypes.ManagerRole) { + return nil, fmt.Errorf("only accept manager role") + } + err = p.assetKeep.RevokeRole(ctx, p.denom, sender.Bytes(), to.Bytes()) + if err != nil { + return nil, err + } + + if err = p.EmitRevokeRoleEvent(ctx, stateDB, sender, to, role); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index b09da709..d8e12172 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -20,9 +20,12 @@ import ( const ( // EventTypeTransfer defines the event type for the ERC-20 Transfer and TransferFrom transactions. - EventTypeTransfer = "Transfer" - EventTypeMint = "Mint" - EventTypeBurn = "Burn" + EventTypeTransfer = "Transfer" + EventTypeMint = "Mint" + EventTypeBurn = "Burn" + EventTypeFreeze = "Freeze" + EventTypeGrantRole = "RoleGranted" + EventTypeRevokeRole = "RoleRevoked" ) // EmitTransferEvent creates a new Transfer event emitted on transfer and transferFrom transactions. @@ -127,7 +130,7 @@ func (p Precompile) EmitBurnEvent(ctx sdk.Context, stateDB vm.StateDB, from comm func (p Precompile) EmitFreezeEvent(ctx sdk.Context, stateDB vm.StateDB, to common.Address) error { // Prepare the event topics - event := p.ABI.Events[EventTypeBurn] + event := p.ABI.Events[EventTypeFreeze] topics := make([]common.Hash, 2) // The first topic is always the signature of the event. @@ -148,6 +151,54 @@ func (p Precompile) EmitFreezeEvent(ctx sdk.Context, stateDB vm.StateDB, to comm return nil } +func (p Precompile) EmitGrantRoleEvent(ctx sdk.Context, stateDB vm.StateDB, sender, to common.Address, role int32) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeGrantRole] + topics := make([]common.Hash, 1) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + arguments := abi.Arguments{event.Inputs[0], event.Inputs[1], event.Inputs[2]} + packed, err := arguments.Pack(sender, to, role) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + +func (p Precompile) EmitRevokeRoleEvent(ctx sdk.Context, stateDB vm.StateDB, sender, to common.Address, role int32) error { + // Prepare the event topics + event := p.ABI.Events[EventTypeRevokeRole] + topics := make([]common.Hash, 1) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + arguments := abi.Arguments{event.Inputs[0], event.Inputs[1], event.Inputs[2]} + packed, err := arguments.Pack(sender, to, role) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 // block height won't exceed uint64 + }) + + return nil +} + // EmitApprovalEvent creates a new approval event emitted on Approve, IncreaseAllowance // and DecreaseAllowance transactions. func (p Precompile) EmitApprovalEvent(ctx sdk.Context, stateDB vm.StateDB, owner, spender common.Address, value *big.Int) error { diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index d95deafc..d73c0ea2 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -222,7 +222,7 @@ func ParseFreezeArgs(args []interface{}) ( } func ParseGrantRoleArgs(args []interface{}) ( - from common.Address, role int32, err error, + to common.Address, role int32, err error, ) { if len(args) != 2 { return common.Address{}, 0, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) @@ -233,7 +233,7 @@ func ParseGrantRoleArgs(args []interface{}) ( return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) } - to, ok := args[0].(common.Address) + to, ok = args[0].(common.Address) if !ok { return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) } @@ -241,4 +241,23 @@ func ParseGrantRoleArgs(args []interface{}) ( return to, role, nil } +func ParseRevokeRoleArgs(args []interface{}) ( + to common.Address, role int32, err error, +) { + if len(args) != 2 { + return common.Address{}, 0, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + role, ok := args[0].(int32) + if !ok { + return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) + } + + to, ok = args[0].(common.Address) + if !ok { + return common.Address{}, 0, fmt.Errorf("invalid to address: %v", args[0]) + } + + return to, role, nil +} diff --git a/proto/realionetwork/asset/v1/tx.proto b/proto/realionetwork/asset/v1/tx.proto index 67539522..205b1f85 100644 --- a/proto/realionetwork/asset/v1/tx.proto +++ b/proto/realionetwork/asset/v1/tx.proto @@ -47,7 +47,7 @@ message MsgAssignRoles { bytes issuer = 1; string token_id = 2; - repeated bytes managers = 3; + bytes managers = 3; } message MsgAssignRolesResponse {} diff --git a/x/asset/keeper/access_control.go b/x/asset/keeper/access_control.go new file mode 100644 index 00000000..cfa25c6d --- /dev/null +++ b/x/asset/keeper/access_control.go @@ -0,0 +1,53 @@ +package keeper + +import ( + "bytes" + "context" + + errorsmod "cosmossdk.io/errors" + "github.com/realiotech/realio-network/x/asset/types" +) + +func (k Keeper) GrantRole(ctx context.Context, tokenId string, issuer []byte, manager []byte) error { + token, err := k.Token.Get(ctx, tokenId) + if err != nil { + return errorsmod.Wrapf(types.ErrTokenGet, err.Error()) + } + + if !bytes.Equal(issuer, token.Issuer) { + return errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") + } + + tokenManagement, err := k.TokenManagement.Get(ctx, tokenId) + if err != nil { + return errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) + } + newManagers := append(tokenManagement.Managers, manager) + tokenManagement.Managers = newManagers + + return k.TokenManagement.Set(ctx, tokenId, tokenManagement) +} + +func (k Keeper) RevokeRole(ctx context.Context, tokenId string, issuer []byte, manager []byte) error { + token, err := k.Token.Get(ctx, tokenId) + if err != nil { + return errorsmod.Wrapf(types.ErrTokenGet, err.Error()) + } + + if !bytes.Equal(issuer, token.Issuer) { + return errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") + } + + tokenManagement, err := k.TokenManagement.Get(ctx, tokenId) + if err != nil { + return errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) + } + managers := tokenManagement.Managers + for i, b := range managers { + if bytes.Equal(b, manager) { + tokenManagement.Managers = append(managers[:i], managers[i+1:]...) + } + } + + return k.TokenManagement.Set(ctx, tokenId, tokenManagement) +} diff --git a/x/asset/keeper/msg_server.go b/x/asset/keeper/msg_server.go index f187f44b..6a0fcdb2 100644 --- a/x/asset/keeper/msg_server.go +++ b/x/asset/keeper/msg_server.go @@ -1,7 +1,6 @@ package keeper import ( - "bytes" "context" "fmt" "strings" @@ -81,25 +80,9 @@ func (ms msgServer) CreateToken(ctx context.Context, msg *types.MsgCreateToken) func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) (*types.MsgAssignRolesResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - token, err := ms.Token.Get(ctx, msg.TokenId) + err := ms.Keeper.GrantRole(ctx, msg.TokenId, msg.Issuer, msg.Managers) if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) - } - - if !bytes.Equal(msg.Issuer, token.Issuer) { - return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") - } - - tokenManagement, err := ms.TokenManagement.Get(ctx, msg.TokenId) - if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) - } - newManagers := append(tokenManagement.Managers, msg.Managers...) - tokenManagement.Managers = newManagers - - err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) - if err != nil { - return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) + return nil, err } sdkCtx.EventManager().EmitEvent( @@ -115,29 +98,9 @@ func (ms msgServer) AssignRoles(ctx context.Context, msg *types.MsgAssignRoles) func (ms msgServer) UnassignRoles(ctx context.Context, msg *types.MsgUnassignRoles) (*types.MsgUnassignRolesResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - token, err := ms.Token.Get(ctx, msg.TokenId) + err := ms.Keeper.RevokeRole(ctx, msg.TokenId, msg.Issuer, msg.Managers) if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenGet, err.Error()) - } - - if !bytes.Equal(msg.Issuer, token.Issuer) { - return nil, errorsmod.Wrapf(types.ErrUnauthorize, "issuer not the creator of the token") - } - - tokenManagement, err := ms.TokenManagement.Get(ctx, msg.TokenId) - if err != nil { - return nil, errorsmod.Wrapf(types.ErrTokenManagementGet, err.Error()) - } - managers := tokenManagement.Managers - for i, b := range managers { - if bytes.Equal(b, msg.Managers) { - tokenManagement.Managers = append(managers[:i], managers[i+1:]...) - } - } - - err = ms.TokenManagement.Set(ctx, msg.TokenId, tokenManagement) - if err != nil { - return nil, errorsmod.Wrap(types.ErrTokenManagementSet, err.Error()) + return nil, err } sdkCtx.EventManager().EmitEvent( diff --git a/x/asset/types/msgs.go b/x/asset/types/msgs.go index 3a8ceef7..02c9551a 100644 --- a/x/asset/types/msgs.go +++ b/x/asset/types/msgs.go @@ -19,7 +19,7 @@ func NewMsgCreateToken(issuer []byte, name string, symbol string, description st } } -func NewMsgAssignRoles(issuer []byte, tokenId string, managers [][]byte) *MsgAssignRoles { +func NewMsgAssignRoles(issuer []byte, tokenId string, managers []byte) *MsgAssignRoles { return &MsgAssignRoles{ Issuer: issuer, TokenId: tokenId, diff --git a/x/asset/types/tx.pb.go b/x/asset/types/tx.pb.go index 27f34ac0..f51ce540 100644 --- a/x/asset/types/tx.pb.go +++ b/x/asset/types/tx.pb.go @@ -179,9 +179,9 @@ func (m *MsgCreateTokenResponse) GetTokenId() string { type MsgAssignRoles struct { // issuer is the address that defines the token - Issuer []byte `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` - TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - Managers [][]byte `protobuf:"bytes,3,rep,name=managers,proto3" json:"managers,omitempty"` + Issuer []byte `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + Managers []byte `protobuf:"bytes,3,opt,name=managers,proto3" json:"managers,omitempty"` } func (m *MsgAssignRoles) Reset() { *m = MsgAssignRoles{} } @@ -231,7 +231,7 @@ func (m *MsgAssignRoles) GetTokenId() string { return "" } -func (m *MsgAssignRoles) GetManagers() [][]byte { +func (m *MsgAssignRoles) GetManagers() []byte { if m != nil { return m.Managers } @@ -478,48 +478,48 @@ func init() { func init() { proto.RegisterFile("realionetwork/asset/v1/tx.proto", fileDescriptor_1cfda60866e68e13) } var fileDescriptor_1cfda60866e68e13 = []byte{ - // 656 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x4e, 0xdb, 0x4c, + // 654 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0xcd, 0x4e, 0xdb, 0x4c, 0x14, 0x8d, 0x09, 0x84, 0x64, 0xc2, 0xcf, 0xa7, 0x11, 0x1f, 0x18, 0xab, 0x35, 0x56, 0x2a, 0x15, 0x0b, 0xa9, 0x36, 0x3f, 0x3b, 0xc4, 0xa6, 0x54, 0x5d, 0x20, 0x41, 0x55, 0xb9, 0xed, 0xa6, 0x9b, 0x68, 0x48, 0x46, 0xce, 0x28, 0xf6, 0x8c, 0xe5, 0x3b, 0x21, 0xc9, 0xa2, 0x52, 0xd5, 0x27, 0xe8, 0xa3, 0xd0, 0xb7, 0x60, 0x89, 0xba, 0xaa, 0xba, 0x40, 0x15, 0x2c, 0x78, 0x8d, 0xca, 0x63, 0x27, - 0xb1, 0x11, 0x89, 0x58, 0x74, 0x37, 0x77, 0xee, 0x99, 0x73, 0x8e, 0xce, 0xcc, 0x1d, 0xb4, 0x15, + 0xb1, 0x11, 0x89, 0x58, 0x75, 0x37, 0x67, 0xee, 0x99, 0x73, 0x8e, 0xee, 0xcc, 0x1d, 0xb4, 0x15, 0x53, 0x12, 0x30, 0xc1, 0xa9, 0xec, 0x8b, 0xb8, 0xeb, 0x12, 0x00, 0x2a, 0xdd, 0x8b, 0x3d, 0x57, - 0x0e, 0x9c, 0x28, 0x16, 0x52, 0xe0, 0xf5, 0x02, 0xc0, 0x51, 0x00, 0xe7, 0x62, 0xcf, 0x58, 0xf3, - 0x85, 0x2f, 0x14, 0xc4, 0x4d, 0x56, 0x29, 0xda, 0x78, 0x31, 0x85, 0x2e, 0x22, 0x31, 0x09, 0x21, - 0x03, 0x35, 0xa6, 0x69, 0x8a, 0x2e, 0xe5, 0x19, 0x66, 0xb3, 0x25, 0x20, 0x14, 0xd0, 0x4c, 0x15, - 0xd2, 0x22, 0x6b, 0x6d, 0xa4, 0x95, 0x1b, 0x82, 0x9f, 0x9c, 0x0a, 0xc1, 0x4f, 0x1b, 0x8d, 0x9f, - 0x73, 0x68, 0xe5, 0x0c, 0xfc, 0x37, 0x31, 0x25, 0x92, 0x7e, 0x4c, 0xc8, 0xf0, 0x3a, 0xaa, 0x30, - 0x80, 0x1e, 0x8d, 0x75, 0xcd, 0xd2, 0xec, 0x25, 0x2f, 0xab, 0x30, 0x46, 0xf3, 0x9c, 0x84, 0x54, - 0x9f, 0xb3, 0x34, 0xbb, 0xe6, 0xa9, 0x35, 0xd6, 0xd1, 0x62, 0x9b, 0xb6, 0x58, 0x48, 0x02, 0xbd, - 0x6c, 0x69, 0xf6, 0xb2, 0x37, 0x2a, 0x13, 0x16, 0x18, 0x86, 0xe7, 0x22, 0xd0, 0xe7, 0x15, 0x3e, - 0xab, 0xb0, 0x85, 0xea, 0x6d, 0x0a, 0xad, 0x98, 0x45, 0x92, 0x09, 0xae, 0x2f, 0xa8, 0x66, 0x7e, - 0x0b, 0x1b, 0xa8, 0x1a, 0x12, 0x4e, 0x7c, 0x1a, 0x83, 0x5e, 0xb1, 0xca, 0xf6, 0x92, 0x37, 0xae, - 0xf1, 0x2e, 0x5a, 0x23, 0x41, 0x20, 0xfa, 0x4d, 0x4e, 0xfb, 0x4d, 0x3a, 0x90, 0x94, 0x03, 0x13, - 0x1c, 0xf4, 0xaa, 0xa5, 0xd9, 0x55, 0x0f, 0xab, 0xde, 0x3b, 0xda, 0x7f, 0x3b, 0xee, 0xe0, 0x6d, - 0xb4, 0x3a, 0xc1, 0x35, 0x03, 0x06, 0x52, 0xaf, 0x59, 0x65, 0xbb, 0xe6, 0xad, 0x4c, 0xb6, 0x4f, - 0x19, 0x48, 0x7c, 0x84, 0x50, 0x48, 0x06, 0x4d, 0xe8, 0x45, 0x51, 0x30, 0xd4, 0x51, 0xe2, 0xeb, - 0xf8, 0xf9, 0xd5, 0xcd, 0x56, 0xe9, 0xf7, 0xcd, 0xd6, 0xff, 0x69, 0x7c, 0xd0, 0xee, 0x3a, 0x4c, - 0xb8, 0x21, 0x91, 0x1d, 0xe7, 0x84, 0x4b, 0xaf, 0x16, 0x92, 0xc1, 0x07, 0x85, 0x3f, 0xac, 0x7f, - 0xbb, 0xbf, 0xdc, 0xc9, 0x92, 0x6a, 0x1c, 0xa0, 0xf5, 0x62, 0xa6, 0x1e, 0x85, 0x48, 0x70, 0xa0, - 0x78, 0x13, 0x55, 0xd5, 0x8d, 0x35, 0x59, 0x5b, 0xa5, 0x5b, 0xf3, 0x16, 0x55, 0x7d, 0xd2, 0x6e, - 0x04, 0xea, 0x22, 0x5e, 0x03, 0x30, 0x9f, 0x7b, 0x22, 0xa0, 0x30, 0xf5, 0x22, 0xf2, 0x24, 0x73, - 0x05, 0x92, 0x42, 0x76, 0xe5, 0x62, 0x76, 0x45, 0x8b, 0xba, 0xb2, 0x98, 0x53, 0x1b, 0x59, 0x6c, - 0x70, 0xf4, 0xdf, 0x19, 0xf8, 0x9f, 0x38, 0xf9, 0x97, 0x4e, 0xb4, 0xe9, 0x4e, 0x0c, 0xa4, 0x3f, - 0xd4, 0x1b, 0x7b, 0xf9, 0x82, 0x56, 0x93, 0x5e, 0xd4, 0x26, 0x92, 0xbe, 0x57, 0xe3, 0x80, 0x9f, - 0xa1, 0x1a, 0xe9, 0xc9, 0x8e, 0x88, 0x99, 0x1c, 0x66, 0x11, 0x4e, 0x36, 0xf0, 0x11, 0xaa, 0xa4, - 0x63, 0xa3, 0xec, 0xd4, 0xf7, 0x4d, 0xe7, 0xf1, 0x51, 0x74, 0x52, 0xb6, 0xe3, 0xf9, 0xe4, 0x82, - 0xbd, 0xec, 0xcc, 0xe1, 0x4a, 0xe2, 0x6b, 0xc2, 0xd6, 0xd8, 0x44, 0x1b, 0x0f, 0xe4, 0x47, 0xce, - 0xf6, 0x7f, 0x94, 0x51, 0xf9, 0x0c, 0x7c, 0xdc, 0x41, 0x4b, 0x05, 0x7b, 0xdb, 0xd3, 0x04, 0x1f, - 0x10, 0x19, 0xee, 0x13, 0x81, 0xe3, 0xa7, 0x43, 0x51, 0x3d, 0x3f, 0xa5, 0x2f, 0x67, 0x9c, 0xcf, - 0xe1, 0x0c, 0xe7, 0x69, 0xb8, 0xbc, 0x4c, 0xfe, 0x0d, 0xce, 0x92, 0xc9, 0xe1, 0x66, 0xca, 0x3c, - 0xf2, 0xca, 0x70, 0x17, 0x2d, 0x17, 0x9f, 0x98, 0x3d, 0x2b, 0x8f, 0x3c, 0xd2, 0xd8, 0x7d, 0x2a, - 0x72, 0x24, 0x66, 0x2c, 0x7c, 0xbd, 0xbf, 0xdc, 0xd1, 0x8e, 0x4f, 0xaf, 0x6e, 0x4d, 0xed, 0xfa, - 0xd6, 0xd4, 0xfe, 0xdc, 0x9a, 0xda, 0xf7, 0x3b, 0xb3, 0x74, 0x7d, 0x67, 0x96, 0x7e, 0xdd, 0x99, - 0xa5, 0xcf, 0xfb, 0x3e, 0x93, 0x9d, 0xde, 0xb9, 0xd3, 0x12, 0xa1, 0x9b, 0x92, 0x4b, 0xda, 0xea, - 0x64, 0xcb, 0x57, 0xa3, 0x4f, 0x77, 0x90, 0x7d, 0xbb, 0x72, 0x18, 0x51, 0x38, 0xaf, 0xa8, 0x0f, - 0xf4, 0xe0, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5a, 0xa7, 0x7c, 0xb3, 0x0e, 0x06, 0x00, 0x00, + 0x0e, 0x9c, 0x28, 0x16, 0x52, 0xe0, 0xf5, 0x02, 0xc1, 0x51, 0x04, 0xe7, 0x62, 0xcf, 0x58, 0xf3, + 0x85, 0x2f, 0x14, 0xc5, 0x4d, 0x56, 0x29, 0xdb, 0x78, 0x31, 0x45, 0x2e, 0x22, 0x31, 0x09, 0x21, + 0x23, 0x35, 0xa6, 0x79, 0x8a, 0x2e, 0xe5, 0x19, 0x67, 0xb3, 0x25, 0x20, 0x14, 0xd0, 0x4c, 0x1d, + 0x52, 0x90, 0x95, 0x36, 0x52, 0xe4, 0x86, 0xe0, 0x27, 0xa7, 0x42, 0xf0, 0xd3, 0x42, 0xe3, 0xe7, + 0x1c, 0x5a, 0x39, 0x03, 0xff, 0x4d, 0x4c, 0x89, 0xa4, 0x1f, 0x13, 0x31, 0xbc, 0x8e, 0x2a, 0x0c, + 0xa0, 0x47, 0x63, 0x5d, 0xb3, 0x34, 0x7b, 0xc9, 0xcb, 0x10, 0xc6, 0x68, 0x9e, 0x93, 0x90, 0xea, + 0x73, 0x96, 0x66, 0xd7, 0x3c, 0xb5, 0xc6, 0x3a, 0x5a, 0x6c, 0xd3, 0x16, 0x0b, 0x49, 0xa0, 0x97, + 0x2d, 0xcd, 0x5e, 0xf6, 0x46, 0x30, 0x51, 0x81, 0x61, 0x78, 0x2e, 0x02, 0x7d, 0x5e, 0xf1, 0x33, + 0x84, 0x2d, 0x54, 0x6f, 0x53, 0x68, 0xc5, 0x2c, 0x92, 0x4c, 0x70, 0x7d, 0x41, 0x15, 0xf3, 0x5b, + 0xd8, 0x40, 0xd5, 0x90, 0x70, 0xe2, 0xd3, 0x18, 0xf4, 0x8a, 0x55, 0xb6, 0x97, 0xbc, 0x31, 0xc6, + 0xbb, 0x68, 0x8d, 0x04, 0x81, 0xe8, 0x37, 0x39, 0xed, 0x37, 0xe9, 0x40, 0x52, 0x0e, 0x4c, 0x70, + 0xd0, 0xab, 0x96, 0x66, 0x57, 0x3d, 0xac, 0x6a, 0xef, 0x68, 0xff, 0xed, 0xb8, 0x82, 0xb7, 0xd1, + 0xea, 0x84, 0xd7, 0x0c, 0x18, 0x48, 0xbd, 0x66, 0x95, 0xed, 0x9a, 0xb7, 0x32, 0xd9, 0x3e, 0x65, + 0x20, 0xf1, 0x11, 0x42, 0x21, 0x19, 0x34, 0xa1, 0x17, 0x45, 0xc1, 0x50, 0x47, 0x49, 0xae, 0xe3, + 0xe7, 0x57, 0x37, 0x5b, 0xa5, 0xdf, 0x37, 0x5b, 0xff, 0xa7, 0xed, 0x83, 0x76, 0xd7, 0x61, 0xc2, + 0x0d, 0x89, 0xec, 0x38, 0x27, 0x5c, 0x7a, 0xb5, 0x90, 0x0c, 0x3e, 0x28, 0xfe, 0x61, 0xfd, 0xdb, + 0xfd, 0xe5, 0x4e, 0xd6, 0xa9, 0xc6, 0x01, 0x5a, 0x2f, 0xf6, 0xd4, 0xa3, 0x10, 0x09, 0x0e, 0x14, + 0x6f, 0xa2, 0xaa, 0xba, 0xb1, 0x26, 0x6b, 0xab, 0xee, 0xd6, 0xbc, 0x45, 0x85, 0x4f, 0xda, 0x8d, + 0x40, 0x5d, 0xc4, 0x6b, 0x00, 0xe6, 0x73, 0x4f, 0x04, 0x14, 0xa6, 0x5e, 0x44, 0x5e, 0x64, 0xae, + 0x20, 0x52, 0xe8, 0x5d, 0x59, 0x1d, 0x1a, 0xe3, 0x62, 0x44, 0x5d, 0x45, 0xcc, 0xb9, 0x8d, 0x22, + 0x36, 0x38, 0xfa, 0xef, 0x0c, 0xfc, 0x4f, 0x9c, 0xfc, 0xa3, 0x24, 0x06, 0xd2, 0x1f, 0xfa, 0x8d, + 0xb3, 0x7c, 0x41, 0xab, 0x49, 0x2d, 0x6a, 0x13, 0x49, 0xdf, 0xab, 0x71, 0xc0, 0xcf, 0x50, 0x8d, + 0xf4, 0x64, 0x47, 0xc4, 0x4c, 0x0e, 0xb3, 0x16, 0x4e, 0x36, 0xf0, 0x11, 0xaa, 0xa4, 0x63, 0xa3, + 0xe2, 0xd4, 0xf7, 0x4d, 0xe7, 0xf1, 0x51, 0x74, 0x52, 0xb5, 0xe3, 0xf9, 0xe4, 0x82, 0xbd, 0xec, + 0xcc, 0xe1, 0x4a, 0x92, 0x6b, 0xa2, 0xd6, 0xd8, 0x44, 0x1b, 0x0f, 0xec, 0x47, 0xc9, 0xf6, 0x7f, + 0x94, 0x51, 0xf9, 0x0c, 0x7c, 0xdc, 0x41, 0x4b, 0x85, 0x78, 0xdb, 0xd3, 0x0c, 0x1f, 0x08, 0x19, + 0xee, 0x13, 0x89, 0xe3, 0xa7, 0x43, 0x51, 0x3d, 0x3f, 0xa5, 0x2f, 0x67, 0x9c, 0xcf, 0xf1, 0x0c, + 0xe7, 0x69, 0xbc, 0xbc, 0x4d, 0xfe, 0x0d, 0xce, 0xb2, 0xc9, 0xf1, 0x66, 0xda, 0x3c, 0xf2, 0xca, + 0x70, 0x17, 0x2d, 0x17, 0x9f, 0x98, 0x3d, 0xab, 0x1f, 0x79, 0xa6, 0xb1, 0xfb, 0x54, 0xe6, 0xc8, + 0xcc, 0x58, 0xf8, 0x7a, 0x7f, 0xb9, 0xa3, 0x1d, 0x9f, 0x5e, 0xdd, 0x9a, 0xda, 0xf5, 0xad, 0xa9, + 0xfd, 0xb9, 0x35, 0xb5, 0xef, 0x77, 0x66, 0xe9, 0xfa, 0xce, 0x2c, 0xfd, 0xba, 0x33, 0x4b, 0x9f, + 0xf7, 0x7d, 0x26, 0x3b, 0xbd, 0x73, 0xa7, 0x25, 0x42, 0x37, 0x15, 0x97, 0xb4, 0xd5, 0xc9, 0x96, + 0xaf, 0x46, 0x9f, 0xee, 0x20, 0xfb, 0x76, 0xe5, 0x30, 0xa2, 0x70, 0x5e, 0x51, 0x1f, 0xe8, 0xc1, + 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0b, 0xc2, 0xbd, 0xcf, 0x0e, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -857,13 +857,11 @@ func (m *MsgAssignRoles) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if len(m.Managers) > 0 { - for iNdEx := len(m.Managers) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Managers[iNdEx]) - copy(dAtA[i:], m.Managers[iNdEx]) - i = encodeVarintTx(dAtA, i, uint64(len(m.Managers[iNdEx]))) - i-- - dAtA[i] = 0x1a - } + i -= len(m.Managers) + copy(dAtA[i:], m.Managers) + i = encodeVarintTx(dAtA, i, uint64(len(m.Managers))) + i-- + dAtA[i] = 0x1a } if len(m.TokenId) > 0 { i -= len(m.TokenId) @@ -1118,11 +1116,9 @@ func (m *MsgAssignRoles) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if len(m.Managers) > 0 { - for _, b := range m.Managers { - l = len(b) - n += 1 + l + sovTx(uint64(l)) - } + l = len(m.Managers) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) } return n } @@ -1719,8 +1715,10 @@ func (m *MsgAssignRoles) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Managers = append(m.Managers, make([]byte, postIndex-iNdEx)) - copy(m.Managers[len(m.Managers)-1], dAtA[iNdEx:postIndex]) + m.Managers = append(m.Managers[:0], dAtA[iNdEx:postIndex]...) + if m.Managers == nil { + m.Managers = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex
    2. LFY&ZBrBzz-L?f!!E@LfC2}^CnlC2;-R&D5 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