Skip to content

Commit eb9ba14

Browse files
committed
adding ts versions
1 parent 9827f11 commit eb9ba14

5 files changed

Lines changed: 240 additions & 0 deletions

File tree

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,11 @@
33
"dependencies": {
44
"@nomiclabs/hardhat-ethers": "^2.0.6",
55
"ethers": "^5.6.9"
6+
},
7+
"devDependencies": {
8+
"@types/node": "^18.0.4",
9+
"ts-node": "^10.9.1",
10+
"tsconfig-paths": "^4.0.0",
11+
"typescript": "^4.7.4"
612
}
713
}

scripts/deploy.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// const { getSelectors, FacetCutAction } = require("./libraries/diamond.js");
2+
import { getSelectors, FacetCutAction } from "./libraries/diamond";
3+
const { ethers } = require("hardhat");
4+
5+
async function deployDiamond() {
6+
const accounts = await ethers.getSigners();
7+
const contractOwner = accounts[0];
8+
9+
// deploy DiamondCutFacet
10+
const DiamondCutFacet = await ethers.getContractFactory("DiamondCutFacet");
11+
const diamondCutFacet = await DiamondCutFacet.deploy();
12+
await diamondCutFacet.deployed();
13+
console.log("DiamondCutFacet deployed:", diamondCutFacet.address);
14+
15+
// deploy Diamond
16+
const Diamond = await ethers.getContractFactory("Diamond");
17+
const diamond = await Diamond.deploy(
18+
contractOwner.address,
19+
diamondCutFacet.address
20+
);
21+
await diamond.deployed();
22+
console.log("Diamond deployed:", diamond.address);
23+
24+
// deploy DiamondInit
25+
// DiamondInit provides a function that is called when the diamond is upgraded to initialize state variables
26+
// Read about how the diamondCut function works here: https://eips.ethereum.org/EIPS/eip-2535#addingreplacingremoving-functions
27+
const DiamondInit = await ethers.getContractFactory("DiamondInit");
28+
const diamondInit = await DiamondInit.deploy();
29+
await diamondInit.deployed();
30+
console.log("DiamondInit deployed:", diamondInit.address);
31+
32+
// deploy facets
33+
console.log("");
34+
console.log("Deploying facets");
35+
const FacetNames = ["DiamondLoupeFacet", "OwnershipFacet"];
36+
const cut = [];
37+
for (const FacetName of FacetNames) {
38+
const Facet = await ethers.getContractFactory(FacetName);
39+
const facet = await Facet.deploy();
40+
await facet.deployed();
41+
console.log(`${FacetName} deployed: ${facet.address}`);
42+
cut.push({
43+
facetAddress: facet.address,
44+
action: FacetCutAction.Add,
45+
functionSelectors: getSelectors(facet),
46+
});
47+
}
48+
49+
// upgrade diamond with facets
50+
console.log("Diamond Cut:", cut);
51+
const diamondCut = await ethers.getContractAt("IDiamondCut", diamond.address);
52+
let tx;
53+
let receipt;
54+
// call to init function
55+
let functionCall = diamondInit.interface.encodeFunctionData("init");
56+
tx = await diamondCut.diamondCut(cut, diamondInit.address, functionCall);
57+
console.log("Diamond cut tx: ", tx.hash);
58+
receipt = await tx.wait();
59+
if (!receipt.status) {
60+
throw Error(`Diamond upgrade failed: ${tx.hash}`);
61+
}
62+
console.log("Completed diamond cut");
63+
return diamond.address;
64+
}
65+
66+
// We recommend this pattern to be able to use async/await everywhere
67+
// and properly handle errors.
68+
if (require.main === module) {
69+
deployDiamond()
70+
.then(() => process.exit(0))
71+
.catch((error) => {
72+
console.error(error);
73+
process.exit(1);
74+
});
75+
}
76+
77+
exports.deployDiamond = deployDiamond;

scripts/genSelectors.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ContractFactory, utils } from "ethers";
2+
import path from "path/posix";
3+
4+
const args = process.argv.slice(2);
5+
6+
if (args.length != 1) {
7+
console.log(`please supply the correct parameters:
8+
facetName
9+
`);
10+
process.exit(1);
11+
}
12+
13+
async function printSelectors(
14+
contractName: string,
15+
artifactFolderPath: string = "../out"
16+
) {
17+
const contractFilePath = path.join(
18+
artifactFolderPath,
19+
`${contractName}.sol`,
20+
`${contractName}.json`
21+
);
22+
const contractArtifact = require(contractFilePath);
23+
const abi = contractArtifact.abi;
24+
const bytecode = contractArtifact.bytecode;
25+
const target = new ContractFactory(abi, bytecode);
26+
const signatures = Object.keys(target.interface.functions);
27+
28+
const selectors = signatures.reduce((acc: string[], val) => {
29+
if (val !== "init(bytes)") {
30+
acc.push(target.interface.getSighash(val));
31+
}
32+
return acc;
33+
}, []);
34+
35+
const coder = utils.defaultAbiCoder;
36+
const coded = coder.encode(["bytes4[]"], [selectors]);
37+
38+
process.stdout.write(coded);
39+
}
40+
41+
// We recommend this pattern to be able to use async/await everywhere
42+
// and properly handle errors.
43+
printSelectors(args[0], args[1])
44+
.then(() => process.exit(0))
45+
.catch((error) => {
46+
console.error(error);
47+
process.exit(1);
48+
});

scripts/libraries/diamond.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import * as ethers from "ethers";
2+
3+
const FacetCutAction = { Add: 0, Replace: 1, Remove: 2 };
4+
5+
// get function selectors from ABI
6+
function getSelectors(contract: ethers.Contract) {
7+
const signatures = Object.keys(contract.interface.functions);
8+
const selectors = signatures.reduce((acc: string[], val) => {
9+
if (val !== "init(bytes)") {
10+
acc.push(contract.interface.getSighash(val));
11+
}
12+
return acc;
13+
}, []);
14+
// selectors.contract = contract
15+
// selectors.remove = remove
16+
// selectors.get = get
17+
return selectors;
18+
}
19+
20+
// get function selector from function signature
21+
function getSelector(func: any) {
22+
const abiInterface = new ethers.utils.Interface([func]);
23+
return abiInterface.getSighash(ethers.utils.Fragment.from(func));
24+
}
25+
26+
// used with getSelectors to remove selectors from an array of selectors
27+
// functionNames argument is an array of function signatures
28+
function remove(this: any, functionNames: string[]) {
29+
const selectors = this.filter((v: any) => {
30+
for (const functionName of functionNames) {
31+
if (v === this.contract.interface.getSighash(functionName)) {
32+
return false;
33+
}
34+
}
35+
return true;
36+
});
37+
// selectors.contract = this.contract
38+
// selectors.remove = this.remove
39+
// selectors.get = this.get
40+
return selectors;
41+
}
42+
43+
// used with getSelectors to get selectors from an array of selectors
44+
// functionNames argument is an array of function signatures
45+
function get(this: any, functionNames: string[]) {
46+
const selectors = this.filter((v: any) => {
47+
for (const functionName of functionNames) {
48+
if (v === this.contract.interface.getSighash(functionName)) {
49+
return true;
50+
}
51+
}
52+
return false;
53+
});
54+
// selectors.contract = this.contract
55+
// selectors.remove = this.remove
56+
// selectors.get = this.get
57+
return selectors;
58+
}
59+
60+
// remove selectors using an array of signatures
61+
function removeSelectors(selectors: any[], signatures: any[]) {
62+
const iface = new ethers.utils.Interface(
63+
signatures.map((v: any) => "function " + v)
64+
);
65+
const removeSelectors = signatures.map((v) => iface.getSighash(v));
66+
selectors = selectors.filter((v) => !removeSelectors.includes(v));
67+
return selectors;
68+
}
69+
70+
// find a particular address position in the return value of diamondLoupeFacet.facets()
71+
function findAddressPositionInFacets(facetAddress: any, facets: any) {
72+
for (let i = 0; i < facets.length; i++) {
73+
if (facets[i].facetAddress === facetAddress) {
74+
return i;
75+
}
76+
}
77+
}
78+
79+
export {
80+
getSelectors,
81+
getSelector,
82+
FacetCutAction,
83+
remove,
84+
removeSelectors,
85+
findAddressPositionInFacets,
86+
};

tsconfig.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2018",
4+
"module": "commonjs",
5+
"strict": true,
6+
"esModuleInterop": true,
7+
"outDir": "dist",
8+
"declaration": true,
9+
"rootDir": "./",
10+
"baseUrl": "./",
11+
"paths": {
12+
"@src/*": ["src/*"],
13+
"@utils/*": ["./utils/*"],
14+
"@scripts/*": ["./scripts/*"],
15+
"@tests/*": ["tests/*"],
16+
"@customTypes/*": ["./types/*"],
17+
"@utils/": ["./utils/*"],
18+
"@migrations/*": ["./migrations/*"],
19+
"@typechain-types/*": ["./typechain-types/*"]
20+
}
21+
},
22+
"include": ["./scripts", "./test", "./typechain"]
23+
}

0 commit comments

Comments
 (0)