create-stylus 0.1.2 → 0.1.3
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 +1 -1
- package/templates/base/package.json +1 -1
- package/templates/base/packages/stylus/scripts/deploy.ts +7 -3
- package/templates/base/packages/stylus/scripts/deploy_contract.ts +38 -30
- package/templates/base/packages/stylus/scripts/test_network.ts +2 -2
- package/templates/base/packages/stylus/scripts/utils/command.ts +64 -40
- package/templates/base/packages/stylus/scripts/utils/contract.ts +67 -0
- package/templates/base/packages/stylus/scripts/utils/network.ts +6 -15
- package/templates/base/packages/stylus/scripts/utils/type.ts +3 -11
- package/templates/base/readme.md +19 -1
package/package.json
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import deployStylusContract from "./deploy_contract";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getDeploymentConfig,
|
|
4
|
+
getRpcUrlFromChain,
|
|
5
|
+
printDeployedAddresses,
|
|
6
|
+
} from "./utils/";
|
|
3
7
|
import { DeployOptions } from "./utils/type";
|
|
4
8
|
import { config as dotenvConfig } from "dotenv";
|
|
5
9
|
import * as path from "path";
|
|
@@ -16,7 +20,7 @@ if (fs.existsSync(envPath)) {
|
|
|
16
20
|
export default async function deployScript(deployOptions: DeployOptions) {
|
|
17
21
|
const config = getDeploymentConfig(deployOptions);
|
|
18
22
|
|
|
19
|
-
console.log(`📡 Using endpoint: ${config.chain
|
|
23
|
+
console.log(`📡 Using endpoint: ${getRpcUrlFromChain(config.chain)}`);
|
|
20
24
|
if (config.chain) {
|
|
21
25
|
console.log(`🌐 Network: ${config.chain?.name}`);
|
|
22
26
|
console.log(`🔗 Chain ID: ${config.chain?.id}`);
|
|
@@ -50,5 +54,5 @@ export default async function deployScript(deployOptions: DeployOptions) {
|
|
|
50
54
|
|
|
51
55
|
// Print the deployed addresses
|
|
52
56
|
console.log("\n\n");
|
|
53
|
-
printDeployedAddresses(config.deploymentDir, config.chain
|
|
57
|
+
printDeployedAddresses(config.deploymentDir, config.chain.id.toString());
|
|
54
58
|
}
|
|
@@ -4,17 +4,18 @@ import {
|
|
|
4
4
|
executeCommand,
|
|
5
5
|
extractDeploymentInfo,
|
|
6
6
|
saveDeployment,
|
|
7
|
-
|
|
7
|
+
getBlockExplorerUrlFromChain,
|
|
8
|
+
getRpcUrlFromChain,
|
|
9
|
+
getContractData,
|
|
10
|
+
contractHasInitializeFunction,
|
|
8
11
|
// estimateGasPrice,
|
|
9
12
|
} from "./utils/";
|
|
10
13
|
import { exportStylusAbi } from "./export_abi";
|
|
11
14
|
import { DeployOptions } from "./utils/type";
|
|
12
15
|
import { buildDeployCommand } from "./utils/command";
|
|
13
|
-
import {
|
|
16
|
+
import { Abi, createPublicClient, createWalletClient, http } from "viem";
|
|
14
17
|
import { privateKeyToAccount } from "viem/accounts";
|
|
15
|
-
|
|
16
18
|
import { arbitrumNitro } from "../../nextjs/utils/scaffold-stylus/supportedChains";
|
|
17
|
-
import deployedContracts from "../../nextjs/contracts/deployedContracts";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Deploy a single contract using cargo stylus
|
|
@@ -50,12 +51,13 @@ export default async function deployStylusContract(
|
|
|
50
51
|
// Extract the actual deployed address from the output
|
|
51
52
|
const deploymentInfo = extractDeploymentInfo(deployOutput);
|
|
52
53
|
if (deploymentInfo) {
|
|
53
|
-
|
|
54
|
+
const blockExplorerUrl = getBlockExplorerUrlFromChain(config.chain);
|
|
55
|
+
if (blockExplorerUrl) {
|
|
54
56
|
console.log(
|
|
55
|
-
`📋 Contract deployed: ${
|
|
57
|
+
`📋 Contract deployed: ${blockExplorerUrl}/address/${deploymentInfo.address}`,
|
|
56
58
|
);
|
|
57
59
|
console.log(
|
|
58
|
-
`Transaction hash: ${
|
|
60
|
+
`Transaction hash: ${blockExplorerUrl}/tx/${deploymentInfo.txHash}`,
|
|
59
61
|
);
|
|
60
62
|
} else {
|
|
61
63
|
console.log(
|
|
@@ -75,32 +77,29 @@ export default async function deployStylusContract(
|
|
|
75
77
|
config.contractFolder,
|
|
76
78
|
config.contractName,
|
|
77
79
|
false,
|
|
78
|
-
config.chain
|
|
80
|
+
config.chain.id.toString(),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Get contract data from deployed contracts after ABI export
|
|
84
|
+
const contractData = getContractData(
|
|
85
|
+
config.chain.id.toString(),
|
|
86
|
+
config.contractName,
|
|
79
87
|
);
|
|
80
88
|
|
|
81
89
|
// Call the initialize function if orbit deployment
|
|
82
90
|
if (
|
|
83
91
|
!!deployOptions.isOrbit &&
|
|
84
|
-
config.chain
|
|
92
|
+
config.chain.id !== arbitrumNitro.id &&
|
|
93
|
+
contractHasInitializeFunction(contractData)
|
|
85
94
|
) {
|
|
86
|
-
const orbitChain = ORBIT_CHAINS.find(
|
|
87
|
-
(chain) => chain.id.toString() === config.chain?.id,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
if (!orbitChain) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
`Chain ${config.chain?.id} is not supported for orbit deployment`,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
95
|
const publicClient = createPublicClient({
|
|
97
|
-
chain:
|
|
96
|
+
chain: config.chain,
|
|
98
97
|
transport: http(),
|
|
99
98
|
});
|
|
100
99
|
|
|
101
100
|
// need wallet client to sign the transaction
|
|
102
101
|
const walletClient = createWalletClient({
|
|
103
|
-
chain:
|
|
102
|
+
chain: config.chain,
|
|
104
103
|
transport: http(),
|
|
105
104
|
});
|
|
106
105
|
|
|
@@ -109,35 +108,44 @@ export default async function deployStylusContract(
|
|
|
109
108
|
const { request } = await publicClient.simulateContract({
|
|
110
109
|
account,
|
|
111
110
|
address: deploymentInfo.address,
|
|
112
|
-
|
|
113
|
-
abi: deployedContracts[config.chain.id][config.contractName].abi,
|
|
111
|
+
abi: contractData.abi as Abi,
|
|
114
112
|
functionName: "initialize",
|
|
115
|
-
args: deployOptions.constructorArgs,
|
|
113
|
+
args: deployOptions.constructorArgs as any[],
|
|
116
114
|
});
|
|
117
115
|
|
|
118
116
|
const initTxHash = await walletClient.writeContract(request);
|
|
119
117
|
|
|
120
118
|
console.log("Initialize transaction hash: ", initTxHash);
|
|
119
|
+
} else {
|
|
120
|
+
console.log("\nContract does not have an initialize function");
|
|
121
|
+
console.log("Skipping initialization");
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
// Step 3: Verify the contract
|
|
124
125
|
if (deployOptions.verify) {
|
|
125
126
|
try {
|
|
126
127
|
const output = await executeCommand(
|
|
127
|
-
`cargo stylus verify --endpoint=${config.chain
|
|
128
|
+
`cargo stylus verify --endpoint=${getRpcUrlFromChain(config.chain)} --deployment-tx=${deploymentInfo.txHash}`,
|
|
128
129
|
deployOptions.contract!,
|
|
129
130
|
"Verifying contract with cargo stylus",
|
|
130
131
|
);
|
|
131
132
|
console.log(output);
|
|
132
133
|
} catch (error) {
|
|
133
|
-
console.error(
|
|
134
|
-
|
|
135
|
-
error
|
|
136
|
-
|
|
134
|
+
console.error(`❌ Verification failed in: ${deployOptions.contract}`);
|
|
135
|
+
if (error instanceof Error) {
|
|
136
|
+
console.error(error.message);
|
|
137
|
+
} else {
|
|
138
|
+
console.error(error);
|
|
139
|
+
}
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
} catch (error) {
|
|
140
|
-
console.error(`❌ Deployment failed in: ${deployOptions.contract}
|
|
143
|
+
console.error(`❌ Deployment failed in: ${deployOptions.contract}`);
|
|
144
|
+
if (error instanceof Error) {
|
|
145
|
+
console.error(error.message);
|
|
146
|
+
} else {
|
|
147
|
+
console.error(error);
|
|
148
|
+
}
|
|
141
149
|
process.exit(1);
|
|
142
150
|
}
|
|
143
151
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getChain } from "./utils/";
|
|
1
|
+
import { getChain, getRpcUrlFromChain } from "./utils/";
|
|
2
2
|
import { SUPPORTED_NETWORKS } from "./utils/";
|
|
3
3
|
|
|
4
4
|
function testNetworkFunctionality() {
|
|
@@ -9,7 +9,7 @@ function testNetworkFunctionality() {
|
|
|
9
9
|
testNetworks.forEach((network) => {
|
|
10
10
|
const chain = getChain(network);
|
|
11
11
|
if (chain) {
|
|
12
|
-
console.log(`✅ ${network}: ${chain
|
|
12
|
+
console.log(`✅ ${network}: ${getRpcUrlFromChain(chain)}`);
|
|
13
13
|
} else {
|
|
14
14
|
console.log(`❌ ${network}: Not found in viem chains`);
|
|
15
15
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import { DeploymentConfig, DeployOptions } from "./type";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
extractGasPriceFromOutput,
|
|
5
|
+
isContractHasConstructor,
|
|
6
|
+
} from "./contract";
|
|
7
|
+
import { getRpcUrlFromChain } from "./network";
|
|
4
8
|
|
|
5
9
|
export async function buildDeployCommand(
|
|
6
10
|
config: DeploymentConfig,
|
|
7
11
|
deployOptions: DeployOptions,
|
|
8
12
|
) {
|
|
9
|
-
let baseCommand = `cargo stylus deploy --endpoint='${config.chain
|
|
13
|
+
let baseCommand = `cargo stylus deploy --endpoint='${getRpcUrlFromChain(config.chain)}' --private-key='${config.privateKey}'`;
|
|
10
14
|
|
|
11
15
|
if (deployOptions.estimateGas) {
|
|
12
16
|
return `${baseCommand} --estimate-gas`;
|
|
@@ -19,8 +23,15 @@ export async function buildDeployCommand(
|
|
|
19
23
|
if (!deployOptions.verify) {
|
|
20
24
|
baseCommand += ` --no-verify`;
|
|
21
25
|
} else {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
if (
|
|
27
|
+
deployOptions.constructorArgs &&
|
|
28
|
+
deployOptions.constructorArgs.length > 0 &&
|
|
29
|
+
isContractHasConstructor(config.contractFolder)
|
|
30
|
+
) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
"Verification is not currently supported with constructors. Please implement and use initialize() function to initialize your contracts: Refer to readme.md for tutorial",
|
|
33
|
+
);
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
if (
|
|
@@ -38,7 +49,7 @@ export async function estimateGasPrice(
|
|
|
38
49
|
config: DeploymentConfig,
|
|
39
50
|
deployOptions: DeployOptions,
|
|
40
51
|
): Promise<string> {
|
|
41
|
-
let deployCommand = `cargo stylus deploy --endpoint='${config.chain
|
|
52
|
+
let deployCommand = `cargo stylus deploy --endpoint='${getRpcUrlFromChain(config.chain)}' --private-key='${config.privateKey}' --no-verify --estimate-gas `;
|
|
42
53
|
if (deployOptions.constructorArgs) {
|
|
43
54
|
deployCommand += ` --constructor-args='${deployOptions.constructorArgs.join(" ")}'`;
|
|
44
55
|
}
|
|
@@ -75,7 +86,6 @@ export function executeCommand(
|
|
|
75
86
|
|
|
76
87
|
let output = "";
|
|
77
88
|
let errorOutput = "";
|
|
78
|
-
const outputLines: string[] = [];
|
|
79
89
|
let errorLines: string[] = [];
|
|
80
90
|
|
|
81
91
|
// Handle stdout
|
|
@@ -83,8 +93,6 @@ export function executeCommand(
|
|
|
83
93
|
childProcess.stdout.on("data", (data: Buffer) => {
|
|
84
94
|
const chunk = data.toString();
|
|
85
95
|
output += chunk;
|
|
86
|
-
const newLines = chunk.split("\n");
|
|
87
|
-
outputLines.push(...newLines);
|
|
88
96
|
});
|
|
89
97
|
}
|
|
90
98
|
|
|
@@ -95,53 +103,37 @@ export function executeCommand(
|
|
|
95
103
|
errorOutput += chunk;
|
|
96
104
|
const newLines = chunk.split("\n");
|
|
97
105
|
errorLines.push(...newLines);
|
|
98
|
-
// Keep only the last
|
|
99
|
-
if (errorLines.length >
|
|
100
|
-
errorLines = errorLines.slice(-
|
|
106
|
+
// Keep only the last 20 lines, just for safety
|
|
107
|
+
if (errorLines.length > 20) {
|
|
108
|
+
errorLines = errorLines.slice(-20);
|
|
101
109
|
}
|
|
102
110
|
});
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
// Handle process completion
|
|
106
114
|
childProcess.on("close", (code: number | null) => {
|
|
107
|
-
|
|
115
|
+
// this can extract and detect errors from docker logs because it not throw error code
|
|
116
|
+
const errors = extractErrorLines(errorLines);
|
|
117
|
+
|
|
118
|
+
if (code === 0 && !errors) {
|
|
108
119
|
console.log(`\n✅ ${description} completed successfully!`);
|
|
109
120
|
resolve(output);
|
|
110
121
|
} else {
|
|
111
122
|
console.error(`\n❌ ${description} failed with exit code ${code}`);
|
|
112
123
|
// Print error output starting from "project metadata hash computed on deployment" or error patterns, or all logs if not found
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
let startIndex = -1;
|
|
122
|
-
if (metadataIndex >= 0) {
|
|
123
|
-
startIndex = metadataIndex;
|
|
124
|
-
} else if (errorIndex >= 0) {
|
|
125
|
-
startIndex = errorIndex;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (startIndex >= 0) {
|
|
129
|
-
const linesToPrint = errorLines.slice(startIndex);
|
|
130
|
-
linesToPrint.forEach((line) => {
|
|
131
|
-
if (line.trim()) console.error(line);
|
|
132
|
-
});
|
|
133
|
-
} else {
|
|
134
|
-
errorLines.forEach((line) => {
|
|
135
|
-
if (line.trim()) console.error(line);
|
|
136
|
-
});
|
|
124
|
+
if (errors) {
|
|
125
|
+
console.error(errors);
|
|
126
|
+
if (
|
|
127
|
+
!command.includes("--no-verify") &&
|
|
128
|
+
errors.includes("mismatch number of constructor arguments")
|
|
129
|
+
) {
|
|
130
|
+
errorOutput += `\nCan not verify contract with constructor arguments.\n`;
|
|
137
131
|
}
|
|
138
132
|
}
|
|
139
|
-
|
|
140
|
-
console.error(errorOutput);
|
|
141
|
-
}
|
|
133
|
+
|
|
142
134
|
reject(
|
|
143
135
|
new Error(
|
|
144
|
-
`Command failed with exit code ${code}. Error output: ${errorOutput}`,
|
|
136
|
+
`Command failed with exit code ${code}. Error output: \n${errorOutput}`,
|
|
145
137
|
),
|
|
146
138
|
);
|
|
147
139
|
}
|
|
@@ -154,3 +146,35 @@ export function executeCommand(
|
|
|
154
146
|
});
|
|
155
147
|
});
|
|
156
148
|
}
|
|
149
|
+
|
|
150
|
+
function extractErrorLines(errorLines: string[]): string | null {
|
|
151
|
+
let output: string = "";
|
|
152
|
+
if (errorLines.length > 0) {
|
|
153
|
+
const metadataIndex = errorLines.findIndex((line) =>
|
|
154
|
+
line.includes("project metadata hash computed on deployment"),
|
|
155
|
+
);
|
|
156
|
+
const errorIndex = errorLines.findIndex(
|
|
157
|
+
(line) =>
|
|
158
|
+
line.toLowerCase().includes("error[") ||
|
|
159
|
+
line.toLowerCase().includes("error:"),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
let startIndex = -1;
|
|
163
|
+
if (metadataIndex >= 0) {
|
|
164
|
+
startIndex = metadataIndex;
|
|
165
|
+
} else if (errorIndex >= 0) {
|
|
166
|
+
startIndex = errorIndex;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (startIndex === -1) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const linesToPrint = errorLines.slice(startIndex);
|
|
174
|
+
linesToPrint.forEach((line) => {
|
|
175
|
+
if (line.trim()) output += line + "\n";
|
|
176
|
+
});
|
|
177
|
+
return output;
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
@@ -41,6 +41,15 @@ export function getContractNameFromCargoToml(contractFolder: string): string {
|
|
|
41
41
|
return parsed.package.name;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
export function isContractHasConstructor(contractFolder: string): boolean {
|
|
45
|
+
const contractPath = path.resolve(contractFolder, "src/lib.rs");
|
|
46
|
+
if (!fs.existsSync(contractPath)) {
|
|
47
|
+
throw new Error(`lib.rs not found in contract folder: ${contractPath}`);
|
|
48
|
+
}
|
|
49
|
+
const contractContent = fs.readFileSync(contractPath, "utf8");
|
|
50
|
+
return contractContent.includes("#[constructor]");
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
export function getExportConfig(
|
|
45
54
|
contractFolder?: string,
|
|
46
55
|
contractName?: string,
|
|
@@ -225,3 +234,61 @@ export function handleSolcError(
|
|
|
225
234
|
console.error("\n💡 Please check the error details above and try again.");
|
|
226
235
|
}
|
|
227
236
|
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Dynamically load deployed contracts from the TypeScript file
|
|
240
|
+
* This is useful when the file has been updated during runtime
|
|
241
|
+
* @returns The deployed contracts object
|
|
242
|
+
*/
|
|
243
|
+
export function loadDeployedContracts(): any {
|
|
244
|
+
const deployedContractsPath = "../nextjs/contracts/deployedContracts.ts";
|
|
245
|
+
|
|
246
|
+
if (!fs.existsSync(deployedContractsPath)) {
|
|
247
|
+
throw new Error("deployedContracts.ts file not found");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const fileContent = fs.readFileSync(deployedContractsPath, "utf8");
|
|
251
|
+
const match = fileContent.match(
|
|
252
|
+
/const deployedContracts = ([\s\S]*?) as const;/,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
if (!match) {
|
|
256
|
+
throw new Error("Could not parse deployedContracts.ts file");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// eslint-disable-next-line no-eval
|
|
260
|
+
return eval("(" + match[1] + ")");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get contract data from deployed contracts
|
|
265
|
+
* @param chainId - The chain ID
|
|
266
|
+
* @param contractName - The contract name
|
|
267
|
+
* @returns The contract data with address, txHash, and abi
|
|
268
|
+
*/
|
|
269
|
+
export function getContractData(chainId: string, contractName: string): any {
|
|
270
|
+
const deployedContracts = loadDeployedContracts();
|
|
271
|
+
|
|
272
|
+
if (
|
|
273
|
+
!deployedContracts ||
|
|
274
|
+
!deployedContracts[chainId] ||
|
|
275
|
+
!deployedContracts[chainId][contractName]
|
|
276
|
+
) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
`Contract ${contractName} not found in deployedContracts for chain ${chainId}`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const contractData = deployedContracts[chainId][contractName];
|
|
283
|
+
if (!contractData.abi) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
`ABI not found for contract ${contractName} on chain ${chainId}`,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return contractData;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function contractHasInitializeFunction(contractData: any): boolean {
|
|
293
|
+
return contractData.abi.some((abi: any) => abi.name === "initialize");
|
|
294
|
+
}
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
import * as path from "path";
|
|
11
11
|
import * as fs from "fs";
|
|
12
12
|
import { config as dotenvConfig } from "dotenv";
|
|
13
|
-
import { SupportedNetworkMinimal } from "./type";
|
|
14
13
|
|
|
15
14
|
const envPath = path.resolve(__dirname, "../../.env");
|
|
16
15
|
if (fs.existsSync(envPath)) {
|
|
@@ -47,7 +46,7 @@ export const ORBIT_CHAINS: Chain[] = [
|
|
|
47
46
|
superpositionTestnet as Chain,
|
|
48
47
|
];
|
|
49
48
|
|
|
50
|
-
export function getChain(networkName: string):
|
|
49
|
+
export function getChain(networkName: string): Chain | null {
|
|
51
50
|
try {
|
|
52
51
|
const actualNetworkName = ALIASES[networkName.toLowerCase()] || networkName;
|
|
53
52
|
|
|
@@ -55,15 +54,7 @@ export function getChain(networkName: string): SupportedNetworkMinimal | null {
|
|
|
55
54
|
([key]) => key.toLowerCase() === actualNetworkName.toLowerCase(),
|
|
56
55
|
);
|
|
57
56
|
|
|
58
|
-
if (chainEntry)
|
|
59
|
-
return {
|
|
60
|
-
name: chainEntry[0],
|
|
61
|
-
alias: getAliasFromNetworkName(chainEntry[0]),
|
|
62
|
-
id: chainEntry[1].id.toString(),
|
|
63
|
-
rpcUrl: getRpcUrlFromChain(chainEntry[1]),
|
|
64
|
-
blockExplorerUrl: chainEntry[1].blockExplorers?.default?.url,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
57
|
+
if (chainEntry) return chainEntry[1];
|
|
67
58
|
|
|
68
59
|
const supportedNetworks = Object.keys(SUPPORTED_NETWORKS);
|
|
69
60
|
console.warn(
|
|
@@ -132,6 +123,7 @@ export function getPrivateKey(networkName: string): string {
|
|
|
132
123
|
|
|
133
124
|
export const getAccountAddress = (networkName: string): Address | undefined => {
|
|
134
125
|
const actualNetworkName = ALIASES[networkName.toLowerCase()] || networkName;
|
|
126
|
+
|
|
135
127
|
switch (actualNetworkName.toLowerCase()) {
|
|
136
128
|
case "arbitrum":
|
|
137
129
|
return process.env["ACCOUNT_ADDRESS_MAINNET"] as Address;
|
|
@@ -155,7 +147,7 @@ export const getAccountAddress = (networkName: string): Address | undefined => {
|
|
|
155
147
|
}
|
|
156
148
|
};
|
|
157
149
|
|
|
158
|
-
function getRpcUrlFromChain(chain: Chain): string {
|
|
150
|
+
export function getRpcUrlFromChain(chain: Chain): string {
|
|
159
151
|
//Prefer user rpc url from env
|
|
160
152
|
switch (chain.id) {
|
|
161
153
|
case arbitrum.id:
|
|
@@ -214,9 +206,8 @@ function getRpcUrlFromChain(chain: Chain): string {
|
|
|
214
206
|
throw new Error(`No RPC URL found for chain ${chain.name}`);
|
|
215
207
|
}
|
|
216
208
|
|
|
217
|
-
function
|
|
209
|
+
export function getBlockExplorerUrlFromChain(chain: Chain): string | undefined {
|
|
218
210
|
return (
|
|
219
|
-
|
|
220
|
-
networkName
|
|
211
|
+
chain.blockExplorers?.default?.url || chain.blockExplorers?.etherscan?.url
|
|
221
212
|
);
|
|
222
213
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address } from "viem";
|
|
1
|
+
import { Address, Chain } from "viem";
|
|
2
2
|
|
|
3
3
|
interface BaseCommandOptions {
|
|
4
4
|
_: (string | number)[];
|
|
@@ -14,11 +14,11 @@ export interface DeployOptions {
|
|
|
14
14
|
contract?: string;
|
|
15
15
|
name?: string;
|
|
16
16
|
constructorArgs?: NonNullable<unknown>[];
|
|
17
|
+
isOrbit?: boolean;
|
|
17
18
|
network?: string;
|
|
18
19
|
estimateGas?: boolean;
|
|
19
20
|
maxFee?: string;
|
|
20
21
|
verify?: boolean;
|
|
21
|
-
isOrbit?: boolean;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface DeploymentData {
|
|
@@ -32,7 +32,7 @@ export interface DeploymentConfig {
|
|
|
32
32
|
contractFolder: string;
|
|
33
33
|
contractName: string;
|
|
34
34
|
deploymentDir: string;
|
|
35
|
-
chain
|
|
35
|
+
chain: Chain;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export interface ExportConfig {
|
|
@@ -43,11 +43,3 @@ export interface ExportConfig {
|
|
|
43
43
|
txHash: string;
|
|
44
44
|
chainId: string;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
export interface SupportedNetworkMinimal {
|
|
48
|
-
name: string;
|
|
49
|
-
alias: string;
|
|
50
|
-
id: string;
|
|
51
|
-
rpcUrl: string;
|
|
52
|
-
blockExplorerUrl?: string | undefined;
|
|
53
|
-
}
|
package/templates/base/readme.md
CHANGED
|
@@ -233,9 +233,10 @@ Check full documentation for more [details](https://docs.arbitrum.io/stylus/how-
|
|
|
233
233
|
|
|
234
234
|
### Stylus Local Verification (Under Development)
|
|
235
235
|
|
|
236
|
-
Make sure your constructor does not contain any args
|
|
236
|
+
Make sure your contract does not include constructor or constructor does not contain any args
|
|
237
237
|
|
|
238
238
|
```rs
|
|
239
|
+
[#constructor]
|
|
239
240
|
pub fn constructor(&mut self)
|
|
240
241
|
```
|
|
241
242
|
|
|
@@ -277,6 +278,23 @@ Check official document for detail instructions: <https://docs.arbitrum.io/stylu
|
|
|
277
278
|
|
|
278
279
|
> **Note**: Arbiscan verification for Stylus contracts is still evolving. If you encounter issues, consider using the local verification method or check Arbiscan's latest documentation for Stylus-specific instructions.
|
|
279
280
|
|
|
281
|
+
**Tip**: If you still want to initialize your contract, then add your own `initialize()` function and initialize it yourself
|
|
282
|
+
Sample :
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
pub fn initialize(&mut self, initial_number: U256) {
|
|
286
|
+
if !self.is_initialized.get() {
|
|
287
|
+
self.number.set(initial_number);
|
|
288
|
+
self.is_initialized.set(true);
|
|
289
|
+
} else {
|
|
290
|
+
panic!("Counter already initialized");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Then use `cast --rpc-url <your-rpc-url> --private-key <your-private-key> [deployed-contract-address] "initialize(uint256)" <initial_number>`
|
|
296
|
+
Or check [`deploy_contract.ts` lines 95-118](packages/stylus/scripts/deploy_contract.ts#L95-L118) and add it to your `deploy.ts` script.
|
|
297
|
+
|
|
280
298
|
</details>
|
|
281
299
|
|
|
282
300
|
## 🛠️ Troubleshooting Common Issues
|