Skip to content

Commit

Permalink
(feat) Documentation
Browse files Browse the repository at this point in the history
(feat) Make zrc_proxy and decimals immutable
(feat) Pass on the result of gas() and not 21000
(feat) Burnable ERC20s
(feat) Tests for ERC20 proxy contract.
(feat) Deployment for ERC20 proxy is now via task and auto-verifies the contract
  • Loading branch information
rrw-zilliqa committed Aug 30, 2024
1 parent 3e37cc5 commit 09bf0e0
Show file tree
Hide file tree
Showing 17 changed files with 6,180 additions and 1,023 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "contracts/experimental/ERC20ProxyForZRC2/lib/openzeppelin-contracts"]
path = contracts/experimental/ERC20ProxyForZRC2/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
1 change: 0 additions & 1 deletion contracts/experimental/ERC20ProxyForZRC2/.env.example

This file was deleted.

67 changes: 55 additions & 12 deletions contracts/experimental/ERC20ProxyForZRC2/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,64 @@
# ERC20ProxyForZRC2 Contract

Check failure on line 1 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

prettier

Incorrect formatting, autoformat by running 'trunk fmt'

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.
These contracts allow ZRC-2 tokens to look like ERC-20 tokens.

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.
Unless you want to build using the `zilliqa-developer` version of `zilliqa-js`, install our dependencies with:

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
```shell
pnpm --ignore-workspace i
```

The following are the deployment commands:
## Deploying a proxy

- Zilliqa Mainnet
You can deploy a proxy with:

```shell
pnpm exec hardhat run scripts/deploy.ts --network zq
```
```shell
export PRIVATE_KEY=<...>
pnpm exec hardhat deployProxy 0x5DD38E64dA8f7d541d8aF45fe00bF37F6a2c6195 --network zq-testnet
```

- Zilliqa Testnet
If your ZRC-2 is burnable (ie. supports the `Burn()` transition), you can use:

```shell
pnpm exec hardhat run scripts/deploy.ts --network zq-testnet
```
```shell
export PRIVATE_KEY=<...>
pnpm exec hardhat deployProxyBurnable 0x5DD38E64dA8f7d541d8aF45fe00bF37F6a2c6195 --network zq-testnet
```

The task should automatically verify these contracts to sourcify.


Check notice on line 29 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

markdownlint(MD012)

[new] Multiple consecutive blank lines
## Networks

Various networks are available in the `hardhat.conf.ts`:

* `zq-testnet` - the Zilliqa 1 testnet

Check notice on line 34 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

markdownlint(MD007)

[new] Unordered list indentation
* `zq` - the Zilliqa 1 mainnet

Check notice on line 35 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

markdownlint(MD007)

[new] Unordered list indentation
* `local-proxy` - a local proxy.

Check notice on line 36 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

markdownlint(MD007)

[new] Unordered list indentation

Check notice on line 37 in contracts/experimental/ERC20ProxyForZRC2/README.md

View workflow job for this annotation

GitHub Actions / Trunk Check

markdownlint(MD009)

[new] Trailing spaces
You can use the `local-proxy` network and run:

```sh
mitmweb --mode reverse:https://dev-api.zilliqa.com --no-web-open-browser --listen-port 5556 --web-port 5557
```

To monitor requests.

## Testing

To run the tests:

```shell
export PRIVATE_KEY=<...>
export TEST_KEY_1=<...>
export TEST_KEY_2=<...>
pnpm exec hardhat test --network zq-testnet
```

Each test has a number prefix so you can select them individually.

If you set the `CACHED` environment variable, we will use a built-in
cached contract deployment whose addresses appear in the source -
please update it if you change the contracts.

This allows you to run tests quickly, without waiting for contract
deployment.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@ library ScillaConnector {
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
*/
function callu128(
address target,
string memory tran_name,
uint128 arg1
) internal {
bytes memory encodedArgs = abi.encode(
target,
tran_name,
CALL_SCILLA_WITH_THE_SAME_SENDER,
arg1
);
uint256 argsLength = encodedArgs.length;

assembly {
let alwaysSuccessForThisPrecompile := call(
gas(),
SCILLA_CALL_PRECOMPILE_ADDRESS,
0,
add(encodedArgs, 0x20),
argsLength,
0x20,
0
)
}
}


/**
* @dev Calls a ZRC2 contract function with two arguments
* @param target The address of the ZRC2 contract
Expand All @@ -30,7 +63,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := call(
21000,
gas(),
SCILLA_CALL_PRECOMPILE_ADDRESS,
0,
add(encodedArgs, 0x20),
Expand Down Expand Up @@ -68,7 +101,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := call(
21000,
gas(),
SCILLA_CALL_PRECOMPILE_ADDRESS,
0,
add(encodedArgs, 0x20),
Expand All @@ -95,7 +128,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := staticcall(
21000,
gas(),
SCILLA_STATE_READ_PRECOMPILE_ADDRESS,
add(encodedArgs, 0x20),
argsLength,
Expand Down Expand Up @@ -123,7 +156,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := staticcall(
21000,
gas(),
SCILLA_STATE_READ_PRECOMPILE_ADDRESS,
add(encodedArgs, 0x20),
argsLength,
Expand Down Expand Up @@ -152,7 +185,7 @@ library ScillaConnector {
uint256 output_len = output.length - 4;
assembly {
success := staticcall(
21000,
gas(),
SCILLA_STATE_READ_PRECOMPILE_ADDRESS,
add(encodedArgs, 0x20),
argsLength,
Expand Down Expand Up @@ -187,7 +220,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := staticcall(
21000,
gas(),
SCILLA_STATE_READ_PRECOMPILE_ADDRESS,
add(encodedArgs, 0x20),
argsLength,
Expand Down Expand Up @@ -224,7 +257,7 @@ library ScillaConnector {

assembly {
let alwaysSuccessForThisPrecompile := staticcall(
21000,
gas(),
SCILLA_STATE_READ_PRECOMPILE_ADDRESS,
add(encodedArgs, 0x20),
argsLength,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {ScillaConnector} from "./ScillaConnector.sol";

contract ZRC2ProxyForZRC2 is IERC20 {
contract ZRC2ERC20Proxy is IERC20 {
using ScillaConnector for address;
using SafeCast for uint256;

address public zrc2_proxy;
address immutable public zrc2_proxy;

// Additional variables useful for wallets
uint8 public decimals;
uint8 immutable public decimals;
string public symbol;
string public name;

Expand Down Expand Up @@ -56,6 +56,15 @@ contract ZRC2ProxyForZRC2 is IERC20 {
return true;
}

function _transferFrom(
address from,
address to,
uint256 tokens
) internal returns (bool) {
zrc2_proxy.call("TransferFrom", from, to, tokens.toUint128());
return true;
}

/**
* @notice Transfer tokens from one address to another
* @param from The address to transfer from
Expand All @@ -68,7 +77,7 @@ contract ZRC2ProxyForZRC2 is IERC20 {
address to,
uint256 tokens
) external returns (bool) {
zrc2_proxy.call("TransferFrom", from, to, tokens.toUint128());
_transferFrom(from, to, tokens);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {ScillaConnector} from "./ScillaConnector.sol";
import {ZRC2ERC20Proxy} from "./ZRC2ERC20Proxy.sol";

contract ZRC2ERC20ProxyBurnable is ZRC2ERC20Proxy {
using ScillaConnector for address;
using SafeCast for uint256;

/** Just chains down to the base constructor */
constructor(address zrc2_address) ZRC2ERC20Proxy(zrc2_address) { }

/**
* @dev Destroys a `value` amount of tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) public virtual {
uint128 value128 = value.toUint128();
zrc2_proxy.callu128("Burn", value128);
}

/**
* @dev Destroys a `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) public virtual {
address self = address(msg.sender);

_transferFrom(account, self, value);
burn(value);
}
}
Loading

0 comments on commit 09bf0e0

Please sign in to comment.