@mapprotocol/common-contracts 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -3
- package/utils/dist/addressCodec.d.ts +14 -0
- package/utils/dist/addressCodec.js +61 -0
- package/utils/dist/codeHash.d.ts +24 -0
- package/utils/dist/codeHash.js +60 -0
- package/utils/dist/deployRecord.d.ts +37 -0
- package/utils/dist/deployRecord.js +104 -0
- package/utils/dist/deployer.d.ts +36 -0
- package/utils/dist/deployer.js +80 -0
- package/utils/dist/evmHelper.d.ts +33 -0
- package/utils/dist/evmHelper.js +83 -0
- package/utils/dist/factory.d.ts +36 -0
- package/utils/dist/factory.js +187 -0
- package/utils/dist/index.d.ts +17 -0
- package/utils/dist/index.js +45 -0
- package/utils/dist/tronHelper.d.ts +127 -0
- package/utils/dist/tronHelper.js +291 -0
- package/utils/dist/verifier.d.ts +14 -0
- package/utils/dist/verifier.js +205 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mapprotocol/common-contracts",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Common contracts for MAP Protocol",
|
|
5
5
|
"main": "typechain-types/index.js",
|
|
6
6
|
"types": "typechain-types/index.d.ts",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"!artifacts/contracts/**/*.dbg.json",
|
|
11
11
|
"typechain-types/**/*",
|
|
12
12
|
"utils/**/*.ts",
|
|
13
|
+
"utils/dist/**/*",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"repository": {
|
|
@@ -31,12 +32,13 @@
|
|
|
31
32
|
"test": "forge test",
|
|
32
33
|
"test:hardhat": "hardhat test",
|
|
33
34
|
"format": "forge fmt",
|
|
34
|
-
"
|
|
35
|
+
"build:utils": "cd utils && tsc",
|
|
36
|
+
"clean": "forge clean && hardhat clean && rm -rf typechain-types utils/dist",
|
|
35
37
|
"compile": "hardhat compile",
|
|
36
38
|
"typecheck": "tsc --noEmit",
|
|
37
39
|
"gas-report": "forge test --gas-report",
|
|
38
40
|
"coverage": "forge coverage",
|
|
39
|
-
"prepublishOnly": "npm run clean && npm run build:hardhat && npm run typecheck"
|
|
41
|
+
"prepublishOnly": "npm run clean && npm run build:hardhat && npm run build:utils && npm run typecheck"
|
|
40
42
|
},
|
|
41
43
|
"keywords": [
|
|
42
44
|
"solidity",
|
|
@@ -81,5 +83,8 @@
|
|
|
81
83
|
"ts-node": ">=8.0.0",
|
|
82
84
|
"typechain": "^8.3.0",
|
|
83
85
|
"typescript": ">=4.5.0"
|
|
86
|
+
},
|
|
87
|
+
"overrides": {
|
|
88
|
+
"axios": "1.15.0"
|
|
84
89
|
}
|
|
85
90
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert any address format to hex bytes.
|
|
3
|
+
* - EVM address (0x prefix): return as-is lowercase
|
|
4
|
+
* - Tron address (T prefix, 34 chars, 0x41 byte): convert via tronToHex
|
|
5
|
+
* - Solana/other base58 address: base58 decode to full bytes
|
|
6
|
+
* @param addr - address in any supported format
|
|
7
|
+
*/
|
|
8
|
+
export declare function addressToHex(addr: string): string;
|
|
9
|
+
/** Check if a string is valid base58 encoding. */
|
|
10
|
+
export declare function isBase58(addr: string): boolean;
|
|
11
|
+
/** Check if address is Tron format (T prefix, 34 chars, 0x41 first byte after decode). */
|
|
12
|
+
export declare function isTronAddress(addr: string): boolean;
|
|
13
|
+
/** Check if chain name is Solana. */
|
|
14
|
+
export declare function isSolanaChain(chainName: string): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addressToHex = addressToHex;
|
|
7
|
+
exports.isBase58 = isBase58;
|
|
8
|
+
exports.isTronAddress = isTronAddress;
|
|
9
|
+
exports.isSolanaChain = isSolanaChain;
|
|
10
|
+
/**
|
|
11
|
+
* Multi-chain address encoding — converts EVM, Tron, and Solana addresses to hex bytes.
|
|
12
|
+
*/
|
|
13
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
14
|
+
const tronHelper_1 = require("./tronHelper");
|
|
15
|
+
/**
|
|
16
|
+
* Convert any address format to hex bytes.
|
|
17
|
+
* - EVM address (0x prefix): return as-is lowercase
|
|
18
|
+
* - Tron address (T prefix, 34 chars, 0x41 byte): convert via tronToHex
|
|
19
|
+
* - Solana/other base58 address: base58 decode to full bytes
|
|
20
|
+
* @param addr - address in any supported format
|
|
21
|
+
*/
|
|
22
|
+
function addressToHex(addr) {
|
|
23
|
+
if (addr.startsWith("0x")) {
|
|
24
|
+
return addr.toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
if (isTronAddress(addr)) {
|
|
27
|
+
return (0, tronHelper_1.tronToHex)(addr);
|
|
28
|
+
}
|
|
29
|
+
if (isBase58(addr)) {
|
|
30
|
+
const decoded = bs58_1.default.decode(addr);
|
|
31
|
+
return "0x" + Buffer.from(decoded).toString("hex");
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Unknown address format: ${addr}`);
|
|
34
|
+
}
|
|
35
|
+
/** Check if a string is valid base58 encoding. */
|
|
36
|
+
function isBase58(addr) {
|
|
37
|
+
const base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
38
|
+
for (const char of addr) {
|
|
39
|
+
if (!base58Chars.includes(char)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
/** Check if address is Tron format (T prefix, 34 chars, 0x41 first byte after decode). */
|
|
46
|
+
function isTronAddress(addr) {
|
|
47
|
+
if (!addr.startsWith("T") || addr.length !== 34 || !isBase58(addr))
|
|
48
|
+
return false;
|
|
49
|
+
try {
|
|
50
|
+
const decoded = bs58_1.default.decode(addr);
|
|
51
|
+
// Tron: 0x41 (1 byte) + address (20 bytes) + checksum (4 bytes) = 25 bytes
|
|
52
|
+
return decoded.length === 25 && decoded[0] === 0x41;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Check if chain name is Solana. */
|
|
59
|
+
function isSolanaChain(chainName) {
|
|
60
|
+
return chainName === "Sol" || chainName === "sol_test";
|
|
61
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get codeHash for a contract deployment.
|
|
3
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
4
|
+
* @param contractName - contract name (e.g. "Gateway", "AuthorityManager")
|
|
5
|
+
* @param args - constructor arguments array
|
|
6
|
+
*/
|
|
7
|
+
export declare function getCodeHash(artifacts: any, contractName: string, args?: any[]): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Get codeHash for an ERC1967Proxy deployment.
|
|
10
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
11
|
+
* @param implAddress - implementation address
|
|
12
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
13
|
+
* @param initArgs - arguments for initialize() function
|
|
14
|
+
*/
|
|
15
|
+
export declare function getProxyCodeHash(artifacts: any, implAddress: string, implName: string, initArgs?: any[]): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Get codeHash for a custom proxy deployment.
|
|
18
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
19
|
+
* @param proxyName - proxy contract name (e.g. "MyCustomProxy")
|
|
20
|
+
* @param implAddress - implementation address
|
|
21
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
22
|
+
* @param initArgs - arguments for initialize() function
|
|
23
|
+
*/
|
|
24
|
+
export declare function getCustomProxyCodeHash(artifacts: any, proxyName: string, implAddress: string, implName: string, initArgs?: any[]): Promise<string>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCodeHash = getCodeHash;
|
|
4
|
+
exports.getProxyCodeHash = getProxyCodeHash;
|
|
5
|
+
exports.getCustomProxyCodeHash = getCustomProxyCodeHash;
|
|
6
|
+
/**
|
|
7
|
+
* Calculate creationCode hash for CREATE2 address prediction.
|
|
8
|
+
*/
|
|
9
|
+
const { keccak256, Interface } = require("ethers");
|
|
10
|
+
/**
|
|
11
|
+
* Get codeHash for a contract deployment.
|
|
12
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
13
|
+
* @param contractName - contract name (e.g. "Gateway", "AuthorityManager")
|
|
14
|
+
* @param args - constructor arguments array
|
|
15
|
+
*/
|
|
16
|
+
async function getCodeHash(artifacts, contractName, args = []) {
|
|
17
|
+
const artifact = await artifacts.readArtifact(contractName);
|
|
18
|
+
let bytecode = artifact.bytecode;
|
|
19
|
+
if (!bytecode.startsWith("0x"))
|
|
20
|
+
bytecode = "0x" + bytecode;
|
|
21
|
+
if (args.length > 0) {
|
|
22
|
+
const iface = new Interface(artifact.abi);
|
|
23
|
+
const encoded = iface.encodeDeploy(args);
|
|
24
|
+
return keccak256(bytecode + encoded.slice(2));
|
|
25
|
+
}
|
|
26
|
+
return keccak256(bytecode);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get codeHash for an ERC1967Proxy deployment.
|
|
30
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
31
|
+
* @param implAddress - implementation address
|
|
32
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
33
|
+
* @param initArgs - arguments for initialize() function
|
|
34
|
+
*/
|
|
35
|
+
async function getProxyCodeHash(artifacts, implAddress, implName, initArgs = []) {
|
|
36
|
+
return getCustomProxyCodeHash(artifacts, "ERC1967Proxy", implAddress, implName, initArgs);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get codeHash for a custom proxy deployment.
|
|
40
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
41
|
+
* @param proxyName - proxy contract name (e.g. "MyCustomProxy")
|
|
42
|
+
* @param implAddress - implementation address
|
|
43
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
44
|
+
* @param initArgs - arguments for initialize() function
|
|
45
|
+
*/
|
|
46
|
+
async function getCustomProxyCodeHash(artifacts, proxyName, implAddress, implName, initArgs = []) {
|
|
47
|
+
const proxyArtifact = await artifacts.readArtifact(proxyName);
|
|
48
|
+
let bytecode = proxyArtifact.bytecode;
|
|
49
|
+
if (!bytecode.startsWith("0x"))
|
|
50
|
+
bytecode = "0x" + bytecode;
|
|
51
|
+
let initData = "0x";
|
|
52
|
+
if (initArgs.length > 0) {
|
|
53
|
+
const implArtifact = await artifacts.readArtifact(implName);
|
|
54
|
+
const iface = new Interface(implArtifact.abi);
|
|
55
|
+
initData = iface.encodeFunctionData("initialize", initArgs);
|
|
56
|
+
}
|
|
57
|
+
const { AbiCoder } = require("ethers");
|
|
58
|
+
const constructorArgs = AbiCoder.defaultAbiCoder().encode(["address", "bytes"], [implAddress, initData]);
|
|
59
|
+
return keccak256(bytecode + constructorArgs.slice(2));
|
|
60
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface DeploymentPath {
|
|
2
|
+
env: string;
|
|
3
|
+
chain: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DeploymentOptions {
|
|
6
|
+
basePath?: string;
|
|
7
|
+
env: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve deployment path from network name and env.
|
|
11
|
+
* @param network - hardhat network name (e.g. "Bsc", "Mapo_test", "Tron")
|
|
12
|
+
* @param env - deployment environment: "prod", "main", "test"
|
|
13
|
+
* @returns { env, chain } for deploy.json lookup
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveDeploymentPath(network: string, env: string): DeploymentPath;
|
|
16
|
+
/**
|
|
17
|
+
* Read a deployed contract address from deploy.json.
|
|
18
|
+
* @param network - hardhat network name
|
|
19
|
+
* @param key - contract key (e.g. "Gateway", "Authority")
|
|
20
|
+
* @param opts - optional basePath and env overrides
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDeploymentByKey(network: string, key: string, opts: DeploymentOptions): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a contract address exists and is valid in deploy.json.
|
|
25
|
+
* @param network - hardhat network name
|
|
26
|
+
* @param key - contract key
|
|
27
|
+
* @param opts - optional basePath and env overrides
|
|
28
|
+
*/
|
|
29
|
+
export declare function hasDeployment(network: string, key: string, opts: DeploymentOptions): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Save a deployed contract address to deploy.json.
|
|
32
|
+
* @param network - hardhat network name
|
|
33
|
+
* @param key - contract key (e.g. "Gateway")
|
|
34
|
+
* @param addr - deployed address
|
|
35
|
+
* @param opts - optional basePath and env overrides
|
|
36
|
+
*/
|
|
37
|
+
export declare function saveDeployment(network: string, key: string, addr: string, opts: DeploymentOptions): Promise<void>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDeploymentPath = resolveDeploymentPath;
|
|
4
|
+
exports.getDeploymentByKey = getDeploymentByKey;
|
|
5
|
+
exports.hasDeployment = hasDeployment;
|
|
6
|
+
exports.saveDeployment = saveDeployment;
|
|
7
|
+
/**
|
|
8
|
+
* Deploy record — read/write deployed contract addresses from deploy.json
|
|
9
|
+
*
|
|
10
|
+
* Structure:
|
|
11
|
+
* {
|
|
12
|
+
* "prod": { "Mapo": { "Relay": "0x..." }, "Bsc": { "Gateway": "0x..." } },
|
|
13
|
+
* "main": { "Mapo": { "Relay": "0x..." } },
|
|
14
|
+
* "test": { "Mapo": { "Relay": "0x..." } }
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
let fs = require("fs");
|
|
18
|
+
let path = require("path");
|
|
19
|
+
function defaultDeployPath() {
|
|
20
|
+
return path.join(process.cwd(), "deployments");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve deployment path from network name and env.
|
|
24
|
+
* @param network - hardhat network name (e.g. "Bsc", "Mapo_test", "Tron")
|
|
25
|
+
* @param env - deployment environment: "prod", "main", "test"
|
|
26
|
+
* @returns { env, chain } for deploy.json lookup
|
|
27
|
+
*/
|
|
28
|
+
function resolveDeploymentPath(network, env) {
|
|
29
|
+
// Strip _test suffix from network name to get chain name
|
|
30
|
+
const chain = network.replace(/_?test$/i, "");
|
|
31
|
+
return { env, chain: chain.charAt(0).toUpperCase() + chain.slice(1) };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read a deployed contract address from deploy.json.
|
|
35
|
+
* @param network - hardhat network name
|
|
36
|
+
* @param key - contract key (e.g. "Gateway", "Authority")
|
|
37
|
+
* @param opts - optional basePath and env overrides
|
|
38
|
+
*/
|
|
39
|
+
async function getDeploymentByKey(network, key, opts) {
|
|
40
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
41
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
42
|
+
const data = await readDeployFile(deployPath);
|
|
43
|
+
const addr = data[env]?.[chain]?.[key];
|
|
44
|
+
if (!addr)
|
|
45
|
+
throw new Error(`no ${key} deployment in ${env}.${chain}`);
|
|
46
|
+
return addr;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if a contract address exists and is valid in deploy.json.
|
|
50
|
+
* @param network - hardhat network name
|
|
51
|
+
* @param key - contract key
|
|
52
|
+
* @param opts - optional basePath and env overrides
|
|
53
|
+
*/
|
|
54
|
+
async function hasDeployment(network, key, opts) {
|
|
55
|
+
try {
|
|
56
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
57
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
58
|
+
const data = await readDeployFile(deployPath);
|
|
59
|
+
const addr = data[env]?.[chain]?.[key];
|
|
60
|
+
return !!addr && addr.length > 2 && addr !== "0x";
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Save a deployed contract address to deploy.json.
|
|
68
|
+
* @param network - hardhat network name
|
|
69
|
+
* @param key - contract key (e.g. "Gateway")
|
|
70
|
+
* @param addr - deployed address
|
|
71
|
+
* @param opts - optional basePath and env overrides
|
|
72
|
+
*/
|
|
73
|
+
async function saveDeployment(network, key, addr, opts) {
|
|
74
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
75
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
76
|
+
const data = await readDeployFile(deployPath);
|
|
77
|
+
if (!data[env])
|
|
78
|
+
data[env] = {};
|
|
79
|
+
if (!data[env][chain])
|
|
80
|
+
data[env][chain] = {};
|
|
81
|
+
data[env][chain][key] = addr;
|
|
82
|
+
const filePath = path.resolve(deployPath, "deploy.json");
|
|
83
|
+
await ensureDir(deployPath);
|
|
84
|
+
await fs.promises.writeFile(filePath, JSON.stringify(data, null, "\t"));
|
|
85
|
+
}
|
|
86
|
+
async function readDeployFile(basePath) {
|
|
87
|
+
const filePath = path.resolve(basePath, "deploy.json");
|
|
88
|
+
try {
|
|
89
|
+
const rawdata = await fs.promises.readFile(filePath, "utf-8");
|
|
90
|
+
return JSON.parse(rawdata);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function ensureDir(dirPath) {
|
|
97
|
+
const absPath = path.resolve(dirPath);
|
|
98
|
+
try {
|
|
99
|
+
await fs.promises.stat(absPath);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
await fs.promises.mkdir(absPath, { recursive: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified deployer — auto-routes to EVM or Tron based on network name.
|
|
3
|
+
*
|
|
4
|
+
* Usage in hardhat tasks:
|
|
5
|
+
* const deployer = createDeployer(hre, { autoVerify: true });
|
|
6
|
+
* let addr = await deployer.deploy("Gateway", [admin], salt);
|
|
7
|
+
* let { proxy, implementation } = await deployer.deployProxy("Gateway", [admin], salt);
|
|
8
|
+
* let newImpl = await deployer.upgrade("Gateway", proxyAddr);
|
|
9
|
+
*/
|
|
10
|
+
export interface DeployerOptions {
|
|
11
|
+
autoVerify?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface DeployResult {
|
|
14
|
+
address: string;
|
|
15
|
+
hex?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DeployProxyResult {
|
|
18
|
+
proxy: string;
|
|
19
|
+
implementation: string;
|
|
20
|
+
proxyHex?: string;
|
|
21
|
+
implementationHex?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface Deployer {
|
|
24
|
+
deploy(contractName: string, args?: any[], salt?: string): Promise<DeployResult>;
|
|
25
|
+
deployProxy(contractName: string, initArgs?: any[], salt?: string): Promise<DeployProxyResult>;
|
|
26
|
+
upgrade(contractName: string, proxyAddr: string): Promise<DeployResult>;
|
|
27
|
+
verify(contractName: string, address: string, constructorArgs?: any[], contractPath?: string): Promise<void>;
|
|
28
|
+
isTron: boolean;
|
|
29
|
+
network: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a unified deployer that auto-routes to EVM or Tron based on network.
|
|
33
|
+
* @param hre - hardhat runtime environment
|
|
34
|
+
* @param opts - options (autoVerify: auto-verify after deploy, defaults to false)
|
|
35
|
+
*/
|
|
36
|
+
export declare function createDeployer(hre: any, opts?: DeployerOptions): Deployer;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDeployer = createDeployer;
|
|
4
|
+
const tronHelper_1 = require("./tronHelper");
|
|
5
|
+
const evmHelper_1 = require("./evmHelper");
|
|
6
|
+
const verifier_1 = require("./verifier");
|
|
7
|
+
/**
|
|
8
|
+
* Create a unified deployer that auto-routes to EVM or Tron based on network.
|
|
9
|
+
* @param hre - hardhat runtime environment
|
|
10
|
+
* @param opts - options (autoVerify: auto-verify after deploy, defaults to false)
|
|
11
|
+
*/
|
|
12
|
+
function createDeployer(hre, opts = {}) {
|
|
13
|
+
const network = hre.network.name;
|
|
14
|
+
const isTron = (0, tronHelper_1.isTronNetwork)(network);
|
|
15
|
+
const autoVerify = opts.autoVerify || false;
|
|
16
|
+
async function tryVerify(contractName, address, constructorArgs, contractPath) {
|
|
17
|
+
if (!autoVerify)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
await (0, verifier_1.verify)(hre, { contractName, address, constructorArgs, contractPath });
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
console.log(`[warn] auto-verify failed: ${e.message || e}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (isTron) {
|
|
27
|
+
const client = tronHelper_1.TronClient.fromHre(hre);
|
|
28
|
+
return {
|
|
29
|
+
isTron: true,
|
|
30
|
+
network,
|
|
31
|
+
async deploy(contractName, args = [], salt = "") {
|
|
32
|
+
let result = await client.deploy(hre.artifacts, contractName, args, salt);
|
|
33
|
+
await tryVerify(contractName, result.base58, args);
|
|
34
|
+
return { address: result.base58, hex: result.hex };
|
|
35
|
+
},
|
|
36
|
+
async deployProxy(contractName, initArgs = [], salt = "") {
|
|
37
|
+
let result = await client.deployProxy(hre.artifacts, contractName, initArgs, salt);
|
|
38
|
+
await tryVerify(contractName, result.implementation.base58);
|
|
39
|
+
return {
|
|
40
|
+
proxy: result.proxy.base58,
|
|
41
|
+
implementation: result.implementation.base58,
|
|
42
|
+
proxyHex: result.proxy.hex,
|
|
43
|
+
implementationHex: result.implementation.hex,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
async upgrade(contractName, proxyAddr) {
|
|
47
|
+
let result = await client.upgradeProxy(hre.artifacts, contractName, proxyAddr);
|
|
48
|
+
await tryVerify(contractName, result.base58);
|
|
49
|
+
return { address: result.base58, hex: result.hex };
|
|
50
|
+
},
|
|
51
|
+
async verify(contractName, address, constructorArgs, contractPath) {
|
|
52
|
+
await (0, verifier_1.verify)(hre, { contractName, address, constructorArgs, contractPath });
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// EVM
|
|
57
|
+
const { ethers, artifacts } = hre;
|
|
58
|
+
return {
|
|
59
|
+
isTron: false,
|
|
60
|
+
network,
|
|
61
|
+
async deploy(contractName, args = [], salt = "") {
|
|
62
|
+
let addr = await (0, evmHelper_1.evmDeploy)(ethers, artifacts, contractName, args, salt);
|
|
63
|
+
await tryVerify(contractName, addr, args);
|
|
64
|
+
return { address: addr };
|
|
65
|
+
},
|
|
66
|
+
async deployProxy(contractName, initArgs = [], salt = "") {
|
|
67
|
+
let result = await (0, evmHelper_1.evmDeployProxy)(ethers, artifacts, contractName, initArgs, salt);
|
|
68
|
+
await tryVerify(contractName, result.implementation);
|
|
69
|
+
return { proxy: result.proxy, implementation: result.implementation };
|
|
70
|
+
},
|
|
71
|
+
async upgrade(contractName, proxyAddr) {
|
|
72
|
+
let addr = await (0, evmHelper_1.evmUpgradeProxy)(ethers, contractName, proxyAddr);
|
|
73
|
+
await tryVerify(contractName, addr);
|
|
74
|
+
return { address: addr };
|
|
75
|
+
},
|
|
76
|
+
async verify(contractName, address, constructorArgs, contractPath) {
|
|
77
|
+
await (0, verifier_1.verify)(hre, { contractName, address, constructorArgs, contractPath });
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy contract on EVM. If salt is provided, uses CREATE2 factory for deterministic address.
|
|
3
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
4
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
5
|
+
* @param contractName - contract name to deploy
|
|
6
|
+
* @param args - constructor arguments array
|
|
7
|
+
* @param salt - optional CREATE2 salt for deterministic address
|
|
8
|
+
* @returns deployed contract address (0x hex)
|
|
9
|
+
*/
|
|
10
|
+
export declare function evmDeploy(ethers: any, artifacts: any, contractName: string, args?: any[], salt?: string): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Deploy implementation + ERC1967 proxy in one step.
|
|
13
|
+
* If salt is provided, proxy is deployed via factory.
|
|
14
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
15
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
16
|
+
* @param contractName - implementation contract name
|
|
17
|
+
* @param initArgs - initialize() function arguments
|
|
18
|
+
* @param salt - optional CREATE2 salt for proxy
|
|
19
|
+
* @returns { proxy, implementation } addresses
|
|
20
|
+
*/
|
|
21
|
+
export declare function evmDeployProxy(ethers: any, artifacts: any, contractName: string, initArgs?: any[], salt?: string): Promise<{
|
|
22
|
+
proxy: string;
|
|
23
|
+
implementation: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Upgrade a UUPS proxy to a new implementation.
|
|
27
|
+
* Deploys new implementation, then calls upgradeToAndCall on the proxy.
|
|
28
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
29
|
+
* @param contractName - new implementation contract name
|
|
30
|
+
* @param proxyAddr - proxy address to upgrade
|
|
31
|
+
* @returns new implementation address
|
|
32
|
+
*/
|
|
33
|
+
export declare function evmUpgradeProxy(ethers: any, contractName: string, proxyAddr: string): Promise<string>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evmDeploy = evmDeploy;
|
|
4
|
+
exports.evmDeployProxy = evmDeployProxy;
|
|
5
|
+
exports.evmUpgradeProxy = evmUpgradeProxy;
|
|
6
|
+
/**
|
|
7
|
+
* Deploy contract on EVM. If salt is provided, uses CREATE2 factory for deterministic address.
|
|
8
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
9
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
10
|
+
* @param contractName - contract name to deploy
|
|
11
|
+
* @param args - constructor arguments array
|
|
12
|
+
* @param salt - optional CREATE2 salt for deterministic address
|
|
13
|
+
* @returns deployed contract address (0x hex)
|
|
14
|
+
*/
|
|
15
|
+
async function evmDeploy(ethers, artifacts, contractName, args = [], salt = "") {
|
|
16
|
+
if (salt) {
|
|
17
|
+
const { evmDeployByFactory } = require("./factory");
|
|
18
|
+
const artifact = await artifacts.readArtifact(contractName);
|
|
19
|
+
const constructorArgs = args.length > 0
|
|
20
|
+
? ethers.AbiCoder.defaultAbiCoder().encode(artifact.abi
|
|
21
|
+
.find((x) => x.type === "constructor")
|
|
22
|
+
?.inputs.map((i) => i.type) || [], args)
|
|
23
|
+
: "0x";
|
|
24
|
+
return evmDeployByFactory(ethers, salt, artifact.bytecode, constructorArgs);
|
|
25
|
+
}
|
|
26
|
+
const [deployer] = await ethers.getSigners();
|
|
27
|
+
console.log("deploy address is:", deployer.address);
|
|
28
|
+
const ContractFactory = await ethers.getContractFactory(contractName);
|
|
29
|
+
const contract = await (await ContractFactory.deploy(...args)).waitForDeployment();
|
|
30
|
+
const addr = await contract.getAddress();
|
|
31
|
+
console.log(`${contractName} deployed: ${addr}`);
|
|
32
|
+
return addr;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Deploy implementation + ERC1967 proxy in one step.
|
|
36
|
+
* If salt is provided, proxy is deployed via factory.
|
|
37
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
38
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
39
|
+
* @param contractName - implementation contract name
|
|
40
|
+
* @param initArgs - initialize() function arguments
|
|
41
|
+
* @param salt - optional CREATE2 salt for proxy
|
|
42
|
+
* @returns { proxy, implementation } addresses
|
|
43
|
+
*/
|
|
44
|
+
async function evmDeployProxy(ethers, artifacts, contractName, initArgs = [], salt = "") {
|
|
45
|
+
const ImplFactory = await ethers.getContractFactory(contractName);
|
|
46
|
+
const impl = await (await ImplFactory.deploy()).waitForDeployment();
|
|
47
|
+
const implAddr = await impl.getAddress();
|
|
48
|
+
console.log(`${contractName} implementation: ${implAddr}`);
|
|
49
|
+
const initData = ImplFactory.interface.encodeFunctionData("initialize", initArgs);
|
|
50
|
+
let proxyAddr;
|
|
51
|
+
if (salt) {
|
|
52
|
+
const { evmDeployByFactory } = require("./factory");
|
|
53
|
+
const proxyArtifact = await artifacts.readArtifact("ERC1967Proxy");
|
|
54
|
+
const constructorArgs = ethers.AbiCoder.defaultAbiCoder().encode(["address", "bytes"], [implAddr, initData]);
|
|
55
|
+
proxyAddr = await evmDeployByFactory(ethers, salt, proxyArtifact.bytecode, constructorArgs);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const ProxyFactory = await ethers.getContractFactory("ERC1967Proxy");
|
|
59
|
+
const proxy = await (await ProxyFactory.deploy(implAddr, initData)).waitForDeployment();
|
|
60
|
+
proxyAddr = await proxy.getAddress();
|
|
61
|
+
}
|
|
62
|
+
console.log(`${contractName} proxy: ${proxyAddr}`);
|
|
63
|
+
return { proxy: proxyAddr, implementation: implAddr };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Upgrade a UUPS proxy to a new implementation.
|
|
67
|
+
* Deploys new implementation, then calls upgradeToAndCall on the proxy.
|
|
68
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
69
|
+
* @param contractName - new implementation contract name
|
|
70
|
+
* @param proxyAddr - proxy address to upgrade
|
|
71
|
+
* @returns new implementation address
|
|
72
|
+
*/
|
|
73
|
+
async function evmUpgradeProxy(ethers, contractName, proxyAddr) {
|
|
74
|
+
const [deployer] = await ethers.getSigners();
|
|
75
|
+
const ImplFactory = await ethers.getContractFactory(contractName);
|
|
76
|
+
const impl = await (await ImplFactory.deploy()).waitForDeployment();
|
|
77
|
+
const implAddr = await impl.getAddress();
|
|
78
|
+
const proxy = await ethers.getContractAt("BaseImplementation", proxyAddr, deployer);
|
|
79
|
+
const oldImpl = await proxy.getImplementation();
|
|
80
|
+
await (await proxy.upgradeToAndCall(implAddr, "0x")).wait();
|
|
81
|
+
console.log(`${contractName} upgraded: ${oldImpl} -> ${implAddr}`);
|
|
82
|
+
return implAddr;
|
|
83
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy contract via CREATE3 factory on EVM chains.
|
|
3
|
+
* Address only depends on salt, not bytecode.
|
|
4
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
5
|
+
* @param salt - human-readable salt string
|
|
6
|
+
* @param bytecode - contract bytecode (artifact.bytecode)
|
|
7
|
+
* @param constructorArgs - ABI-encoded constructor arguments
|
|
8
|
+
* @returns deployed contract address
|
|
9
|
+
*/
|
|
10
|
+
export declare function evmDeployByFactory(ethers: any, salt: string, bytecode: string, constructorArgs?: string): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Get predicted factory address for a salt on EVM (CREATE3 — only needs salt).
|
|
13
|
+
* @param ethers - ethers from hardhat runtime
|
|
14
|
+
* @param salt - human-readable salt string
|
|
15
|
+
*/
|
|
16
|
+
export declare function evmGetFactoryAddress(ethers: any, salt: string): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Deploy contract via CREATE2 factory on Tron.
|
|
19
|
+
* Address depends on salt + creationCode (bytecode + constructor args).
|
|
20
|
+
* @param tronWeb - initialized tronweb instance
|
|
21
|
+
* @param artifacts - hardhat artifacts
|
|
22
|
+
* @param contractName - contract name to deploy
|
|
23
|
+
* @param salt - human-readable salt string
|
|
24
|
+
* @param args - constructor arguments array
|
|
25
|
+
* @param feeLimit - tron fee limit
|
|
26
|
+
* @returns deployed contract address (0x-prefixed hex)
|
|
27
|
+
*/
|
|
28
|
+
export declare function tronDeployByFactory(tronWeb: any, artifacts: any, contractName: string, salt: string, args?: any[], feeLimit?: number): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Get predicted factory address for a salt on Tron (CREATE2 — needs salt + codeHash).
|
|
31
|
+
* @param tronWeb - initialized tronweb instance
|
|
32
|
+
* @param salt - human-readable salt string
|
|
33
|
+
* @param codeHash - keccak256 of creationCode (bytecode + constructor args)
|
|
34
|
+
* @returns address in base58 format
|
|
35
|
+
*/
|
|
36
|
+
export declare function tronGetFactoryAddress(tronWeb: any, salt: string, codeHash: string): Promise<string>;
|