@mapprotocol/common-contracts 0.1.1 → 0.3.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 +114 -58
- package/artifacts/contracts/AuthorityManager.sol/AuthorityManager.json +2 -2
- package/artifacts/contracts/factory/Create2Factory.sol/Create2Factory.json +107 -0
- package/contracts/factory/Create2Factory.sol +57 -0
- package/package.json +15 -3
- package/typechain-types/contracts/factory/Create2Factory.ts +174 -0
- package/typechain-types/contracts/factory/index.ts +4 -0
- package/typechain-types/contracts/index.ts +2 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/manager/AccessManager__factory.ts +1 -1
- package/typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils__factory.ts +1 -1
- package/typechain-types/factories/@openzeppelin/contracts/utils/Address__factory.ts +1 -1
- package/typechain-types/factories/@openzeppelin/contracts/utils/Errors__factory.ts +1 -1
- package/typechain-types/factories/@openzeppelin/contracts/utils/math/SafeCast__factory.ts +1 -1
- package/typechain-types/factories/contracts/AuthorityManager__factory.ts +1 -1
- package/typechain-types/factories/contracts/factory/Create2Factory__factory.ts +163 -0
- package/typechain-types/factories/contracts/factory/index.ts +4 -0
- package/typechain-types/factories/contracts/index.ts +1 -0
- package/typechain-types/hardhat.d.ts +18 -0
- package/typechain-types/index.ts +2 -0
- package/utils/addressCodec.ts +57 -0
- package/utils/codeHash.ts +75 -0
- package/utils/deployRecord.ts +117 -0
- package/utils/deployer.ts +123 -0
- package/utils/evmHelper.ts +108 -0
- package/utils/factory.ts +210 -0
- package/utils/index.ts +42 -0
- package/utils/tronHelper.ts +362 -0
- package/utils/verifier.ts +225 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/* Autogenerated file. Do not edit manually. */
|
|
2
|
+
/* tslint:disable */
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
import {
|
|
5
|
+
Contract,
|
|
6
|
+
ContractFactory,
|
|
7
|
+
ContractTransactionResponse,
|
|
8
|
+
Interface,
|
|
9
|
+
} from "ethers";
|
|
10
|
+
import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers";
|
|
11
|
+
import type { NonPayableOverrides } from "../../../common";
|
|
12
|
+
import type {
|
|
13
|
+
Create2Factory,
|
|
14
|
+
Create2FactoryInterface,
|
|
15
|
+
} from "../../../contracts/factory/Create2Factory";
|
|
16
|
+
|
|
17
|
+
const _abi = [
|
|
18
|
+
{
|
|
19
|
+
anonymous: false,
|
|
20
|
+
inputs: [
|
|
21
|
+
{
|
|
22
|
+
indexed: true,
|
|
23
|
+
internalType: "address",
|
|
24
|
+
name: "addr",
|
|
25
|
+
type: "address",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
indexed: true,
|
|
29
|
+
internalType: "bytes32",
|
|
30
|
+
name: "salt",
|
|
31
|
+
type: "bytes32",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
name: "Deployed",
|
|
35
|
+
type: "event",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
inputs: [
|
|
39
|
+
{
|
|
40
|
+
internalType: "bytes32",
|
|
41
|
+
name: "salt",
|
|
42
|
+
type: "bytes32",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
internalType: "bytes",
|
|
46
|
+
name: "creationCode",
|
|
47
|
+
type: "bytes",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
internalType: "uint256",
|
|
51
|
+
name: "value",
|
|
52
|
+
type: "uint256",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
name: "deploy",
|
|
56
|
+
outputs: [
|
|
57
|
+
{
|
|
58
|
+
internalType: "address",
|
|
59
|
+
name: "addr",
|
|
60
|
+
type: "address",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
stateMutability: "nonpayable",
|
|
64
|
+
type: "function",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
inputs: [
|
|
68
|
+
{
|
|
69
|
+
internalType: "bytes32",
|
|
70
|
+
name: "salt",
|
|
71
|
+
type: "bytes32",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
internalType: "bytes32",
|
|
75
|
+
name: "codeHash",
|
|
76
|
+
type: "bytes32",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
name: "getAddress",
|
|
80
|
+
outputs: [
|
|
81
|
+
{
|
|
82
|
+
internalType: "address",
|
|
83
|
+
name: "",
|
|
84
|
+
type: "address",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
stateMutability: "view",
|
|
88
|
+
type: "function",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
inputs: [
|
|
92
|
+
{
|
|
93
|
+
internalType: "bytes32",
|
|
94
|
+
name: "salt",
|
|
95
|
+
type: "bytes32",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
internalType: "bytes32",
|
|
99
|
+
name: "codeHash",
|
|
100
|
+
type: "bytes32",
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
name: "getAddressTron",
|
|
104
|
+
outputs: [
|
|
105
|
+
{
|
|
106
|
+
internalType: "address",
|
|
107
|
+
name: "",
|
|
108
|
+
type: "address",
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
stateMutability: "view",
|
|
112
|
+
type: "function",
|
|
113
|
+
},
|
|
114
|
+
] as const;
|
|
115
|
+
|
|
116
|
+
const _bytecode =
|
|
117
|
+
"0x6080604052348015600f57600080fd5b506102f98061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063933559b014610046578063c7aeef0f14610075578063d3a3968614610088575b600080fd5b61005961005436600461018e565b61009b565b6040516001600160a01b03909116815260200160405180910390f35b6100596100833660046101c6565b6100d8565b61005961009636600461018e565b61016c565b6040516000906100b990604160f81b9030908690869060200161028a565b60408051601f1981840301815291905280516020909101209392505050565b60008383516020850184f590506001600160a01b03811661012f5760405162461bcd60e51b815260206004820152600d60248201526c1111541313d657d19052531151609a1b604482015260640160405180910390fd5b60405184906001600160a01b038316907f94bfd9af14ef450884c8a7ddb5734e2e1e14e70a1c84f0801cc5a29e34d2642890600090a39392505050565b6040516000906100b9906001600160f81b03199030908690869060200161028a565b600080604083850312156101a157600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156101db57600080fd5b83359250602084013567ffffffffffffffff808211156101fa57600080fd5b818601915086601f83011261020e57600080fd5b813581811115610220576102206101b0565b604051601f8201601f19908116603f01168101908382118183101715610248576102486101b0565b8160405282815289602084870101111561026157600080fd5b826020860160208301376000602084830101528096505050505050604084013590509250925092565b6001600160f81b031994909416845260609290921b6bffffffffffffffffffffffff19166001840152601583015260358201526055019056fea26469706673582212205fb7d781d8404b93aed56d95e5543997fe78a250c5faf35b40c771504b4c853b64736f6c63430008190033";
|
|
118
|
+
|
|
119
|
+
type Create2FactoryConstructorParams =
|
|
120
|
+
| [signer?: Signer]
|
|
121
|
+
| ConstructorParameters<typeof ContractFactory>;
|
|
122
|
+
|
|
123
|
+
const isSuperArgs = (
|
|
124
|
+
xs: Create2FactoryConstructorParams
|
|
125
|
+
): xs is ConstructorParameters<typeof ContractFactory> => xs.length > 1;
|
|
126
|
+
|
|
127
|
+
export class Create2Factory__factory extends ContractFactory {
|
|
128
|
+
constructor(...args: Create2FactoryConstructorParams) {
|
|
129
|
+
if (isSuperArgs(args)) {
|
|
130
|
+
super(...args);
|
|
131
|
+
} else {
|
|
132
|
+
super(_abi, _bytecode, args[0]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
override getDeployTransaction(
|
|
137
|
+
overrides?: NonPayableOverrides & { from?: string }
|
|
138
|
+
): Promise<ContractDeployTransaction> {
|
|
139
|
+
return super.getDeployTransaction(overrides || {});
|
|
140
|
+
}
|
|
141
|
+
override deploy(overrides?: NonPayableOverrides & { from?: string }) {
|
|
142
|
+
return super.deploy(overrides || {}) as Promise<
|
|
143
|
+
Create2Factory & {
|
|
144
|
+
deploymentTransaction(): ContractTransactionResponse;
|
|
145
|
+
}
|
|
146
|
+
>;
|
|
147
|
+
}
|
|
148
|
+
override connect(runner: ContractRunner | null): Create2Factory__factory {
|
|
149
|
+
return super.connect(runner) as Create2Factory__factory;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static readonly bytecode = _bytecode;
|
|
153
|
+
static readonly abi = _abi;
|
|
154
|
+
static createInterface(): Create2FactoryInterface {
|
|
155
|
+
return new Interface(_abi) as Create2FactoryInterface;
|
|
156
|
+
}
|
|
157
|
+
static connect(
|
|
158
|
+
address: string,
|
|
159
|
+
runner?: ContractRunner | null
|
|
160
|
+
): Create2Factory {
|
|
161
|
+
return new Contract(address, _abi, runner) as unknown as Create2Factory;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -89,6 +89,10 @@ declare module "hardhat/types/runtime" {
|
|
|
89
89
|
name: "BaseImplementation",
|
|
90
90
|
signerOrOptions?: ethers.Signer | FactoryOptions
|
|
91
91
|
): Promise<Contracts.BaseImplementation__factory>;
|
|
92
|
+
getContractFactory(
|
|
93
|
+
name: "Create2Factory",
|
|
94
|
+
signerOrOptions?: ethers.Signer | FactoryOptions
|
|
95
|
+
): Promise<Contracts.Create2Factory__factory>;
|
|
92
96
|
|
|
93
97
|
getContractAt(
|
|
94
98
|
name: "AccessManagedUpgradeable",
|
|
@@ -185,6 +189,11 @@ declare module "hardhat/types/runtime" {
|
|
|
185
189
|
address: string | ethers.Addressable,
|
|
186
190
|
signer?: ethers.Signer
|
|
187
191
|
): Promise<Contracts.BaseImplementation>;
|
|
192
|
+
getContractAt(
|
|
193
|
+
name: "Create2Factory",
|
|
194
|
+
address: string | ethers.Addressable,
|
|
195
|
+
signer?: ethers.Signer
|
|
196
|
+
): Promise<Contracts.Create2Factory>;
|
|
188
197
|
|
|
189
198
|
deployContract(
|
|
190
199
|
name: "AccessManagedUpgradeable",
|
|
@@ -262,6 +271,10 @@ declare module "hardhat/types/runtime" {
|
|
|
262
271
|
name: "BaseImplementation",
|
|
263
272
|
signerOrOptions?: ethers.Signer | DeployContractOptions
|
|
264
273
|
): Promise<Contracts.BaseImplementation>;
|
|
274
|
+
deployContract(
|
|
275
|
+
name: "Create2Factory",
|
|
276
|
+
signerOrOptions?: ethers.Signer | DeployContractOptions
|
|
277
|
+
): Promise<Contracts.Create2Factory>;
|
|
265
278
|
|
|
266
279
|
deployContract(
|
|
267
280
|
name: "AccessManagedUpgradeable",
|
|
@@ -358,6 +371,11 @@ declare module "hardhat/types/runtime" {
|
|
|
358
371
|
args: any[],
|
|
359
372
|
signerOrOptions?: ethers.Signer | DeployContractOptions
|
|
360
373
|
): Promise<Contracts.BaseImplementation>;
|
|
374
|
+
deployContract(
|
|
375
|
+
name: "Create2Factory",
|
|
376
|
+
args: any[],
|
|
377
|
+
signerOrOptions?: ethers.Signer | DeployContractOptions
|
|
378
|
+
): Promise<Contracts.Create2Factory>;
|
|
361
379
|
|
|
362
380
|
// default types
|
|
363
381
|
getContractFactory(
|
package/typechain-types/index.ts
CHANGED
|
@@ -44,3 +44,5 @@ export type { AuthorityManager } from "./contracts/AuthorityManager";
|
|
|
44
44
|
export { AuthorityManager__factory } from "./factories/contracts/AuthorityManager__factory";
|
|
45
45
|
export type { BaseImplementation } from "./contracts/base/BaseImplementation";
|
|
46
46
|
export { BaseImplementation__factory } from "./factories/contracts/base/BaseImplementation__factory";
|
|
47
|
+
export type { Create2Factory } from "./contracts/factory/Create2Factory";
|
|
48
|
+
export { Create2Factory__factory } from "./factories/contracts/factory/Create2Factory__factory";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-chain address encoding — converts EVM, Tron, and Solana addresses to hex bytes.
|
|
3
|
+
*/
|
|
4
|
+
import bs58 from "bs58";
|
|
5
|
+
import { tronToHex } from "./tronHelper";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert any address format to hex bytes.
|
|
9
|
+
* - EVM address (0x prefix): return as-is lowercase
|
|
10
|
+
* - Tron address (T prefix, 34 chars, 0x41 byte): convert via tronToHex
|
|
11
|
+
* - Solana/other base58 address: base58 decode to full bytes
|
|
12
|
+
* @param addr - address in any supported format
|
|
13
|
+
*/
|
|
14
|
+
export function addressToHex(addr: string): string {
|
|
15
|
+
if (addr.startsWith("0x")) {
|
|
16
|
+
return addr.toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (isTronAddress(addr)) {
|
|
20
|
+
return tronToHex(addr);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isBase58(addr)) {
|
|
24
|
+
const decoded = bs58.decode(addr);
|
|
25
|
+
return "0x" + Buffer.from(decoded).toString("hex");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
throw new Error(`Unknown address format: ${addr}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Check if a string is valid base58 encoding. */
|
|
32
|
+
export function isBase58(addr: string): boolean {
|
|
33
|
+
const base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
34
|
+
for (const char of addr) {
|
|
35
|
+
if (!base58Chars.includes(char)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Check if address is Tron format (T prefix, 34 chars, 0x41 first byte after decode). */
|
|
43
|
+
export function isTronAddress(addr: string): boolean {
|
|
44
|
+
if (!addr.startsWith("T") || addr.length !== 34 || !isBase58(addr)) return false;
|
|
45
|
+
try {
|
|
46
|
+
const decoded = bs58.decode(addr);
|
|
47
|
+
// Tron: 0x41 (1 byte) + address (20 bytes) + checksum (4 bytes) = 25 bytes
|
|
48
|
+
return decoded.length === 25 && decoded[0] === 0x41;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Check if chain name is Solana. */
|
|
55
|
+
export function isSolanaChain(chainName: string): boolean {
|
|
56
|
+
return chainName === "Sol" || chainName === "sol_test";
|
|
57
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate creationCode hash for CREATE2 address prediction.
|
|
3
|
+
*/
|
|
4
|
+
const { keccak256, Interface } = require("ethers");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get codeHash for a contract deployment.
|
|
8
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
9
|
+
* @param contractName - contract name (e.g. "Gateway", "AuthorityManager")
|
|
10
|
+
* @param args - constructor arguments array
|
|
11
|
+
*/
|
|
12
|
+
export async function getCodeHash(artifacts: any, contractName: string, args: any[] = []): Promise<string> {
|
|
13
|
+
const artifact = await artifacts.readArtifact(contractName);
|
|
14
|
+
let bytecode = artifact.bytecode;
|
|
15
|
+
if (!bytecode.startsWith("0x")) bytecode = "0x" + bytecode;
|
|
16
|
+
|
|
17
|
+
if (args.length > 0) {
|
|
18
|
+
const iface = new Interface(artifact.abi);
|
|
19
|
+
const encoded = iface.encodeDeploy(args);
|
|
20
|
+
return keccak256(bytecode + encoded.slice(2));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return keccak256(bytecode);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get codeHash for an ERC1967Proxy deployment.
|
|
28
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
29
|
+
* @param implAddress - implementation address
|
|
30
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
31
|
+
* @param initArgs - arguments for initialize() function
|
|
32
|
+
*/
|
|
33
|
+
export async function getProxyCodeHash(
|
|
34
|
+
artifacts: any,
|
|
35
|
+
implAddress: string,
|
|
36
|
+
implName: string,
|
|
37
|
+
initArgs: any[] = []
|
|
38
|
+
): Promise<string> {
|
|
39
|
+
return getCustomProxyCodeHash(artifacts, "ERC1967Proxy", implAddress, implName, initArgs);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get codeHash for a custom proxy deployment.
|
|
44
|
+
* @param artifacts - hardhat artifacts (hre.artifacts)
|
|
45
|
+
* @param proxyName - proxy contract name (e.g. "MyCustomProxy")
|
|
46
|
+
* @param implAddress - implementation address
|
|
47
|
+
* @param implName - implementation contract name (for encoding initData)
|
|
48
|
+
* @param initArgs - arguments for initialize() function
|
|
49
|
+
*/
|
|
50
|
+
export async function getCustomProxyCodeHash(
|
|
51
|
+
artifacts: any,
|
|
52
|
+
proxyName: string,
|
|
53
|
+
implAddress: string,
|
|
54
|
+
implName: string,
|
|
55
|
+
initArgs: any[] = []
|
|
56
|
+
): Promise<string> {
|
|
57
|
+
const proxyArtifact = await artifacts.readArtifact(proxyName);
|
|
58
|
+
let bytecode = proxyArtifact.bytecode;
|
|
59
|
+
if (!bytecode.startsWith("0x")) bytecode = "0x" + bytecode;
|
|
60
|
+
|
|
61
|
+
let initData = "0x";
|
|
62
|
+
if (initArgs.length > 0) {
|
|
63
|
+
const implArtifact = await artifacts.readArtifact(implName);
|
|
64
|
+
const iface = new Interface(implArtifact.abi);
|
|
65
|
+
initData = iface.encodeFunctionData("initialize", initArgs);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { AbiCoder } = require("ethers");
|
|
69
|
+
const constructorArgs = AbiCoder.defaultAbiCoder().encode(
|
|
70
|
+
["address", "bytes"],
|
|
71
|
+
[implAddress, initData]
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
return keccak256(bytecode + constructorArgs.slice(2));
|
|
75
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy record — read/write deployed contract addresses from deploy.json
|
|
3
|
+
*
|
|
4
|
+
* Structure:
|
|
5
|
+
* {
|
|
6
|
+
* "prod": { "Mapo": { "Relay": "0x..." }, "Bsc": { "Gateway": "0x..." } },
|
|
7
|
+
* "main": { "Mapo": { "Relay": "0x..." } },
|
|
8
|
+
* "test": { "Mapo": { "Relay": "0x..." } }
|
|
9
|
+
* }
|
|
10
|
+
*/
|
|
11
|
+
let fs = require("fs");
|
|
12
|
+
let path = require("path");
|
|
13
|
+
|
|
14
|
+
type DeployData = {
|
|
15
|
+
[env: string]: {
|
|
16
|
+
[chain: string]: {
|
|
17
|
+
[key: string]: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface DeploymentPath {
|
|
23
|
+
env: string; // "prod", "main", "test"
|
|
24
|
+
chain: string; // "Mapo", "Bsc", "Tron"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DeploymentOptions {
|
|
28
|
+
basePath?: string; // defaults to <cwd>/deployments/
|
|
29
|
+
env: string; // "prod", "main", "test" — required
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function defaultDeployPath(): string {
|
|
33
|
+
return path.join(process.cwd(), "deployments");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve deployment path from network name and env.
|
|
38
|
+
* @param network - hardhat network name (e.g. "Bsc", "Mapo_test", "Tron")
|
|
39
|
+
* @param env - deployment environment: "prod", "main", "test"
|
|
40
|
+
* @returns { env, chain } for deploy.json lookup
|
|
41
|
+
*/
|
|
42
|
+
export function resolveDeploymentPath(network: string, env: string): DeploymentPath {
|
|
43
|
+
// Strip _test suffix from network name to get chain name
|
|
44
|
+
const chain = network.replace(/_?test$/i, "");
|
|
45
|
+
return { env, chain: chain.charAt(0).toUpperCase() + chain.slice(1) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Read a deployed contract address from deploy.json.
|
|
50
|
+
* @param network - hardhat network name
|
|
51
|
+
* @param key - contract key (e.g. "Gateway", "Authority")
|
|
52
|
+
* @param opts - optional basePath and env overrides
|
|
53
|
+
*/
|
|
54
|
+
export async function getDeploymentByKey(network: string, key: string, opts: DeploymentOptions): Promise<string> {
|
|
55
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
56
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
57
|
+
const data = await readDeployFile(deployPath);
|
|
58
|
+
const addr = data[env]?.[chain]?.[key];
|
|
59
|
+
if (!addr) throw new Error(`no ${key} deployment in ${env}.${chain}`);
|
|
60
|
+
return addr;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if a contract address exists and is valid in deploy.json.
|
|
65
|
+
* @param network - hardhat network name
|
|
66
|
+
* @param key - contract key
|
|
67
|
+
* @param opts - optional basePath and env overrides
|
|
68
|
+
*/
|
|
69
|
+
export async function hasDeployment(network: string, key: string, opts: DeploymentOptions): Promise<boolean> {
|
|
70
|
+
try {
|
|
71
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
72
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
73
|
+
const data = await readDeployFile(deployPath);
|
|
74
|
+
const addr = data[env]?.[chain]?.[key];
|
|
75
|
+
return !!addr && addr.length > 2 && addr !== "0x";
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Save a deployed contract address to deploy.json.
|
|
83
|
+
* @param network - hardhat network name
|
|
84
|
+
* @param key - contract key (e.g. "Gateway")
|
|
85
|
+
* @param addr - deployed address
|
|
86
|
+
* @param opts - optional basePath and env overrides
|
|
87
|
+
*/
|
|
88
|
+
export async function saveDeployment(network: string, key: string, addr: string, opts: DeploymentOptions): Promise<void> {
|
|
89
|
+
const deployPath = opts.basePath || defaultDeployPath();
|
|
90
|
+
const { env, chain } = resolveDeploymentPath(network, opts.env);
|
|
91
|
+
const data = await readDeployFile(deployPath);
|
|
92
|
+
if (!data[env]) data[env] = {};
|
|
93
|
+
if (!data[env][chain]) data[env][chain] = {};
|
|
94
|
+
data[env][chain][key] = addr;
|
|
95
|
+
const filePath = path.resolve(deployPath, "deploy.json");
|
|
96
|
+
await ensureDir(deployPath);
|
|
97
|
+
await fs.promises.writeFile(filePath, JSON.stringify(data, null, "\t"));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function readDeployFile(basePath: string): Promise<DeployData> {
|
|
101
|
+
const filePath = path.resolve(basePath, "deploy.json");
|
|
102
|
+
try {
|
|
103
|
+
const rawdata = await fs.promises.readFile(filePath, "utf-8");
|
|
104
|
+
return JSON.parse(rawdata);
|
|
105
|
+
} catch {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function ensureDir(dirPath: string): Promise<void> {
|
|
111
|
+
const absPath = path.resolve(dirPath);
|
|
112
|
+
try {
|
|
113
|
+
await fs.promises.stat(absPath);
|
|
114
|
+
} catch {
|
|
115
|
+
await fs.promises.mkdir(absPath, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isTronNetwork, TronClient } from "./tronHelper";
|
|
2
|
+
import { evmDeploy, evmDeployProxy, evmUpgradeProxy } from "./evmHelper";
|
|
3
|
+
import { verify as _verify } from "./verifier";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Unified deployer — auto-routes to EVM or Tron based on network name.
|
|
7
|
+
*
|
|
8
|
+
* Usage in hardhat tasks:
|
|
9
|
+
* const deployer = createDeployer(hre, { autoVerify: true });
|
|
10
|
+
* let addr = await deployer.deploy("Gateway", [admin], salt);
|
|
11
|
+
* let { proxy, implementation } = await deployer.deployProxy("Gateway", [admin], salt);
|
|
12
|
+
* let newImpl = await deployer.upgrade("Gateway", proxyAddr);
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface DeployerOptions {
|
|
16
|
+
autoVerify?: boolean; // auto verify after deploy/upgrade, defaults to false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DeployResult {
|
|
20
|
+
address: string; // primary address (0x hex for EVM, base58 for Tron)
|
|
21
|
+
hex?: string; // 0x hex (Tron only, EVM same as address)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface DeployProxyResult {
|
|
25
|
+
proxy: string; // proxy address (0x hex for EVM, base58 for Tron)
|
|
26
|
+
implementation: string; // impl address
|
|
27
|
+
proxyHex?: string; // Tron hex
|
|
28
|
+
implementationHex?: string; // Tron hex
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Deployer {
|
|
32
|
+
deploy(contractName: string, args?: any[], salt?: string): Promise<DeployResult>;
|
|
33
|
+
deployProxy(contractName: string, initArgs?: any[], salt?: string): Promise<DeployProxyResult>;
|
|
34
|
+
upgrade(contractName: string, proxyAddr: string): Promise<DeployResult>;
|
|
35
|
+
verify(contractName: string, address: string, constructorArgs?: any[], contractPath?: string): Promise<void>;
|
|
36
|
+
isTron: boolean;
|
|
37
|
+
network: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a unified deployer that auto-routes to EVM or Tron based on network.
|
|
42
|
+
* @param hre - hardhat runtime environment
|
|
43
|
+
* @param opts - options (autoVerify: auto-verify after deploy, defaults to false)
|
|
44
|
+
*/
|
|
45
|
+
export function createDeployer(hre: any, opts: DeployerOptions = {}): Deployer {
|
|
46
|
+
const network = hre.network.name;
|
|
47
|
+
const isTron = isTronNetwork(network);
|
|
48
|
+
const autoVerify = opts.autoVerify || false;
|
|
49
|
+
|
|
50
|
+
async function tryVerify(contractName: string, address: string, constructorArgs?: any[], contractPath?: string) {
|
|
51
|
+
if (!autoVerify) return;
|
|
52
|
+
try {
|
|
53
|
+
await _verify(hre, { contractName, address, constructorArgs, contractPath });
|
|
54
|
+
} catch (e: any) {
|
|
55
|
+
console.log(`[warn] auto-verify failed: ${e.message || e}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (isTron) {
|
|
60
|
+
const client = TronClient.fromHre(hre);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
isTron: true,
|
|
64
|
+
network,
|
|
65
|
+
|
|
66
|
+
async deploy(contractName, args = [], salt = "") {
|
|
67
|
+
let result = await client.deploy(hre.artifacts, contractName, args, salt);
|
|
68
|
+
await tryVerify(contractName, result.base58, args);
|
|
69
|
+
return { address: result.base58, hex: result.hex };
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async deployProxy(contractName, initArgs = [], salt = "") {
|
|
73
|
+
let result = await client.deployProxy(hre.artifacts, contractName, initArgs, salt);
|
|
74
|
+
await tryVerify(contractName, result.implementation.base58);
|
|
75
|
+
return {
|
|
76
|
+
proxy: result.proxy.base58,
|
|
77
|
+
implementation: result.implementation.base58,
|
|
78
|
+
proxyHex: result.proxy.hex,
|
|
79
|
+
implementationHex: result.implementation.hex,
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async upgrade(contractName, proxyAddr) {
|
|
84
|
+
let result = await client.upgradeProxy(hre.artifacts, contractName, proxyAddr);
|
|
85
|
+
await tryVerify(contractName, result.base58);
|
|
86
|
+
return { address: result.base58, hex: result.hex };
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
async verify(contractName, address, constructorArgs, contractPath) {
|
|
90
|
+
await _verify(hre, { contractName, address, constructorArgs, contractPath });
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// EVM
|
|
96
|
+
const { ethers, artifacts } = hre;
|
|
97
|
+
return {
|
|
98
|
+
isTron: false,
|
|
99
|
+
network,
|
|
100
|
+
|
|
101
|
+
async deploy(contractName, args = [], salt = "") {
|
|
102
|
+
let addr = await evmDeploy(ethers, artifacts, contractName, args, salt);
|
|
103
|
+
await tryVerify(contractName, addr, args);
|
|
104
|
+
return { address: addr };
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async deployProxy(contractName, initArgs = [], salt = "") {
|
|
108
|
+
let result = await evmDeployProxy(ethers, artifacts, contractName, initArgs, salt);
|
|
109
|
+
await tryVerify(contractName, result.implementation);
|
|
110
|
+
return { proxy: result.proxy, implementation: result.implementation };
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
async upgrade(contractName, proxyAddr) {
|
|
114
|
+
let addr = await evmUpgradeProxy(ethers, contractName, proxyAddr);
|
|
115
|
+
await tryVerify(contractName, addr);
|
|
116
|
+
return { address: addr };
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
async verify(contractName, address, constructorArgs, contractPath) {
|
|
120
|
+
await _verify(hre, { contractName, address, constructorArgs, contractPath });
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|