@mapprotocol/common-contracts 0.3.1 → 0.4.0
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/README.md +30 -100
- package/package.json +18 -3
- package/script/base/Base.s.sol +231 -0
- package/script/base/interfaces/IFactory.sol +7 -0
- package/utils/deployer.ts +15 -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 +48 -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 +24 -0
- package/utils/dist/verifier.js +229 -0
- package/utils/verifier.ts +72 -41
|
@@ -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,48 @@
|
|
|
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
|
+
/**
|
|
12
|
+
* Auto-verify contracts after deploy/upgrade.
|
|
13
|
+
* Failures are logged as warnings, never thrown — call deployer.verify() for explicit error handling.
|
|
14
|
+
* Defaults to false.
|
|
15
|
+
*/
|
|
16
|
+
autoVerify?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface DeployResult {
|
|
19
|
+
address: string;
|
|
20
|
+
hex?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface DeployProxyResult {
|
|
23
|
+
proxy: string;
|
|
24
|
+
implementation: string;
|
|
25
|
+
proxyHex?: string;
|
|
26
|
+
implementationHex?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface Deployer {
|
|
29
|
+
/**
|
|
30
|
+
* Deploy a contract.
|
|
31
|
+
* @param contractName - artifact name
|
|
32
|
+
* @param args - constructor arguments as raw values
|
|
33
|
+
* @param salt - "" or omitted = direct deploy; non-empty string = CREATE2 factory (deterministic address)
|
|
34
|
+
*/
|
|
35
|
+
deploy(contractName: string, args?: any[], salt?: string): Promise<DeployResult>;
|
|
36
|
+
deployProxy(contractName: string, initArgs?: any[], salt?: string): Promise<DeployProxyResult>;
|
|
37
|
+
upgrade(contractName: string, proxyAddr: string): Promise<DeployResult>;
|
|
38
|
+
/** Verify explicitly (throws on failure, unlike autoVerify which only warns). */
|
|
39
|
+
verify(contractName: string, address: string, constructorArgs?: any[], contractPath?: string): Promise<void>;
|
|
40
|
+
isTron: boolean;
|
|
41
|
+
network: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a unified deployer that auto-routes to EVM or Tron based on network.
|
|
45
|
+
* @param hre - hardhat runtime environment
|
|
46
|
+
* @param opts - options (autoVerify: auto-verify after deploy, defaults to false)
|
|
47
|
+
*/
|
|
48
|
+
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>;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evmDeployByFactory = evmDeployByFactory;
|
|
4
|
+
exports.evmGetFactoryAddress = evmGetFactoryAddress;
|
|
5
|
+
exports.tronDeployByFactory = tronDeployByFactory;
|
|
6
|
+
exports.tronGetFactoryAddress = tronGetFactoryAddress;
|
|
7
|
+
/**
|
|
8
|
+
* Factory deployment — deterministic contract addresses across chains.
|
|
9
|
+
* EVM: CREATE3 factory at 0x6258e4d2950757A749a4d4683A7342261ce12471
|
|
10
|
+
* Tron: CREATE2 factory at TJAwD5VfMYMGWwdPi2aVcoQwVBfsuw5wQt
|
|
11
|
+
*/
|
|
12
|
+
const tronHelper_1 = require("./tronHelper");
|
|
13
|
+
// Factory contract addresses
|
|
14
|
+
const EVM_FACTORY = "0x6258e4d2950757A749a4d4683A7342261ce12471";
|
|
15
|
+
const TRON_FACTORY = "TJAwD5VfMYMGWwdPi2aVcoQwVBfsuw5wQt";
|
|
16
|
+
// EVM factory ABI (CREATE3 — getAddress only needs salt)
|
|
17
|
+
// function deploy(bytes32 salt, bytes creationCode, uint256 value)
|
|
18
|
+
// function getAddress(bytes32 salt) view returns (address)
|
|
19
|
+
const EVM_FACTORY_ABI = [
|
|
20
|
+
{
|
|
21
|
+
"inputs": [{ "name": "salt", "type": "bytes32" }, { "name": "creationCode", "type": "bytes" }, { "name": "value", "type": "uint256" }],
|
|
22
|
+
"name": "deploy",
|
|
23
|
+
"outputs": [],
|
|
24
|
+
"stateMutability": "nonpayable",
|
|
25
|
+
"type": "function"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"inputs": [{ "name": "salt", "type": "bytes32" }],
|
|
29
|
+
"name": "getAddress",
|
|
30
|
+
"outputs": [{ "name": "", "type": "address" }],
|
|
31
|
+
"stateMutability": "view",
|
|
32
|
+
"type": "function"
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
// Tron factory ABI (CREATE2 — getAddress needs salt + codeHash)
|
|
36
|
+
// function deploy(bytes32 salt, bytes creationCode, uint256 value) returns (address)
|
|
37
|
+
// function getAddress(bytes32 salt, bytes32 codeHash) view returns (address)
|
|
38
|
+
// function getAddressTron(bytes32 salt, bytes32 codeHash) view returns (address)
|
|
39
|
+
const TRON_FACTORY_ABI = [
|
|
40
|
+
{
|
|
41
|
+
"inputs": [{ "name": "salt", "type": "bytes32" }, { "name": "creationCode", "type": "bytes" }, { "name": "value", "type": "uint256" }],
|
|
42
|
+
"name": "deploy",
|
|
43
|
+
"outputs": [{ "name": "addr", "type": "address" }],
|
|
44
|
+
"stateMutability": "nonpayable",
|
|
45
|
+
"type": "function"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"inputs": [{ "name": "salt", "type": "bytes32" }, { "name": "codeHash", "type": "bytes32" }],
|
|
49
|
+
"name": "getAddressTron",
|
|
50
|
+
"outputs": [{ "name": "", "type": "address" }],
|
|
51
|
+
"stateMutability": "view",
|
|
52
|
+
"type": "function"
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
// ============================================================
|
|
56
|
+
// EVM Factory (CREATE3, ethers.js)
|
|
57
|
+
// ============================================================
|
|
58
|
+
/**
|
|
59
|
+
* Deploy contract via CREATE3 factory on EVM chains.
|
|
60
|
+
* Address only depends on salt, not bytecode.
|
|
61
|
+
* @param ethers - ethers from hardhat runtime (hre.ethers)
|
|
62
|
+
* @param salt - human-readable salt string
|
|
63
|
+
* @param bytecode - contract bytecode (artifact.bytecode)
|
|
64
|
+
* @param constructorArgs - ABI-encoded constructor arguments
|
|
65
|
+
* @returns deployed contract address
|
|
66
|
+
*/
|
|
67
|
+
async function evmDeployByFactory(ethers, salt, bytecode, constructorArgs = "0x") {
|
|
68
|
+
const [signer] = await ethers.getSigners();
|
|
69
|
+
const factory = new ethers.Contract(EVM_FACTORY, EVM_FACTORY_ABI, signer);
|
|
70
|
+
const code = await ethers.provider.getCode(EVM_FACTORY);
|
|
71
|
+
if (code === "0x")
|
|
72
|
+
throw new Error("factory not deployed on this chain");
|
|
73
|
+
const saltHash = ethers.keccak256(ethers.toUtf8Bytes(salt));
|
|
74
|
+
const predicted = await factory.getAddress(saltHash);
|
|
75
|
+
const existingCode = await ethers.provider.getCode(predicted);
|
|
76
|
+
if (existingCode !== "0x") {
|
|
77
|
+
console.log(`already deployed at ${predicted}`);
|
|
78
|
+
return predicted;
|
|
79
|
+
}
|
|
80
|
+
const fullBytecode = constructorArgs === "0x"
|
|
81
|
+
? bytecode
|
|
82
|
+
: ethers.concat([bytecode, constructorArgs]);
|
|
83
|
+
const tx = await factory.deploy(saltHash, fullBytecode, 0);
|
|
84
|
+
await tx.wait();
|
|
85
|
+
// Verify contract was actually deployed
|
|
86
|
+
const deployedCode = await ethers.provider.getCode(predicted);
|
|
87
|
+
if (deployedCode === "0x") {
|
|
88
|
+
throw new Error(`factory deploy failed: no contract at predicted address ${predicted}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`deployed via factory at ${predicted}`);
|
|
91
|
+
return predicted;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get predicted factory address for a salt on EVM (CREATE3 — only needs salt).
|
|
95
|
+
* @param ethers - ethers from hardhat runtime
|
|
96
|
+
* @param salt - human-readable salt string
|
|
97
|
+
*/
|
|
98
|
+
async function evmGetFactoryAddress(ethers, salt) {
|
|
99
|
+
const factory = new ethers.Contract(EVM_FACTORY, EVM_FACTORY_ABI, await ethers.provider);
|
|
100
|
+
const saltHash = ethers.keccak256(ethers.toUtf8Bytes(salt));
|
|
101
|
+
return factory.getAddress(saltHash);
|
|
102
|
+
}
|
|
103
|
+
// ============================================================
|
|
104
|
+
// Tron Factory (CREATE2, tronweb)
|
|
105
|
+
// ============================================================
|
|
106
|
+
/**
|
|
107
|
+
* Deploy contract via CREATE2 factory on Tron.
|
|
108
|
+
* Address depends on salt + creationCode (bytecode + constructor args).
|
|
109
|
+
* @param tronWeb - initialized tronweb instance
|
|
110
|
+
* @param artifacts - hardhat artifacts
|
|
111
|
+
* @param contractName - contract name to deploy
|
|
112
|
+
* @param salt - human-readable salt string
|
|
113
|
+
* @param args - constructor arguments array
|
|
114
|
+
* @param feeLimit - tron fee limit
|
|
115
|
+
* @returns deployed contract address (0x-prefixed hex)
|
|
116
|
+
*/
|
|
117
|
+
async function tronDeployByFactory(tronWeb, artifacts, contractName, salt, args = [], feeLimit = 15000000000) {
|
|
118
|
+
const factory = await tronWeb.contract(TRON_FACTORY_ABI, TRON_FACTORY);
|
|
119
|
+
const saltHash = tronWeb.sha3(salt);
|
|
120
|
+
// Build creation code with constructor args
|
|
121
|
+
const artifact = await artifacts.readArtifact(contractName);
|
|
122
|
+
let creationCode = artifact.bytecode;
|
|
123
|
+
if (args.length > 0) {
|
|
124
|
+
const iface = new (require("ethers").Interface)(artifact.abi);
|
|
125
|
+
const encoded = iface.encodeDeploy(args);
|
|
126
|
+
creationCode = creationCode + encoded.slice(2);
|
|
127
|
+
}
|
|
128
|
+
// Check if already deployed
|
|
129
|
+
const codeHash = tronWeb.sha3(creationCode);
|
|
130
|
+
const predicted = await factory.getAddressTron(saltHash, codeHash).call();
|
|
131
|
+
const predictedHex = predicted.replace(/^41/, "0x");
|
|
132
|
+
try {
|
|
133
|
+
const existing = await tronWeb.trx.getContract(tronWeb.address.fromHex(predicted));
|
|
134
|
+
if (existing && existing.bytecode) {
|
|
135
|
+
console.log(`already deployed at ${(0, tronHelper_1.tronFromHex)(predicted)}`);
|
|
136
|
+
return predictedHex;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch { }
|
|
140
|
+
// Deploy
|
|
141
|
+
console.log(`deploying ${contractName} via factory with salt "${salt}"...`);
|
|
142
|
+
const { sendAndWait } = require("./tronHelper");
|
|
143
|
+
const txResult = await sendAndWait(factory.deploy(saltHash, creationCode, 0), tronWeb, { feeLimit });
|
|
144
|
+
// Read actual address from Deployed event
|
|
145
|
+
let addrHex = predictedHex; // fallback to predicted
|
|
146
|
+
if (txResult.log && txResult.log.length > 0) {
|
|
147
|
+
// Deployed(address indexed addr, bytes32 indexed salt)
|
|
148
|
+
// First topic = event sig, second topic = addr
|
|
149
|
+
const addrTopic = txResult.log[0].topics?.[1];
|
|
150
|
+
if (addrTopic) {
|
|
151
|
+
addrHex = "0x" + addrTopic.slice(24); // last 20 bytes
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Verify contract was actually deployed
|
|
155
|
+
const addrBase58 = (0, tronHelper_1.tronFromHex)(addrHex);
|
|
156
|
+
try {
|
|
157
|
+
const deployed = await tronWeb.trx.getContract(addrBase58);
|
|
158
|
+
if (!deployed || !deployed.bytecode) {
|
|
159
|
+
throw new Error(`factory deploy failed: no contract at ${addrBase58}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
if (e.message?.includes("factory deploy failed"))
|
|
164
|
+
throw e;
|
|
165
|
+
// Contract might not be indexed yet, wait and retry
|
|
166
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
167
|
+
const deployed = await tronWeb.trx.getContract(addrBase58);
|
|
168
|
+
if (!deployed || !deployed.bytecode) {
|
|
169
|
+
throw new Error(`factory deploy failed: no contract at ${addrBase58}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
console.log(`${contractName} deployed: ${addrBase58} (${addrHex})`);
|
|
173
|
+
return addrHex;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get predicted factory address for a salt on Tron (CREATE2 — needs salt + codeHash).
|
|
177
|
+
* @param tronWeb - initialized tronweb instance
|
|
178
|
+
* @param salt - human-readable salt string
|
|
179
|
+
* @param codeHash - keccak256 of creationCode (bytecode + constructor args)
|
|
180
|
+
* @returns address in base58 format
|
|
181
|
+
*/
|
|
182
|
+
async function tronGetFactoryAddress(tronWeb, salt, codeHash) {
|
|
183
|
+
const factory = await tronWeb.contract(TRON_FACTORY_ABI, TRON_FACTORY);
|
|
184
|
+
const saltHash = tronWeb.sha3(salt);
|
|
185
|
+
const addr = await factory.getAddressTron(saltHash, codeHash).call();
|
|
186
|
+
return (0, tronHelper_1.tronFromHex)(addr);
|
|
187
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mapprotocol/common-contracts/utils
|
|
3
|
+
*
|
|
4
|
+
* Shared TypeScript utilities for MAP Protocol contract operations.
|
|
5
|
+
*
|
|
6
|
+
* Quick start:
|
|
7
|
+
* const deployer = createDeployer(hre, { autoVerify: true });
|
|
8
|
+
* await deployer.deploy("MyContract", [arg1], "optional_salt");
|
|
9
|
+
* await deployer.deployProxy("MyContract", [initArg], "optional_salt");
|
|
10
|
+
* await deployer.upgrade("MyContract", proxyAddr);
|
|
11
|
+
*/
|
|
12
|
+
export { createDeployer, type Deployer, type DeployResult, type DeployProxyResult, type DeployerOptions } from "./deployer";
|
|
13
|
+
export { resolveDeploymentPath, getDeploymentByKey, hasDeployment, saveDeployment, type DeploymentPath, type DeploymentOptions } from "./deployRecord";
|
|
14
|
+
export { verify, type VerifyOptions } from "./verifier";
|
|
15
|
+
export { getCodeHash, getProxyCodeHash, getCustomProxyCodeHash } from "./codeHash";
|
|
16
|
+
export { addressToHex, isBase58, isTronAddress, isSolanaChain } from "./addressCodec";
|
|
17
|
+
export { TronClient, tronFromHex, tronToHex, isTronNetwork, sendAndWait, waitForTx, type TronAddress } from "./tronHelper";
|