@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.
Files changed (28) hide show
  1. package/README.md +114 -58
  2. package/artifacts/contracts/AuthorityManager.sol/AuthorityManager.json +2 -2
  3. package/artifacts/contracts/factory/Create2Factory.sol/Create2Factory.json +107 -0
  4. package/contracts/factory/Create2Factory.sol +57 -0
  5. package/package.json +15 -3
  6. package/typechain-types/contracts/factory/Create2Factory.ts +174 -0
  7. package/typechain-types/contracts/factory/index.ts +4 -0
  8. package/typechain-types/contracts/index.ts +2 -0
  9. package/typechain-types/factories/@openzeppelin/contracts/access/manager/AccessManager__factory.ts +1 -1
  10. package/typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils__factory.ts +1 -1
  11. package/typechain-types/factories/@openzeppelin/contracts/utils/Address__factory.ts +1 -1
  12. package/typechain-types/factories/@openzeppelin/contracts/utils/Errors__factory.ts +1 -1
  13. package/typechain-types/factories/@openzeppelin/contracts/utils/math/SafeCast__factory.ts +1 -1
  14. package/typechain-types/factories/contracts/AuthorityManager__factory.ts +1 -1
  15. package/typechain-types/factories/contracts/factory/Create2Factory__factory.ts +163 -0
  16. package/typechain-types/factories/contracts/factory/index.ts +4 -0
  17. package/typechain-types/factories/contracts/index.ts +1 -0
  18. package/typechain-types/hardhat.d.ts +18 -0
  19. package/typechain-types/index.ts +2 -0
  20. package/utils/addressCodec.ts +57 -0
  21. package/utils/codeHash.ts +75 -0
  22. package/utils/deployRecord.ts +117 -0
  23. package/utils/deployer.ts +123 -0
  24. package/utils/evmHelper.ts +108 -0
  25. package/utils/factory.ts +210 -0
  26. package/utils/index.ts +42 -0
  27. package/utils/tronHelper.ts +362 -0
  28. package/utils/verifier.ts +225 -0
@@ -0,0 +1,108 @@
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 async function evmDeploy(
11
+ ethers: any,
12
+ artifacts: any,
13
+ contractName: string,
14
+ args: any[] = [],
15
+ salt: string = ""
16
+ ): Promise<string> {
17
+ if (salt) {
18
+ const { evmDeployByFactory } = require("./factory");
19
+ const artifact = await artifacts.readArtifact(contractName);
20
+ const constructorArgs = args.length > 0
21
+ ? ethers.AbiCoder.defaultAbiCoder().encode(
22
+ artifact.abi
23
+ .find((x: any) => x.type === "constructor")
24
+ ?.inputs.map((i: any) => i.type) || [],
25
+ args
26
+ )
27
+ : "0x";
28
+ return evmDeployByFactory(ethers, salt, artifact.bytecode, constructorArgs);
29
+ }
30
+
31
+ const [deployer] = await ethers.getSigners();
32
+ console.log("deploy address is:", deployer.address);
33
+
34
+ const ContractFactory = await ethers.getContractFactory(contractName);
35
+ const contract = await (await ContractFactory.deploy(...args)).waitForDeployment();
36
+ const addr = await contract.getAddress();
37
+ console.log(`${contractName} deployed: ${addr}`);
38
+ return addr;
39
+ }
40
+
41
+ /**
42
+ * Deploy implementation + ERC1967 proxy in one step.
43
+ * If salt is provided, proxy is deployed via factory.
44
+ * @param ethers - ethers from hardhat runtime (hre.ethers)
45
+ * @param artifacts - hardhat artifacts (hre.artifacts)
46
+ * @param contractName - implementation contract name
47
+ * @param initArgs - initialize() function arguments
48
+ * @param salt - optional CREATE2 salt for proxy
49
+ * @returns { proxy, implementation } addresses
50
+ */
51
+ export async function evmDeployProxy(
52
+ ethers: any,
53
+ artifacts: any,
54
+ contractName: string,
55
+ initArgs: any[] = [],
56
+ salt: string = ""
57
+ ): Promise<{ proxy: string; implementation: string }> {
58
+ const ImplFactory = await ethers.getContractFactory(contractName);
59
+ const impl = await (await ImplFactory.deploy()).waitForDeployment();
60
+ const implAddr = await impl.getAddress();
61
+ console.log(`${contractName} implementation: ${implAddr}`);
62
+
63
+ const initData = ImplFactory.interface.encodeFunctionData("initialize", initArgs);
64
+
65
+ let proxyAddr: string;
66
+ if (salt) {
67
+ const { evmDeployByFactory } = require("./factory");
68
+ const proxyArtifact = await artifacts.readArtifact("ERC1967Proxy");
69
+ const constructorArgs = ethers.AbiCoder.defaultAbiCoder().encode(
70
+ ["address", "bytes"],
71
+ [implAddr, initData]
72
+ );
73
+ proxyAddr = await evmDeployByFactory(ethers, salt, proxyArtifact.bytecode, constructorArgs);
74
+ } else {
75
+ const ProxyFactory = await ethers.getContractFactory("ERC1967Proxy");
76
+ const proxy = await (await ProxyFactory.deploy(implAddr, initData)).waitForDeployment();
77
+ proxyAddr = await proxy.getAddress();
78
+ }
79
+
80
+ console.log(`${contractName} proxy: ${proxyAddr}`);
81
+ return { proxy: proxyAddr, implementation: implAddr };
82
+ }
83
+
84
+ /**
85
+ * Upgrade a UUPS proxy to a new implementation.
86
+ * Deploys new implementation, then calls upgradeToAndCall on the proxy.
87
+ * @param ethers - ethers from hardhat runtime (hre.ethers)
88
+ * @param contractName - new implementation contract name
89
+ * @param proxyAddr - proxy address to upgrade
90
+ * @returns new implementation address
91
+ */
92
+ export async function evmUpgradeProxy(
93
+ ethers: any,
94
+ contractName: string,
95
+ proxyAddr: string
96
+ ): Promise<string> {
97
+ const [deployer] = await ethers.getSigners();
98
+ const ImplFactory = await ethers.getContractFactory(contractName);
99
+ const impl = await (await ImplFactory.deploy()).waitForDeployment();
100
+ const implAddr = await impl.getAddress();
101
+
102
+ const proxy = await ethers.getContractAt("BaseImplementation", proxyAddr, deployer);
103
+ const oldImpl = await proxy.getImplementation();
104
+ await (await proxy.upgradeToAndCall(implAddr, "0x")).wait();
105
+
106
+ console.log(`${contractName} upgraded: ${oldImpl} -> ${implAddr}`);
107
+ return implAddr;
108
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Factory deployment — deterministic contract addresses across chains.
3
+ * EVM: CREATE3 factory at 0x6258e4d2950757A749a4d4683A7342261ce12471
4
+ * Tron: CREATE2 factory at TJAwD5VfMYMGWwdPi2aVcoQwVBfsuw5wQt
5
+ */
6
+ import { tronFromHex } from "./tronHelper";
7
+
8
+ // Factory contract addresses
9
+ const EVM_FACTORY = "0x6258e4d2950757A749a4d4683A7342261ce12471";
10
+ const TRON_FACTORY = "TJAwD5VfMYMGWwdPi2aVcoQwVBfsuw5wQt";
11
+
12
+ // EVM factory ABI (CREATE3 — getAddress only needs salt)
13
+ // function deploy(bytes32 salt, bytes creationCode, uint256 value)
14
+ // function getAddress(bytes32 salt) view returns (address)
15
+ const EVM_FACTORY_ABI = [
16
+ {
17
+ "inputs": [{"name": "salt", "type": "bytes32"}, {"name": "creationCode", "type": "bytes"}, {"name": "value", "type": "uint256"}],
18
+ "name": "deploy",
19
+ "outputs": [],
20
+ "stateMutability": "nonpayable",
21
+ "type": "function"
22
+ },
23
+ {
24
+ "inputs": [{"name": "salt", "type": "bytes32"}],
25
+ "name": "getAddress",
26
+ "outputs": [{"name": "", "type": "address"}],
27
+ "stateMutability": "view",
28
+ "type": "function"
29
+ }
30
+ ];
31
+
32
+ // Tron factory ABI (CREATE2 — getAddress needs salt + codeHash)
33
+ // function deploy(bytes32 salt, bytes creationCode, uint256 value) returns (address)
34
+ // function getAddress(bytes32 salt, bytes32 codeHash) view returns (address)
35
+ // function getAddressTron(bytes32 salt, bytes32 codeHash) view returns (address)
36
+ const TRON_FACTORY_ABI = [
37
+ {
38
+ "inputs": [{"name": "salt", "type": "bytes32"}, {"name": "creationCode", "type": "bytes"}, {"name": "value", "type": "uint256"}],
39
+ "name": "deploy",
40
+ "outputs": [{"name": "addr", "type": "address"}],
41
+ "stateMutability": "nonpayable",
42
+ "type": "function"
43
+ },
44
+ {
45
+ "inputs": [{"name": "salt", "type": "bytes32"}, {"name": "codeHash", "type": "bytes32"}],
46
+ "name": "getAddressTron",
47
+ "outputs": [{"name": "", "type": "address"}],
48
+ "stateMutability": "view",
49
+ "type": "function"
50
+ }
51
+ ];
52
+
53
+ // ============================================================
54
+ // EVM Factory (CREATE3, ethers.js)
55
+ // ============================================================
56
+
57
+ /**
58
+ * Deploy contract via CREATE3 factory on EVM chains.
59
+ * Address only depends on salt, not bytecode.
60
+ * @param ethers - ethers from hardhat runtime (hre.ethers)
61
+ * @param salt - human-readable salt string
62
+ * @param bytecode - contract bytecode (artifact.bytecode)
63
+ * @param constructorArgs - ABI-encoded constructor arguments
64
+ * @returns deployed contract address
65
+ */
66
+ export async function evmDeployByFactory(
67
+ ethers: any,
68
+ salt: string,
69
+ bytecode: string,
70
+ constructorArgs: string = "0x"
71
+ ): Promise<string> {
72
+ const [signer] = await ethers.getSigners();
73
+ const factory = new ethers.Contract(EVM_FACTORY, EVM_FACTORY_ABI, signer);
74
+
75
+ const code = await ethers.provider.getCode(EVM_FACTORY);
76
+ if (code === "0x") throw new Error("factory not deployed on this chain");
77
+
78
+ const saltHash = ethers.keccak256(ethers.toUtf8Bytes(salt));
79
+ const predicted = await factory.getAddress(saltHash);
80
+
81
+ const existingCode = await ethers.provider.getCode(predicted);
82
+ if (existingCode !== "0x") {
83
+ console.log(`already deployed at ${predicted}`);
84
+ return predicted;
85
+ }
86
+
87
+ const fullBytecode = constructorArgs === "0x"
88
+ ? bytecode
89
+ : ethers.concat([bytecode, constructorArgs]);
90
+
91
+ const tx = await factory.deploy(saltHash, fullBytecode, 0);
92
+ await tx.wait();
93
+
94
+ // Verify contract was actually deployed
95
+ const deployedCode = await ethers.provider.getCode(predicted);
96
+ if (deployedCode === "0x") {
97
+ throw new Error(`factory deploy failed: no contract at predicted address ${predicted}`);
98
+ }
99
+ console.log(`deployed via factory at ${predicted}`);
100
+ return predicted;
101
+ }
102
+
103
+ /**
104
+ * Get predicted factory address for a salt on EVM (CREATE3 — only needs salt).
105
+ * @param ethers - ethers from hardhat runtime
106
+ * @param salt - human-readable salt string
107
+ */
108
+ export async function evmGetFactoryAddress(ethers: any, salt: string): Promise<string> {
109
+ const factory = new ethers.Contract(EVM_FACTORY, EVM_FACTORY_ABI, await ethers.provider);
110
+ const saltHash = ethers.keccak256(ethers.toUtf8Bytes(salt));
111
+ return factory.getAddress(saltHash);
112
+ }
113
+
114
+ // ============================================================
115
+ // Tron Factory (CREATE2, tronweb)
116
+ // ============================================================
117
+
118
+ /**
119
+ * Deploy contract via CREATE2 factory on Tron.
120
+ * Address depends on salt + creationCode (bytecode + constructor args).
121
+ * @param tronWeb - initialized tronweb instance
122
+ * @param artifacts - hardhat artifacts
123
+ * @param contractName - contract name to deploy
124
+ * @param salt - human-readable salt string
125
+ * @param args - constructor arguments array
126
+ * @param feeLimit - tron fee limit
127
+ * @returns deployed contract address (0x-prefixed hex)
128
+ */
129
+ export async function tronDeployByFactory(
130
+ tronWeb: any,
131
+ artifacts: any,
132
+ contractName: string,
133
+ salt: string,
134
+ args: any[] = [],
135
+ feeLimit: number = 15_000_000_000
136
+ ): Promise<string> {
137
+ const factory = await tronWeb.contract(TRON_FACTORY_ABI, TRON_FACTORY);
138
+ const saltHash = tronWeb.sha3(salt);
139
+
140
+ // Build creation code with constructor args
141
+ const artifact = await artifacts.readArtifact(contractName);
142
+ let creationCode = artifact.bytecode;
143
+ if (args.length > 0) {
144
+ const iface = new (require("ethers").Interface)(artifact.abi);
145
+ const encoded = iface.encodeDeploy(args);
146
+ creationCode = creationCode + encoded.slice(2);
147
+ }
148
+
149
+ // Check if already deployed
150
+ const codeHash = tronWeb.sha3(creationCode);
151
+ const predicted = await factory.getAddressTron(saltHash, codeHash).call();
152
+ const predictedHex = predicted.replace(/^41/, "0x");
153
+ try {
154
+ const existing = await tronWeb.trx.getContract(tronWeb.address.fromHex(predicted));
155
+ if (existing && existing.bytecode) {
156
+ console.log(`already deployed at ${tronFromHex(predicted)}`);
157
+ return predictedHex;
158
+ }
159
+ } catch {}
160
+
161
+ // Deploy
162
+ console.log(`deploying ${contractName} via factory with salt "${salt}"...`);
163
+ const { sendAndWait } = require("./tronHelper");
164
+ const txResult = await sendAndWait(factory.deploy(saltHash, creationCode, 0), tronWeb, { feeLimit });
165
+
166
+ // Read actual address from Deployed event
167
+ let addrHex = predictedHex; // fallback to predicted
168
+ if (txResult.log && txResult.log.length > 0) {
169
+ // Deployed(address indexed addr, bytes32 indexed salt)
170
+ // First topic = event sig, second topic = addr
171
+ const addrTopic = txResult.log[0].topics?.[1];
172
+ if (addrTopic) {
173
+ addrHex = "0x" + addrTopic.slice(24); // last 20 bytes
174
+ }
175
+ }
176
+
177
+ // Verify contract was actually deployed
178
+ const addrBase58 = tronFromHex(addrHex);
179
+ try {
180
+ const deployed = await tronWeb.trx.getContract(addrBase58);
181
+ if (!deployed || !deployed.bytecode) {
182
+ throw new Error(`factory deploy failed: no contract at ${addrBase58}`);
183
+ }
184
+ } catch (e: any) {
185
+ if (e.message?.includes("factory deploy failed")) throw e;
186
+ // Contract might not be indexed yet, wait and retry
187
+ await new Promise(r => setTimeout(r, 3000));
188
+ const deployed = await tronWeb.trx.getContract(addrBase58);
189
+ if (!deployed || !deployed.bytecode) {
190
+ throw new Error(`factory deploy failed: no contract at ${addrBase58}`);
191
+ }
192
+ }
193
+
194
+ console.log(`${contractName} deployed: ${addrBase58} (${addrHex})`);
195
+ return addrHex;
196
+ }
197
+
198
+ /**
199
+ * Get predicted factory address for a salt on Tron (CREATE2 — needs salt + codeHash).
200
+ * @param tronWeb - initialized tronweb instance
201
+ * @param salt - human-readable salt string
202
+ * @param codeHash - keccak256 of creationCode (bytecode + constructor args)
203
+ * @returns address in base58 format
204
+ */
205
+ export async function tronGetFactoryAddress(tronWeb: any, salt: string, codeHash: string): Promise<string> {
206
+ const factory = await tronWeb.contract(TRON_FACTORY_ABI, TRON_FACTORY);
207
+ const saltHash = tronWeb.sha3(salt);
208
+ const addr = await factory.getAddressTron(saltHash, codeHash).call();
209
+ return tronFromHex(addr);
210
+ }
package/utils/index.ts ADDED
@@ -0,0 +1,42 @@
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
+
13
+ // Unified deployer — recommended entry point for deploy/upgrade/verify
14
+ export {
15
+ createDeployer,
16
+ type Deployer,
17
+ type DeployResult,
18
+ type DeployProxyResult,
19
+ type DeployerOptions
20
+ } from "./deployer";
21
+
22
+ // Deploy record — deploy.json address management
23
+ export {
24
+ resolveDeploymentPath,
25
+ getDeploymentByKey,
26
+ hasDeployment,
27
+ saveDeployment,
28
+ type DeploymentPath,
29
+ type DeploymentOptions
30
+ } from "./deployRecord";
31
+
32
+ // Contract verification
33
+ export { verify, type VerifyOptions } from "./verifier";
34
+
35
+ // Code hash for CREATE2 address prediction
36
+ export { getCodeHash, getProxyCodeHash, getCustomProxyCodeHash } from "./codeHash";
37
+
38
+ // Address encoding
39
+ export { addressToHex, isBase58, isTronAddress, isSolanaChain } from "./addressCodec";
40
+
41
+ // Tron utilities
42
+ export { TronClient, tronFromHex, tronToHex, isTronNetwork, sendAndWait, waitForTx, type TronAddress } from "./tronHelper";