Skip to content

Commit

Permalink
feat: new deployment script (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xGorilla authored Dec 18, 2023
1 parent 1739e9d commit 76d582b
Show file tree
Hide file tree
Showing 27 changed files with 405 additions and 353 deletions.
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
branch = master
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/brockelmore/forge-std
branch = master
url = https://github.com/foundry-rs/forge-std
branch = v1.7.3
[submodule "lib/prb-test"]
path = lib/prb-test
url = https://github.com/paulrberg/prb-test
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,16 @@ Example:

You will need to set your custom `name` and `symbol` for your XERC20 to be deployed, no need to add an 'x' infront of it, the contract will do that for you. For more details check the section below.


## Setup Guide to Deploy an xERC20 Token

This guide provides a detailed, step-by-step process to deploy an xERC20 token using this repository. We will first demonstrate how to deploy the xERC20 token alone, and then we’ll cover the scenario in which you want to deploy both the xERC20 token and the lockbox.

## Deploying xERC20 Without the Lockbox

> [!IMPORTANT]
> Verifying contracts deployed with --via-ir is not working correctly with Foundry.
> Read the following post for a solution: https://github.com/foundry-rs/foundry/issues/3507#issuecomment-1465382107
### 1. Navigate to the MultichainCreateXERC20 Script

Locate and open the `MultichainCreateXERC20.sol` file, which should be situated within the `solidity/scripts` directory.
Expand Down Expand Up @@ -221,3 +224,4 @@ Now broadcast it and you are good to go.
The deployments are stored in ./broadcast

See the [Foundry Book for available options](https://book.getfoundry.sh/reference/forge/forge-create.html).

38 changes: 11 additions & 27 deletions broadcast/MultichainDeploy.sol/1/run-latest.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions broadcast/MultichainDeploy.sol/10/run-latest.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions broadcast/MultichainDeploy.sol/100/run-latest.json

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions broadcast/MultichainDeploy.sol/137/run-latest.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions broadcast/MultichainDeploy.sol/420/run-latest.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions broadcast/MultichainDeploy.sol/42161/run-latest.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions broadcast/MultichainDeploy.sol/421613/run-latest.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions broadcast/MultichainDeploy.sol/5/run-latest.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions broadcast/MultichainDeploy.sol/56/run-latest.json

Large diffs are not rendered by default.

52 changes: 43 additions & 9 deletions broadcast/MultichainDeploy.sol/80001/run-latest.json

Large diffs are not rendered by default.

24 changes: 11 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"version": "1.0.0",
"private": true,
"description": "Production ready Solidity boilerplate with Foundry",
"homepage": "https://github.com/defi-wonderland/solidity-foundry-boilerplate#readme",
"homepage": "https://github.com/defi-wonderland/xERC20#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/defi-wonderland/solidity-foundry-boilerplate.git"
"url": "git+https://github.com/defi-wonderland/xERC20.git"
},
"license": "MIT",
"author": "Wonderland",
Expand All @@ -16,25 +16,23 @@
"gas1cent (https://github.com/gas1cent)"
],
"scripts": {
"build": "forge build",
"build": "forge build --via-ir",
"build:optimized": "FOUNDRY_PROFILE=optimized forge build",
"coverage": "forge coverage --match-contract Unit",
"deploy:mainnet": "bash -c 'source .env && forge script DeployMainnet --rpc-url $MAINNET_RPC --broadcast --private-key $MAINNET_DEPLOYER_PK --verify --etherscan-api-key $ETHERSCAN_API_KEY'",
"deploy:rinkeby": "bash -c 'source .env && forge script DeployRinkeby --rpc-url $RINKEBY_RPC --broadcast --private-key $RINKEBY_DEPLOYER_PK --verify --etherscan-api-key $ETHERSCAN_API_KEY'",
"postinstall": "forge install",
"lint:check": "yarn lint:sol-tests && yarn lint:sol-logic && forge fmt check",
"lint:fix": "sort-package-json && forge fmt && yarn lint:sol-tests --fix && yarn lint:sol-logic --fix",
"lint:sol-logic": "solhint 'solidity/contracts/**/*.sol' 'solidity/interfaces/**/*.sol'",
"lint:sol-tests": "solhint -c .solhint.tests.json 'solidity/test/**/*.sol'",
"prepare": "husky install",
"script:DeployFactory": "forge script solidity/scripts/MultichainDeploy.sol:MultichainDeploy --legacy",
"script:DeployFactory:broadcast": "forge script solidity/scripts/MultichainDeploy.sol:MultichainDeploy --legacy --broadcast --verify --slow",
"script:DeployXERC20": "forge script solidity/scripts/MultichainCreateXERC20.sol:MultichainCreateXERC20 --legacy",
"script:DeployXERC20:broadcast": "forge script solidity/scripts/MultichainCreateXERC20.sol:MultichainCreateXERC20 --legacy --broadcast --verify --slow",
"test": "forge test -vvv",
"test:e2e": "forge test --match-contract E2E -vvv",
"test:unit": "forge test --match-contract Unit -vvv",
"test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit"
"script:DeployFactory": "forge script solidity/scripts/XERC20FactoryDeploy.sol:XERC20FactoryDeploy --legacy --via-ir",
"script:DeployFactory:broadcast": "forge script solidity/scripts/XERC20FactoryDeploy.sol:XERC20FactoryDeploy --legacy --broadcast --verify --slow --via-ir",
"script:DeployXERC20": "forge script solidity/scripts/XERC20Deploy.sol:XERC20Deploy --legacy --via-ir",
"script:DeployXERC20:broadcast": "forge script solidity/scripts/XERC20Deploy.sol:XERC20Deploy --legacy --broadcast --verify --slow --via-ir",
"test": "forge test -vvv --via-ir",
"test:e2e": "forge test --match-contract E2E -vvv --via-ir",
"test:unit": "forge test --match-contract Unit -vvv --via-ir",
"test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit --via-ir"
},
"lint-staged": {
"*.{js,css,md,ts,sol}": "forge fmt",
Expand Down
15 changes: 9 additions & 6 deletions solidity/contracts/XERC20Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,25 @@ contract XERC20Factory is IXERC20Factory {
/**
* @notice Deploys an XERC20Lockbox contract using CREATE3
*
* @dev When deploying a lockbox for the gas token of the chain, then, the base token needs to be address(0)
* @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for
* @param _baseToken The address of the base token that you want to lock
* @param _isNative Whether or not the base token is native
* @param _isGasToken Whether or not the base token is the native (gas) token of the chain. Eg: MATIC for polygon chain
*/

function deployLockbox(
address _xerc20,
address _baseToken,
bool _isNative
bool _isGasToken
) external returns (address payable _lockbox) {
if (_baseToken == address(0) && !_isNative) revert IXERC20Factory_BadTokenAddress();
if ((_baseToken == address(0) && !_isGasToken) || (_isGasToken && _baseToken != address(0))) {
revert IXERC20Factory_BadTokenAddress();
}

if (XERC20(_xerc20).owner() != msg.sender) revert IXERC20Factory_NotOwner();
if (_lockboxRegistry[_xerc20] != address(0)) revert IXERC20Factory_LockboxAlreadyDeployed();

_lockbox = _deployLockbox(_xerc20, _baseToken, _isNative);
_lockbox = _deployLockbox(_xerc20, _baseToken, _isGasToken);

emit LockboxDeployed(_lockbox);
}
Expand Down Expand Up @@ -109,11 +112,11 @@ contract XERC20Factory is IXERC20Factory {
function _deployLockbox(
address _xerc20,
address _baseToken,
bool _isNative
bool _isGasToken
) internal returns (address payable _lockbox) {
bytes32 _salt = keccak256(abi.encodePacked(_xerc20, _baseToken, msg.sender));
bytes memory _creation = type(XERC20Lockbox).creationCode;
bytes memory _bytecode = abi.encodePacked(_creation, abi.encode(_xerc20, _baseToken, _isNative));
bytes memory _bytecode = abi.encodePacked(_creation, abi.encode(_xerc20, _baseToken, _isGasToken));

_lockbox = payable(CREATE3.deploy(_salt, _bytecode, 0));

Expand Down
25 changes: 13 additions & 12 deletions solidity/contracts/XERC20Lockbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,28 @@ contract XERC20Lockbox is IXERC20Lockbox {
* @notice Whether the ERC20 token is the native gas token of this chain
*/

bool public immutable IS_NATIVE;
bool public immutable IS_GAS_TOKEN;

/**
* @notice Constructor
*
* @param _xerc20 The address of the XERC20 contract
* @param _erc20 The address of the ERC20 contract
* @param _isGasToken Whether the ERC20 token is the native gas token of this chain or not
*/

constructor(address _xerc20, address _erc20, bool _isNative) {
constructor(address _xerc20, address _erc20, bool _isGasToken) {
XERC20 = IXERC20(_xerc20);
ERC20 = IERC20(_erc20);
IS_NATIVE = _isNative;
IS_GAS_TOKEN = _isGasToken;
}

/**
* @notice Deposit native tokens into the lockbox
*/

function depositNative() public payable {
if (!IS_NATIVE) revert IXERC20Lockbox_NotNative();
function depositGasToken() public payable {
if (!IS_GAS_TOKEN) revert IXERC20Lockbox_NotGasToken();

_deposit(msg.sender, msg.value);
}
Expand All @@ -57,7 +58,7 @@ contract XERC20Lockbox is IXERC20Lockbox {
*/

function deposit(uint256 _amount) external {
if (IS_NATIVE) revert IXERC20Lockbox_Native();
if (IS_GAS_TOKEN) revert IXERC20Lockbox_GasToken();

_deposit(msg.sender, _amount);
}
Expand All @@ -70,7 +71,7 @@ contract XERC20Lockbox is IXERC20Lockbox {
*/

function depositTo(address _to, uint256 _amount) external {
if (IS_NATIVE) revert IXERC20Lockbox_Native();
if (IS_GAS_TOKEN) revert IXERC20Lockbox_GasToken();

_deposit(_to, _amount);
}
Expand All @@ -81,8 +82,8 @@ contract XERC20Lockbox is IXERC20Lockbox {
* @param _to The user to send the XERC20 to
*/

function depositNativeTo(address _to) public payable {
if (!IS_NATIVE) revert IXERC20Lockbox_NotNative();
function depositGasTokenTo(address _to) public payable {
if (!IS_GAS_TOKEN) revert IXERC20Lockbox_NotGasToken();

_deposit(_to, msg.value);
}
Expand Down Expand Up @@ -120,7 +121,7 @@ contract XERC20Lockbox is IXERC20Lockbox {

XERC20.burn(msg.sender, _amount);

if (IS_NATIVE) {
if (IS_GAS_TOKEN) {
(bool _success,) = payable(_to).call{value: _amount}('');
if (!_success) revert IXERC20Lockbox_WithdrawFailed();
} else {
Expand All @@ -136,7 +137,7 @@ contract XERC20Lockbox is IXERC20Lockbox {
*/

function _deposit(address _to, uint256 _amount) internal {
if (!IS_NATIVE) {
if (!IS_GAS_TOKEN) {
ERC20.safeTransferFrom(msg.sender, address(this), _amount);
}

Expand All @@ -145,6 +146,6 @@ contract XERC20Lockbox is IXERC20Lockbox {
}

receive() external payable {
depositNative();
depositGasToken();
}
}
4 changes: 2 additions & 2 deletions solidity/interfaces/IXERC20Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ interface IXERC20Factory {
*
* @param _xerc20 The address of the xerc20 that you want to deploy a lockbox for
* @param _baseToken The address of the base token that you want to lock
* @param _isNative Whether or not the base token is native
* @param _isGasToken Whether or not the base token is native
*/

function deployLockbox(
address _xerc20,
address _baseToken,
bool _isNative
bool _isGasToken
) external returns (address payable _lockbox);
}
6 changes: 3 additions & 3 deletions solidity/interfaces/IXERC20Lockbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ interface IXERC20Lockbox {
* @notice Reverts when a user tries to deposit native tokens on a non-native lockbox
*/

error IXERC20Lockbox_NotNative();
error IXERC20Lockbox_NotGasToken();

/**
* @notice Reverts when a user tries to deposit non-native tokens on a native lockbox
*/

error IXERC20Lockbox_Native();
error IXERC20Lockbox_GasToken();

/**
* @notice Reverts when a user tries to withdraw and the call fails
Expand Down Expand Up @@ -55,7 +55,7 @@ interface IXERC20Lockbox {
* @param _user The user to send the XERC20 to
*/

function depositNativeTo(address _user) external payable;
function depositGasTokenTo(address _user) external payable;

/**
* @notice Withdraw ERC20 tokens from the lockbox
Expand Down
72 changes: 0 additions & 72 deletions solidity/scripts/MultichainCreateXERC20.sol

This file was deleted.

55 changes: 0 additions & 55 deletions solidity/scripts/MultichainDeploy.sol

This file was deleted.

2 changes: 1 addition & 1 deletion solidity/scripts/ScriptingLibrary/ScriptingLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ contract ScriptingLibrary {
function hexStringToAddress(string memory s) public pure returns (bytes memory) {
bytes memory ss = bytes(s);
require(ss.length % 2 == 0); // length must be even
bytes memory r = new bytes(ss.length/2);
bytes memory r = new bytes(ss.length / 2);
for (uint256 i = 0; i < ss.length / 2; ++i) {
r[i] = bytes1(fromHexChar(uint8(ss[2 * i])) * 16 + fromHexChar(uint8(ss[2 * i + 1])));
}
Expand Down
Loading

0 comments on commit 76d582b

Please sign in to comment.