-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ZIL-5536: New ERC20ProxyForZRC2 contract example (#351)
* ERC2ProxyForZRC2 * Update readme * update bazelignore
- Loading branch information
Showing
12 changed files
with
2,886 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
PRIVATE-KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
node_modules | ||
.env | ||
|
||
# Hardhat files | ||
/cache | ||
/artifacts | ||
|
||
# TypeChain files | ||
/typechain | ||
/typechain-types | ||
|
||
# solidity-coverage files | ||
/coverage | ||
/coverage.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# ERC20ProxyForZRC2 Contract | ||
|
||
This is the contract to deploy a ERC20Proxy for a ZRC2 contract living in the scilla environment. It leverages the precompiles available in Zilliqa to interoperate between the 2 environments. | ||
|
||
Make sure to specify the `zrc2_address` on the deployment file for the ERC20Proxy to be correctly deployed. This allows EVM to execute all desired functions on the ZRC2 as if it were a ERC20. Implementing IERC20 means that all existing DApps and wallets should be compatible with this token. | ||
|
||
Make sure to also copy `.env.example` into `.env` and fill in the necessarily variables. Also ensure that `pnpm install` to install any necessary dependencies | ||
|
||
The following are the deployment commands: | ||
|
||
- Zilliqa Mainnet | ||
|
||
```shell | ||
pnpm exec hardhat run scripts/deploy.ts --network zq | ||
``` | ||
|
||
- Zilliqa Testnet | ||
|
||
```shell | ||
pnpm exec hardhat run scripts/deploy.ts --network zq-testnet | ||
``` |
238 changes: 238 additions & 0 deletions
238
contracts/experimental/ERC20ProxyForZRC2/contracts/ScillaConnector.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity ^0.8.20; | ||
|
||
library ScillaConnector { | ||
uint private constant CALL_SCILLA_WITH_THE_SAME_SENDER = 1; | ||
uint private constant SCILLA_CALL_PRECOMPILE_ADDRESS = 0x5a494c53; | ||
uint private constant SCILLA_STATE_READ_PRECOMPILE_ADDRESS = 0x5a494c92; | ||
|
||
/** | ||
* @dev Calls a ZRC2 contract function with two arguments | ||
* @param target The address of the ZRC2 contract | ||
* @param tran_name The name of the function to call | ||
* @param arg1 The first argument to the function | ||
* @param arg2 The second argument to the function | ||
*/ | ||
function call( | ||
address target, | ||
string memory tran_name, | ||
address arg1, | ||
uint128 arg2 | ||
) internal { | ||
bytes memory encodedArgs = abi.encode( | ||
target, | ||
tran_name, | ||
CALL_SCILLA_WITH_THE_SAME_SENDER, | ||
arg1, | ||
arg2 | ||
); | ||
uint256 argsLength = encodedArgs.length; | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := call( | ||
21000, | ||
SCILLA_CALL_PRECOMPILE_ADDRESS, | ||
0, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
0x20, | ||
0 | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Calls a ZRC2 contract function with three arguments | ||
* @param target The address of the ZRC2 contract | ||
* @param tran_name The name of the function to call on the ZRC2 contract | ||
* @param arg1 The first argument to the function | ||
* @param arg2 The second argument to the function | ||
* @param arg3 The third argument to the function | ||
*/ | ||
function call( | ||
address target, | ||
string memory tran_name, | ||
address arg1, | ||
address arg2, | ||
uint128 arg3 | ||
) internal { | ||
bytes memory encodedArgs = abi.encode( | ||
target, | ||
tran_name, | ||
CALL_SCILLA_WITH_THE_SAME_SENDER, | ||
arg1, | ||
arg2, | ||
arg3 | ||
); | ||
uint256 argsLength = encodedArgs.length; | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := call( | ||
21000, | ||
SCILLA_CALL_PRECOMPILE_ADDRESS, | ||
0, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
0x20, | ||
0 | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* @dev Reads a 128 bit integer from a ZRC2 contract | ||
* @param target The address of the ZRC2 contract | ||
* @param variable_name The name of the variable to read from the ZRC2 contract | ||
* @return The value of the variable | ||
*/ | ||
function readUint128( | ||
address target, | ||
string memory variable_name | ||
) internal view returns (uint128) { | ||
bytes memory encodedArgs = abi.encode(target, variable_name); | ||
uint256 argsLength = encodedArgs.length; | ||
bytes memory output = new bytes(36); | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := staticcall( | ||
21000, | ||
SCILLA_STATE_READ_PRECOMPILE_ADDRESS, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
add(output, 0x20), | ||
32 | ||
) | ||
} | ||
|
||
return abi.decode(output, (uint128)); | ||
} | ||
|
||
/** | ||
* @dev Reads a 32 bit integer from a ZRC2 contract | ||
* @param target The address of the ZRC2 contract | ||
* @param variable_name The name of the variable to read from the ZRC2 contract | ||
* @return The value of the variable | ||
*/ | ||
function readUint32( | ||
address target, | ||
string memory variable_name | ||
) internal view returns (uint32) { | ||
bytes memory encodedArgs = abi.encode(target, variable_name); | ||
uint256 argsLength = encodedArgs.length; | ||
bytes memory output = new bytes(36); | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := staticcall( | ||
21000, | ||
SCILLA_STATE_READ_PRECOMPILE_ADDRESS, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
add(output, 0x20), | ||
32 | ||
) | ||
} | ||
|
||
return abi.decode(output, (uint32)); | ||
} | ||
|
||
/** | ||
* @dev Reads a string from a ZRC2 contract | ||
* @param target The address of the ZRC2 contract | ||
* @param variable_name The name of the variable to read from the ZRC2 contract | ||
* @return retVal The value of the variable | ||
*/ | ||
function readString( | ||
address target, | ||
string memory variable_name | ||
) internal view returns (string memory retVal) { | ||
bytes memory encodedArgs = abi.encode(target, variable_name); | ||
uint256 argsLength = encodedArgs.length; | ||
bool success; | ||
bytes memory output = new bytes(128); | ||
uint256 output_len = output.length - 4; | ||
assembly { | ||
success := staticcall( | ||
21000, | ||
SCILLA_STATE_READ_PRECOMPILE_ADDRESS, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
add(output, 0x20), | ||
output_len | ||
) | ||
} | ||
require(success); | ||
|
||
(retVal) = abi.decode(output, (string)); | ||
return retVal; | ||
} | ||
|
||
/** | ||
* @dev Reads a 128 bit integer from a map in a ZRC2 contract | ||
* @param variable_name The name of the map in the ZRC2 contract | ||
* @param addressMapKey The key to the map | ||
* @return The value associated with the key in the map | ||
*/ | ||
function readMapUint128( | ||
address target, | ||
string memory variable_name, | ||
address addressMapKey | ||
) internal view returns (uint128) { | ||
bytes memory encodedArgs = abi.encode( | ||
target, | ||
variable_name, | ||
addressMapKey | ||
); | ||
uint256 argsLength = encodedArgs.length; | ||
bytes memory output = new bytes(36); | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := staticcall( | ||
21000, | ||
SCILLA_STATE_READ_PRECOMPILE_ADDRESS, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
add(output, 0x20), | ||
32 | ||
) | ||
} | ||
|
||
return abi.decode(output, (uint128)); | ||
} | ||
|
||
/** | ||
* @dev Reads a 128 bit integer from a nested map in a ZRC2 contract | ||
* @param target The address of the ZRC2 contract | ||
* @param variable_name The name of the map in the ZRC2 contract | ||
* @param firstMapKey The first key to the map | ||
* @param secondMapKey The second key to the map | ||
* @return The value associated with the keys in the map | ||
*/ | ||
function readNestedMapUint128( | ||
address target, | ||
string memory variable_name, | ||
address firstMapKey, | ||
address secondMapKey | ||
) internal view returns (uint128) { | ||
bytes memory encodedArgs = abi.encode( | ||
target, | ||
variable_name, | ||
firstMapKey, | ||
secondMapKey | ||
); | ||
uint256 argsLength = encodedArgs.length; | ||
bytes memory output = new bytes(36); | ||
|
||
assembly { | ||
let alwaysSuccessForThisPrecompile := staticcall( | ||
21000, | ||
SCILLA_STATE_READ_PRECOMPILE_ADDRESS, | ||
add(encodedArgs, 0x20), | ||
argsLength, | ||
add(output, 0x20), | ||
32 | ||
) | ||
} | ||
|
||
return abi.decode(output, (uint128)); | ||
} | ||
} |
Oops, something went wrong.