Skip to content

Commit

Permalink
fix: Tenderly DevNets Integration (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
Whytecrowe authored Jun 14, 2023
2 parents 5aa6ddc + c149e24 commit aa5686a
Show file tree
Hide file tree
Showing 22 changed files with 907 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"extends": ["@zero-tech/eslint-config-cpt/node-ts/.eslintrc.json"],
"rules": {
"no-unused-expressions": "off",
// "no-console": "off", // For debugging
"no-console": "off"
// "@typescript-eslint/no-unused-vars": "off" // For debugging
}
}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ typechain-types
cache
artifacts

# hardhat-tenderly plugin
deployments

*.env
2 changes: 1 addition & 1 deletion contracts/access/ZNSRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ abstract contract ZNSRoles {
// so we don't have to upgrade all contracts
// TODO AC: possibly remove executor role?
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
// this role is here specifically for the ZNSEthRegistrar contract
// this role is here specifically for the ZNSRegistrar contract
bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE");
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.18;


interface IZNSEthRegistrar {
interface IZNSRegistrar {
event DomainRegistered(
bytes32 indexed domainHash,
uint256 indexed tokenId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import { IZNSEthRegistrar } from "./IZNSEthRegistrar.sol";
import { IZNSRegistrar } from "./IZNSRegistrar.sol";
import { IZNSRegistry } from "../registry/IZNSRegistry.sol";
import { IZNSTreasury } from "./IZNSTreasury.sol";
import { IZNSDomainToken } from "../token/IZNSDomainToken.sol";
Expand All @@ -10,7 +10,7 @@ import { AccessControlled } from "../access/AccessControlled.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";


contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar {
contract ZNSRegistrar is AccessControlled, UUPSUpgradeable, IZNSRegistrar {
IZNSRegistry public registry;
IZNSTreasury public treasury;
IZNSDomainToken public domainToken;
Expand All @@ -19,21 +19,21 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
modifier onlyNameOwner(bytes32 domainHash) {
require(
msg.sender == registry.getDomainOwner(domainHash),
"ZNSEthRegistrar: Not the owner of the Name"
"ZNSRegistrar: Not the owner of the Name"
);
_;
}

modifier onlyTokenOwner(bytes32 domainHash) {
require(
msg.sender == domainToken.ownerOf(uint256(domainHash)),
"ZNSEthRegistrar: Not the owner of the Token"
"ZNSRegistrar: Not the owner of the Token"
);
_;
}

/**
* @notice Create an instance of the ZNSEthRegistrar
* @notice Create an instance of the ZNSRegistrar
* for registering ZNS domains and subdomains
*/
function initialize(
Expand Down Expand Up @@ -62,15 +62,15 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
) external override returns (bytes32) {
require(
bytes(name).length != 0,
"ZNSEthRegistrar: Domain Name not provided"
"ZNSRegistrar: Domain Name not provided"
);

// Create hash for given domain name
bytes32 domainHash = keccak256(bytes(name));

require(
!registry.exists(domainHash),
"ZNSEthRegistrar: Domain already exists"
"ZNSRegistrar: Domain already exists"
);

// Staking logic
Expand All @@ -96,9 +96,9 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
// TODO: figure out how to guard this so people can stake tokens
// without the risk of staking contract or wallet to call reclaim+revoke
// from underneath them
function revokeDomain(bytes32 domainHash)
function revokeDomain(bytes32 domainHash)
external
override
override
onlyNameOwner(domainHash)
onlyTokenOwner(domainHash)
{
Expand All @@ -123,7 +123,7 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
function setRegistry(address registry_) public override onlyAdmin {
require(
registry_ != address(0),
"ZNSEthRegistrar: registry_ is 0x0 address"
"ZNSRegistrar: registry_ is 0x0 address"
);
registry = IZNSRegistry(registry_);

Expand All @@ -133,7 +133,7 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
function setTreasury(address treasury_) public override onlyAdmin {
require(
treasury_ != address(0),
"ZNSEthRegistrar: treasury_ is 0x0 address"
"ZNSRegistrar: treasury_ is 0x0 address"
);
treasury = IZNSTreasury(treasury_);

Expand All @@ -143,7 +143,7 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
function setDomainToken(address domainToken_) public override onlyAdmin {
require(
domainToken_ != address(0),
"ZNSEthRegistrar: domainToken_ is 0x0 address"
"ZNSRegistrar: domainToken_ is 0x0 address"
);
domainToken = IZNSDomainToken(domainToken_);

Expand All @@ -153,7 +153,7 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar
function setAddressResolver(address addressResolver_) public override onlyAdmin {
require(
addressResolver_ != address(0),
"ZNSEthRegistrar: addressResolver_ is 0x0 address"
"ZNSRegistrar: addressResolver_ is 0x0 address"
);
addressResolver = IZNSAddressResolver(addressResolver_);

Expand All @@ -162,13 +162,13 @@ contract ZNSEthRegistrar is AccessControlled, UUPSUpgradeable, IZNSEthRegistrar

function setAccessController(address accessController_)
external
override(AccessControlled, IZNSEthRegistrar)
override(AccessControlled, IZNSRegistrar)
onlyAdmin
{
_setAccessController(accessController_);
}

function getAccessController() external view override(AccessControlled, IZNSEthRegistrar) returns (address) {
function getAccessController() external view override(AccessControlled, IZNSRegistrar) returns (address) {
return address(accessController);
}

Expand Down
8 changes: 0 additions & 8 deletions contracts/upgradeMocks/distribution/ZNSEthRegistrarMock.sol

This file was deleted.

8 changes: 8 additions & 0 deletions contracts/upgradeMocks/distribution/ZNSRegistrarMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import { ZNSRegistrar } from "../../distribution/ZNSRegistrar.sol";
import { UpgradeMock } from "../UpgradeMock.sol";

/* solhint-disable */
contract ZNSRegistrarUpgradeMock is ZNSRegistrar, UpgradeMock {}
25 changes: 24 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-unused-vars */
require("dotenv").config();

import { HardhatUserConfig } from "hardhat/config";
import * as tenderly from "@tenderly/hardhat-tenderly";
import "@nomicfoundation/hardhat-toolbox";
import "@nomiclabs/hardhat-ethers";
import "@nomicfoundation/hardhat-network-helpers";
import "@nomicfoundation/hardhat-chai-matchers";
import "@openzeppelin/hardhat-upgrades";
import "solidity-coverage";


const config : HardhatUserConfig = {
solidity: {
compilers: [
Expand Down Expand Up @@ -44,10 +46,31 @@ const config : HardhatUserConfig = {
url: "https://goerli.infura.io/v3/77c3d733140f4c12a77699e24cb30c27",
timeout: 10000000,
},
devnet: {
// Add current URL that you spawned if not using automated spawning
url: `${process.env.DEVNET_RPC_URL}`,
chainId: 1,
},
},
etherscan: {
apiKey: `${process.env.ETHERSCAN_API_KEY}`,
},
tenderly: {
project: `${process.env.TENDERLY_PROJECT_SLUG}`,
username: `${process.env.TENDERLY_ACCOUNT_ID}`,
},
};

// This call is needed to initialize Tenderly with Hardhat,
// the automatic verifications, though, don't seem to work,
// needing us to verify explicitly in code, however,
// for Tenderly to work properly with Hardhat this method
// needs to be called. The call below is commented out
// because if we leave it here, solidity-coverage
// does not work properly locally or in CI, so we
// keep it commented out and uncomment when using DevNet
// locally.
// !!! Uncomment this when using Tenderly DevNet !!!
// tenderly.setup({ automaticVerifications: true });

export default config;
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "zns-contracts",
"name": "@zero-tech/zns-contracts",
"version": "0.0.0",
"description": "Zero Name Service Smart Contracts",
"author": "Zero CPT",
Expand All @@ -20,7 +20,8 @@
"test": "hardhat test",
"semantic-release": "semantic-release --tag-format='v${version}-dev'",
"coverage": "hardhat coverage",
"check-coverage": "istanbul check-coverage --statements 90 --branches 87 --functions 89 --lines 90"
"check-coverage": "istanbul check-coverage --statements 90 --branches 87 --functions 89 --lines 90",
"devnet": "ts-node src/tenderly/devnet-execute.ts"
},
"pre-commit": [
"lint"
Expand All @@ -32,10 +33,11 @@
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomicfoundation/hardhat-toolbox": "2.0.2",
"@nomiclabs/hardhat-ethers": "2.2.2",
"@nomiclabs/hardhat-etherscan": "^3.0.0",
"@openzeppelin/contracts": "4.8.2",
"@openzeppelin/contracts-upgradeable": "4.8.2",
"@openzeppelin/hardhat-upgrades": "^1.26.0",
"@nomiclabs/hardhat-etherscan": "3.0.0",
"@openzeppelin/contracts": "4.8.3",
"@openzeppelin/contracts-upgradeable": "4.8.3",
"@openzeppelin/hardhat-upgrades": "1.26.0",
"@tenderly/hardhat-tenderly": "^1.7.4",
"@semantic-release/git": "^10.0.1",
"@typechain/ethers-v5": "10.1.0",
"@typechain/hardhat": "6.1.2",
Expand Down
46 changes: 46 additions & 0 deletions src/tenderly/devnet-execute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
import { promisify } from "util";
import { exec } from "child_process";

const execAsync = promisify(exec);

const spawnCommand = "ts-node src/tenderly/spawn-devnet.ts";
const opCommandBase = "npx hardhat run";
const networkArg = "--network devnet";
const opsPath = "src/tenderly/run-all-flows.ts";

/**
* Top level function to execute everything on the DevNet.
* It executes 2 child processes:
* 1. Spawn a DevNet through the helper and ts-node directly,
* this will also set all the required env vars, so that Hardhat can correctly
* work with contracts and auth in Tenderly
* 2. Launch deploy and operation flow with contracts using Hardhat
*
* To execute this, uncomment `tenderly.setup()` line in the hardhat.config.ts
* then run `yarn devnet` in the terminal.
* */
const execute = async () => {
// spawn DevNet on Tenderly with ts-node directly
const spawnRes = await execAsync(spawnCommand);
process.stdout.write(spawnRes.stdout);
process.stderr.write(spawnRes.stderr);

const opCommand = `${opCommandBase} ${opsPath} ${networkArg}`;

// deploy all contracts, run flows using Hardhat
const opRes = await execAsync(opCommand);
// pass Tenderly logger through
process.stdout.write(opRes.stdout);
process.stderr.write(opRes.stderr);

return spawnRes;
};


execute()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
52 changes: 52 additions & 0 deletions src/tenderly/run-all-flows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as hre from "hardhat";
import * as ethers from "ethers";
import { deployZNS, hashDomainLabel } from "../../test/helpers";
import { BigNumber } from "ethers";


const domainName = "wilder";
const domainHash = hashDomainLabel(domainName);
const tokenId = BigNumber.from(domainHash);


export const runAllFlows = async () => {
const [
governor,
user,
] = await hre.ethers.getSigners();

const zns = await deployZNS({
deployer: governor,
governorAddresses: [governor.address],
adminAddresses: [governor.address],
logAddresses: true,
});

// get some funds for the user
await zns.zeroToken.connect(user).approve(zns.treasury.address, ethers.constants.MaxUint256);
await zns.zeroToken.transfer(user.address, ethers.utils.parseEther("15"));

// Register Domain
await zns.registrar.connect(governor).registerDomain(
domainName,
user.address,
);

// Transfer Domain
await zns.domainToken.connect(governor).transferFrom(governor.address, user.address, tokenId);

// Reclaim Domain
await zns.registrar.connect(user).reclaimDomain(domainHash);

// Revoke Domain
await zns.registrar.connect(user).revokeDomain(domainHash);
};


runAllFlows()
.then(() => process.exit(0))
.catch(error => {
// eslint-disable-next-line no-console
console.error(error);
process.exit(1);
});
Loading

0 comments on commit aa5686a

Please sign in to comment.