Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scripts to deploy, upgrade and interact with EthErc20FastBridge #28

Merged
merged 17 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,111 @@ Described in the corresponding [README](eth/README.md)

### Near
Described in the corresponding [README](near/README.md)


## EthErc20Bridge scripts
Below given command will help user to deploy and interact with contracts on the network provided as arg to below command, if no arg is provided it will use default network from hardhat-config.

First set up your `.env` file in `spectere-bridge-protocol/.env`, for help `.env.example` is provided in `spectere-bridge-protocol` directory.
1. First copy content of `.env.example` file
2. Create a new file in `spectere-bridge-protocol` directory and name it `.env`
3. Paste copied content in `.env` file
4. Fill up details as required as per used in `hardhat.config.json` file.

Then, to run below scripts go to `spectere-bridge-protocol/eth` directory, i.e. **run command `cd eth`**

example : to deploy EthErc20FastBridge on <network-name> network (network-name must be defined in hardhat-config.json's networks)
`npm run deploy:bridge -- <network-name>`

### Deployment script
Running ths script will deploy bridge proxy and store proxy and implementation address in `spectre-bridge-protocol/eth/scripts/deployment/deploymentAddresses.json`
To execute this script => run command `yarn run deploy:bridge -- <network-name>`
example : to deploy bridge on goerli run command `yarn run deploy:bridge -- goerli`

### Deploy and verify
Running this script will first deploy and then verify bridge.
To execute this script => run command `yarn run deploy:verify:bridge -- <network-name>`
example : to deploy and verify bridge on goerli run command `yarn run deploy:verify:bridge -- goerli`

### Upgrade script
To upgrade bridge contract(using hardhat's upgrades plugin), use `spectre-bridge-protocol/eth/scripts/EthErc20FastBridge/upgrade_bridge.js` script.
<!-- Before upgrading, go to file `spectre-bridge-protocol/eth/scripts/EthErc20FastBridge/upgrade_bridge.js` and update current bridge proxy address at line 7. -->

To execute this script => run command `yarn run upgrade:bridge -- <network-name>`
example : to upgrade on goerli run command `yarn run deploy:verify:bridge -- goerli`

### Whitelisting
To interact with EthErc20FastBridge whitelisting methods use methods defined in spectre-bridge-protocol/eth/scripts/EthErc20FastBridge/whitelistTokens.js
UrAvgDeveloper marked this conversation as resolved.
Show resolved Hide resolved

* To bulk update whitelist status of tokens import and use method `bulkWhitelistStatusUpdate` from above mentioned file with an array of token addresses, an array of their corresponding status and a signer with `WHITELISTING_TOKENS_ADMIN_ROLE` as parameters.

* To whitelist one token import and use method `addTokenToWhitelist` from above mentioned file with a token address and a signer with `WHITELISTING_TOKENS_ADMIN_ROLE` as parameters.

* To remove one token from whitelist use method `removeTokenFromWhitelist` from above mentioned file with tokens address and signer with `WHITELISTING_TOKENS_ADMIN_ROLE` as parameters.

* To check whether a token is whitelisted or not import and use method `isTokenInWhitelist` from above mentioned file with tokens address and signer with `WHITELISTING_TOKENS_ADMIN_ROLE` as parameters.

example : If you want whitelist whitelist one token, script would like,
```
const { ethers } = require("hardhat");
const { addTokenToWhitelist } = require("./whitelistTokens");

const WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";

async function main() {
const [signer] = await ethers.getSigners(); // signer must have WHITELISTING_TOKENS_ADMIN_ROLE
await addTokenToWhitelist(WETH, signer);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
```
And to run above script run `npx hardhat run <path_to_script/script.js> --` from eth folder.

### Pause/Unpause transfers
To interact with EthErc20FastBridge pause and unpause methods use methods defined in spectre-bridge-protocol/eth/scripts/EthErc20FastBridge/pause_unPause.js

* To pause transfers import and use `pauseTransfer` method from above mentioned file with a signer with `PAUSABLE_ADMIN_ROLE` as parameter.

* To unpause transfers import and use `unpauseTransfer` method from above mentioned file with a signer with `UNPAUSABLE_ADMIN_ROLE` as parameter.

These methods can be used in similar to above example

### To interact with above methods use script `spectre-bridge-protocol/eth/scripts/EthErc20FastBridge/interact_with_bridge.js`
Follow below steps to execute script and start interacting
1. First, create your `.env` file(mentioned in `EthErc20Bridge scripts` section's starting)
2. Go to `spectre-bridge-protocol/eth` directory in terminal
3. Run command `npm run interact:bridge -- <network_name_as_defined_in_hardhat_config>`
4. Follow guide in terminal
Note: bridge address will be picked from `deploymentAddress[network].new.bridge` (from `spectre-bridge-protocol/eth/scripts/deployment/deploymentAddresses.json`)

### To interact with FastBridge using hardhat task
To call any method of EthErc20FastBridge use hardhat task `method`
Run command `npx hardhat method --jsonstring <json_string_input>`
```
to create `json_string_input`
1. create json with `signature` and `arguments` properties in below example format

{
"signature": "setWhitelistedTokens(address[],bool[])",
"argcount": "2",
"arguments": {
"arg1": [
"0xdAC17F958D2ee523a2206206994597C13D831ec7",
"0xB8c77482e45F1F44dE1745F52C74426C631bDD52",
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
],
"arg2": [
true,
true,
true
]
}
}

2. pass below json to JSON.stringify() and use output as `json_string_input`

```
example: to call `setWhitelistedTokens` method run command `npx hardhat method --jsonstring '{"signature":"setWhitelistedTokens","arguments":{"arg1":["0xdAC17F958D2ee523a2206206994597C13D831ec7"],"arg2":[true]}}'`
4 changes: 3 additions & 1 deletion eth/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ ETHERSCAN_API_KEY =
ETHERSCAN_URL =

REPORT_GAS =
GAS_REPORT_TO_FILE =
GAS_REPORT_TO_FILE =

BRIDGE_PROXY_ADDRESS =
38 changes: 34 additions & 4 deletions eth/hardhat.config.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
require("dotenv").config();

require("@nomicfoundation/hardhat-toolbox");

require("@nomicfoundation/hardhat-chai-matchers");
require("@nomiclabs/hardhat-ethers");
require("@nomicfoundation/hardhat-network-helpers");

require("hardhat-contract-sizer");
require("hardhat-abi-exporter");
require("@openzeppelin/hardhat-upgrades");
const { ethers } = require("ethers");
sept-en marked this conversation as resolved.
Show resolved Hide resolved
const { task } = require("hardhat/config");
const deploymentAddress = require("./scripts/deployment/deploymentAddresses.json");
const bridgeArtifacts = require("./artifacts/contracts/EthErc20FastBridge.sol/EthErc20FastBridge.json");

const PRIVATE_KEYS = process.env.PRIVATE_KEYS ? process.env.PRIVATE_KEYS.split(",") : [];
const PRIVATE_KEY = process.env.PRIVATE_KEY || '11'.repeat(32);
const PRIVATE_KEY = process.env.PRIVATE_KEY || "11".repeat(32);

const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY;
const INFURA_API_KEY = process.env.INFURA_API_KEY;
Expand All @@ -20,6 +21,35 @@ const FORKING = true;
const ENABLED_OPTIMIZER = true;
const OPTIMIZER_RUNS = 200;

task("method", "Execute Fastbridge methods")
.addParam("jsonstring", "JSON string with function signature and arguments")
.setAction(async (taskArgs) => {
const network = (await ethers.getDefaultProvider().getNetwork()).name;
const bridgeAddress = deploymentAddress[network].new.bridge;
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_TASK);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

const jsonString = taskArgs.jsonstring;
const json = JSON.parse(jsonString);
const arg = json.arguments;
const functionSignature = json.signature;
sept-en marked this conversation as resolved.
Show resolved Hide resolved
console.log(arg);
const functionArguments = Object.values(arg);
console.log(functionSignature, functionArguments);
sept-en marked this conversation as resolved.
Show resolved Hide resolved
const iface = new ethers.utils.Interface(bridgeArtifacts.abi);
sept-en marked this conversation as resolved.
Show resolved Hide resolved
// Send the transaction
const txdata = iface.encodeFunctionData(functionSignature, functionArguments);
const tx = await signer.sendTransaction({
to: bridgeAddress,
data: txdata,
gasLimit: 999999
sept-en marked this conversation as resolved.
Show resolved Hide resolved
});
console.log(tx);
await tx.wait();

console.log("Transaction mined!");
});

module.exports = {
solidity: {
compilers: [
Expand Down
7 changes: 5 additions & 2 deletions eth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"dev:size-contracts": "npm run compile-all && npx hardhat size-contracts",
"deploy:all": "npx hardhat run scripts/deployment/",
"deploy:test-tokens": "npm run compile-all && npx hardhat run scripts/deployment/deploy-test-tokens.js --network goerli",
"deploy:bridge": "npm run compile-all && npx hardhat run scripts/deployment/deploy-bridge.js --network goerli",
"deploy:bridge": "npm run compile-all && npx hardhat run scripts/deployment/deploy-bridge.js --network ",
"deploy:verify:bridge": "npm run compile-all && npx hardhat run scripts/EthErc20FastBridge/deploy_and_verify_bridge.js --network",
sept-en marked this conversation as resolved.
Show resolved Hide resolved
"upgrade:bridge": "npm run compile-all && npx hardhat run scripts/EthErc20FastBridge/upgrade_bridge.js --network ",
"dev:abi": "npx hardhat clear-abi && npx hardhat export-abi",
"dev:coverage": "npx hardhat coverage",
"docgen": "npx shx rm -rf docs && npx solidity-docgen --solc-module solc -t docgen -H docgen/helpers.js -o docs/",
Expand Down Expand Up @@ -47,7 +49,8 @@
"@nomicfoundation/hardhat-network-helpers": "^1.0.7",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"@openzeppelin/contracts": "4.8.0",
"@openzeppelin/contracts-upgradeable": "^4.8.0"
"@openzeppelin/contracts-upgradeable": "^4.8.0",
"@openzeppelin/upgrades-core": "^1.20.6"
},
"devDependencies": {
"@commitlint/cli": "^17.3.0",
Expand Down
36 changes: 36 additions & 0 deletions eth/scripts/EthErc20FastBridge/deploy_and_verify_bridge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const { ethers, upgrades } = require("hardhat");
const { getAddressSaver, verify } = require("../deployment/utilities/helpers");
const { getImplementationAddress } = require("@openzeppelin/upgrades-core");
const path = require("path");

const main = async () => {
const [deployer] = await ethers.getSigners();
const network = (await ethers.getDefaultProvider().getNetwork()).name;
const addressesPath = path.join(__dirname, "../deployment/deploymentAddresses.json");
const saveAddress = getAddressSaver(addressesPath, network, true);

const tokensAddresses = Object.values(require("../deployment/deploymentAddresses.json").tokens);
const whitelistedTokens = Object.values(require("../deployment/deploymentAddresses.json").whitelisted_tokens);

const bridge = await ethers.getContractFactory("EthErc20FastBridge", deployer);
const Bridge = await upgrades.deployProxy(bridge, [tokensAddresses, whitelistedTokens], {
unsafeAllow: ["delegatecall"]
});
await Bridge.deployed();

sept-en marked this conversation as resolved.
Show resolved Hide resolved
saveAddress("bridge_proxy", Bridge.address); // save bridge address

const currentImplAddress = await getImplementationAddress(ethers.provider, Bridge.address);

saveAddress("bridge_Implementation", currentImplAddress); // save implementation address

// verify
console.log("Verifing Contract");
await verify(Bridge.address, [tokensAddresses, whitelistedTokens]);
console.log("Verified.");
};

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
80 changes: 80 additions & 0 deletions eth/scripts/EthErc20FastBridge/interact_with_bridge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const { ethers } = require("hardhat");
const {
bulkWhitelistStatusUpdate,
addTokenToWhitelist,
removeTokenFromWhitelist,
isTokenInWhitelist
} = require("./whitelistTokens");
const { pauseTransfer, unpauseTransfer } = require("./pause_unpause");
const { withdrawStuckTokens } = require("./withdraw_Stuck_tokens");
const prompt = require("prompt-sync")();

async function main() {
console.log(
"Please select operation to perform on Bridge :\n" +
"1. Bulk whitelist Tokens\n" +
"2. Add one token to whitelist\n" +
"3. Remove token from whitelist\n" +
"4. Check token's whitelist status\n" +
"5. Pause transfers\n" +
"6. Unpause transfers\n" +
"7. Withdraw stuck tokens\n"
);

const choice = prompt("Please Enter your choice :");
if (choice !== null) {
let userInput = choice.toString().trim().toLowerCase();
if (userInput === "1") {
console.log("to execute bulkWhitelistStatusUpdate(tokensArray, statusArray, signer)");
const inputTokens = prompt("please enter space separated token addresses : ");
let addressArray = inputTokens.trim().split(" ");
const inputStatuses = prompt("please enter space separated token addresses : ");
let statusArray = inputStatuses.trim().split(" ");
console.log(addressArray);

const [whitelistingAdminSigner] = await ethers.getSigners();
if (addressArray.length == statusArray) {
await bulkWhitelistStatusUpdate(addressArray, statusArray, whitelistingAdminSigner);
} else {
console.log("number of tokens is not equal to number of statuses provided");
}
} else if (userInput === "2") {
console.log("to execute addTokenToWhitelist(token, signer)");
const inputToken = prompt("please enter token address : ");
let tokenAddress = inputToken.trim();
const [whitelistingAdminSigner] = await ethers.getSigners();
await addTokenToWhitelist(tokenAddress, whitelistingAdminSigner);
} else if (userInput === "3") {
console.log("to execute removeTokenFromWhitelist(token, signer)");
const inputToken = prompt("please enter token address : ");
let tokenAddress = inputToken.trim();
const [whitelistingAdminSigner] = await ethers.getSigners();
await removeTokenFromWhitelist(tokenAddress, whitelistingAdminSigner);
} else if (userInput === "4") {
console.log("to execute isTokenInWhitelist(token)");
const inputToken = prompt("please enter token address : ");
let token = inputToken.trim();
await isTokenInWhitelist(token);
} else if (userInput === "5") {
console.log("to execute pauseTransfer(signer)");
const [pausableAdminSigner] = await ethers.getSigners();
await pauseTransfer(pausableAdminSigner);
} else if (userInput === "6") {
console.log("Executing unpauseTransfer(signer)");
const [unpausableAdminSigner] = await ethers.getSigners();
await unpauseTransfer(unpausableAdminSigner);
} else if (userInput === "7") {
console.log("to execute withdrawStuckTokens(signer)");
const [defaultAdminSigner] = await ethers.getSigners();
await withdrawStuckTokens(defaultAdminSigner);
sept-en marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Handle invalid input
console.log("Invalid input.");
}
}
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
28 changes: 28 additions & 0 deletions eth/scripts/EthErc20FastBridge/pause_unpause.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { getBridgeContract } = require("./whitelistTokens");
sept-en marked this conversation as resolved.
Show resolved Hide resolved

async function pauseTransfer(signer) {
let bridge;
try {
bridge = await getBridgeContract();
await bridge.connect(signer).pause();
console.log("Transfers paused successfully!");
} catch (error) {
console.error("Transfers pause failed with error", error);
}
}

async function unpauseTransfer(signer) {
let bridge;
try {
bridge = await getBridgeContract();
await bridge.connect(signer).unPause();
console.log("Transfers unpaused successfully!");
} catch (error) {
console.error("Transfers unpause failed with error", error);
}
}

module.exports = {
pauseTransfer,
unpauseTransfer
};
47 changes: 47 additions & 0 deletions eth/scripts/EthErc20FastBridge/upgrade_bridge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { ethers, upgrades } = require("hardhat");
const { getImplementationAddress } = require("@openzeppelin/upgrades-core");
require("dotenv");
// const { argv } = require("process");

async function main() {
const [deployer] = await ethers.getSigners();

const EthErc20FastBridge = await ethers.getContractFactory("EthErc20FastBridge", deployer);
const bridgeaddress = process.env.BRIDGE_PROXY_ADDRESS;
console.log(bridgeaddress);
console.log("Need to upgrade bridge?");
console.log("Proxy provided : ", bridgeaddress);

process.stdout.write("Ok to proceed? (y/n) : ");
process.stdin.on("readable", async () => {
const chunk = process.stdin.read();
if (chunk !== null) {
let userInput = chunk.toString().trim().toLowerCase();
if (userInput === "y") {
// Perform the upgrade
console.log("Performing the upgrade...");
await upgrades.upgradeProxy(
bridgeaddress, // address of proxy deployed
EthErc20FastBridge,
{
unsafeAllow: ["delegatecall"]
}
);
const currentImplAddress = await getImplementationAddress(ethers.provider, bridgeaddress);
console.log("EthErc20FastBridge upgraded");
console.log("Current implementation address is ", currentImplAddress);
} else if (userInput === "n") {
// Do not upgrade
console.log("Bridge upgrade cancelled.");
} else {
// Handle invalid input
console.log("Invalid input.");
}
}
});
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Loading