Skip to content

Commit 74fcb56

Browse files
authored
chore: Simplify error messages and refactor contract declaration (#664)
1 parent 7888b62 commit 74fcb56

File tree

3 files changed

+186
-35
lines changed

3 files changed

+186
-35
lines changed

packages/snfoundry/scripts-ts/deploy-contract.ts

Lines changed: 175 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,45 @@ let deployCalls = [];
136136

137137
const { provider, deployer, feeToken }: Network = networks[networkName];
138138

139+
/**
140+
* Calculate estimated tip for declaration transaction with fee escalation
141+
*/
142+
const estimateTransactionTip = async (
143+
payload: DeclareContractPayload,
144+
classHash: string
145+
): Promise<bigint> => {
146+
const { overall_fee } = await deployer.estimateDeclareFee({
147+
contract: payload.contract,
148+
compiledClassHash: classHash,
149+
});
150+
151+
const minimumTip = 500000000000000000n; // 0.1 STRK
152+
const finalTip = overall_fee > minimumTip ? overall_fee : minimumTip;
153+
154+
return finalTip;
155+
};
156+
157+
/**
158+
* Get contract size for logging purposes
159+
*/
160+
const getContractSize = (payload: DeclareContractPayload): number => {
161+
return typeof payload.contract === "string"
162+
? payload.contract.length
163+
: JSON.stringify(payload.contract).length;
164+
};
165+
166+
/**
167+
* Calculate retry interval based on contract size
168+
*/
169+
const estimateRetryInterval = (payload: DeclareContractPayload): number => {
170+
const contractSize = getContractSize(payload);
171+
172+
const baseInterval = 5000;
173+
const sizeMultiplier = Math.ceil(contractSize / 100000) * 1.5; // 1.5 seconds per 100KB
174+
175+
return Math.min(baseInterval + sizeMultiplier * 1000, 30000);
176+
};
177+
139178
const declareIfNot_NotWait = async (
140179
payload: DeclareContractPayload,
141180
options?: UniversalDetails
@@ -167,8 +206,18 @@ const declareIfNot_NotWait = async (
167206
}
168207

169208
try {
170-
const declareOptions =
171-
networkName === "devnet" ? { ...options, tip: 1000n } : { ...options };
209+
const estimatedTip = await estimateTransactionTip(payload, classHash);
210+
const retryInterval = estimateRetryInterval(payload);
211+
console.log(yellow(`Estimated tip: ${estimatedTip.toString()}`));
212+
console.log(
213+
yellow(`Estimated retry interval: ${retryInterval.toString()}`)
214+
);
215+
216+
const declareOptions = {
217+
...options,
218+
estimated_tip: estimatedTip,
219+
};
220+
172221
const { transaction_hash } = await deployer.declare(
173222
payload,
174223
declareOptions
@@ -178,24 +227,28 @@ const declareIfNot_NotWait = async (
178227
console.log(
179228
yellow("Waiting for declaration transaction to be accepted...")
180229
);
181-
const receipt = await provider.waitForTransaction(transaction_hash);
182-
console.log(
183-
yellow("Declaration transaction receipt:"),
184-
JSON.stringify(
185-
receipt,
186-
(_, v) => (typeof v === "bigint" ? v.toString() : v),
187-
2
188-
)
189-
);
230+
const receipt = await provider.waitForTransaction(transaction_hash, {
231+
retryInterval,
232+
});
190233

191234
const receiptAny = receipt as any;
192235
if (receiptAny.execution_status !== "SUCCEEDED") {
236+
// Show verbose error details when declaration fails
237+
console.log(
238+
red("Declaration transaction receipt:"),
239+
JSON.stringify(
240+
receipt,
241+
(_, v) => (typeof v === "bigint" ? v.toString() : v),
242+
2
243+
)
244+
);
193245
const revertReason = receiptAny.revert_reason || "Unknown reason";
194246
throw new Error(
195247
red(`Declaration failed or reverted. Reason: ${revertReason}`)
196248
);
197249
}
198250
console.log(green("Declaration successful"));
251+
console.log(yellow("Declaration fee:"), receiptAny.actual_fee);
199252
}
200253

201254
return {
@@ -207,15 +260,42 @@ const declareIfNot_NotWait = async (
207260
e.isType("VALIDATION_FAILURE") &&
208261
e.baseError.data.includes("exceed balance")
209262
) {
263+
console.error(red("❌ Class declaration failed: Insufficient balance"));
264+
console.error(red(` Deployer address: ${deployer.address}`));
210265
console.error(
211-
red("Class declaration failed: deployer"),
212-
deployer.address,
213-
red("has insufficient balance.")
266+
red(
267+
` Please ensure your account has enough ${feeToken[0].name} to cover the declaration fee.`
268+
)
214269
);
215270
throw "Class declaration failed: insufficient balance";
216271
}
217272

218-
console.error(red("Class declaration failed: error details below"));
273+
if (
274+
e instanceof RpcError &&
275+
(e.message?.includes("connection") || e.message?.includes("network"))
276+
) {
277+
console.error(red("❌ Class declaration failed: RPC connection error"));
278+
console.error(red(` Unable to connect to ${networkName} network.`));
279+
console.error(
280+
red(" Please check your RPC URL and network connectivity.")
281+
);
282+
throw "Class declaration failed: RPC connection error";
283+
}
284+
285+
if (
286+
e instanceof RpcError &&
287+
(e.message?.includes("timeout") || e.message?.includes("TIMEOUT"))
288+
) {
289+
console.error(red("❌ Class declaration failed: Request timeout"));
290+
console.error(
291+
red(
292+
" The RPC request timed out. Please try again or check your network connection."
293+
)
294+
);
295+
throw "Class declaration failed: request timeout";
296+
}
297+
298+
console.error(red("❌ Class declaration failed: error details below"));
219299
console.error(e);
220300
throw "Class declaration failed";
221301
}
@@ -465,14 +545,45 @@ const executeDeployCalls = async (options?: UniversalDetails) => {
465545
e.baseError.data.includes("exceed balance")
466546
) {
467547
console.error(
468-
red("Deployment tx execution failed: deployer"),
469-
deployer.address,
470-
red("has insufficient balance.")
548+
red("❌ Deployment execution failed: Insufficient balance")
549+
);
550+
console.error(red(` Deployer address: ${deployer.address}`));
551+
console.error(
552+
red(
553+
` Please ensure your account has enough ${feeToken[0].name} to cover the deployment fees.`
554+
)
471555
);
472556
throw "Deployment tx execution failed: insufficient balance";
473557
}
474558

475-
console.error(red("Deployment tx execution failed: error details below"));
559+
if (
560+
e instanceof RpcError &&
561+
(e.message?.includes("connection") || e.message?.includes("network"))
562+
) {
563+
console.error(
564+
red("❌ Deployment execution failed: RPC connection error")
565+
);
566+
console.error(red(` Unable to connect to ${networkName} network.`));
567+
console.error(
568+
red(" Please check your RPC URL and network connectivity.")
569+
);
570+
throw "Deployment tx execution failed: RPC connection error";
571+
}
572+
573+
if (
574+
e instanceof RpcError &&
575+
(e.message?.includes("timeout") || e.message?.includes("TIMEOUT"))
576+
) {
577+
console.error(red("❌ Deployment execution failed: Request timeout"));
578+
console.error(
579+
red(
580+
" The RPC request timed out. Please try again or check your network connection."
581+
)
582+
);
583+
throw "Deployment tx execution failed: request timeout";
584+
}
585+
586+
console.error(red("❌ Deployment execution failed: error details below"));
476587
console.error(e);
477588
throw "Deployment tx execution failed";
478589
}
@@ -512,25 +623,40 @@ const exportDeployments = () => {
512623

513624
const assertDeployerDefined = () => {
514625
if (!deployer) {
515-
const errorMessage = `Deployer account is not defined. \`ACCOUNT_ADDRESS_${networkName.toUpperCase()}\` or \`PRIVATE_KEY_${networkName.toUpperCase()}\` is missing from \`.env\`.`;
516-
console.error(red(errorMessage));
626+
const errorMessage = `❌ Deployer account is not defined. \`ACCOUNT_ADDRESS_${networkName.toUpperCase()}\` or \`PRIVATE_KEY_${networkName.toUpperCase()}\` is missing from \`.env\`.\n Please add both environment variables to your \`.env\` file.`;
517627
throw new Error(errorMessage);
518628
}
519629
};
520630

521631
const assertRpcNetworkActive = async () => {
522632
if (!provider) {
523-
const errorMessage = `RPC provider is not defined. \`RPC_URL_${networkName.toUpperCase()}\` is missing from \`.env\`.`;
524-
console.error(red(errorMessage));
633+
const errorMessage = `❌ RPC provider is not defined. \`RPC_URL_${networkName.toUpperCase()}\` is missing from \`.env\`.`;
525634
throw new Error(errorMessage);
526635
}
527636

528637
try {
529638
const block = await provider.getBlock("latest");
530639
console.log(green(`✓ RPC connected (Block #${block.block_number})`));
531640
} catch (e) {
532-
const errorMessage = `RPC provider is not active. \`RPC_URL_${networkName.toUpperCase()}\` is not reachable.\n`;
533-
console.error(red(errorMessage), e);
641+
if (
642+
e instanceof RpcError &&
643+
(e.message?.includes("connection") || e.message?.includes("network"))
644+
) {
645+
const errorMessage = `❌ RPC connection failed. Unable to connect to ${networkName} network.\n Please check your \`RPC_URL_${networkName.toUpperCase()}\` in \`.env\` and ensure the RPC endpoint is accessible.`;
646+
throw new Error(errorMessage);
647+
}
648+
649+
if (
650+
e instanceof RpcError &&
651+
(e.message?.includes("timeout") || e.message?.includes("TIMEOUT"))
652+
) {
653+
const errorMessage = `❌ RPC request timeout. The connection to ${networkName} network timed out.\n Please check your network connection and try again.`;
654+
throw new Error(errorMessage);
655+
}
656+
657+
const errorMessage = `❌ RPC provider is not active. \`RPC_URL_${networkName.toUpperCase()}\` is not reachable.\n Error details: ${
658+
e.message || e
659+
}`;
534660
throw new Error(errorMessage);
535661
}
536662
};
@@ -564,20 +690,37 @@ const assertDeployerSignable = async () => {
564690
);
565691
} catch (e) {
566692
if (e.toString().includes("Contract not found")) {
567-
const errorMessage = `Deployer account at \`${deployer.address}\` hasn't been deployed on ${networkName} network.`;
568-
console.error(red(errorMessage), e);
693+
const errorMessage = `Deployer account at \`${deployer.address}\` hasn't been deployed on ${networkName} network.\n Please deploy your account first or use a different account address.`;
694+
569695
throw new Error(errorMessage);
570696
}
571697

572-
const errorMessage =
573-
"Unable to verify signature from the deployer account. Possible causes: network latency, RPC timeout.";
574-
console.error(red(errorMessage), e);
698+
if (
699+
e instanceof RpcError &&
700+
(e.message?.includes("connection") || e.message?.includes("network"))
701+
) {
702+
const errorMessage = `❌ Unable to verify deployer signature: RPC connection error.\n Please check your network connection and RPC endpoint.`;
703+
704+
throw new Error(errorMessage);
705+
}
706+
707+
if (
708+
e instanceof RpcError &&
709+
(e.message?.includes("timeout") || e.message?.includes("TIMEOUT"))
710+
) {
711+
const errorMessage = `❌ Unable to verify deployer signature: Request timeout.\n Please try again or check your network connection.`;
712+
713+
throw new Error(errorMessage);
714+
}
715+
716+
const errorMessage = `❌ Unable to verify signature from the deployer account.\n Possible causes: network latency, RPC timeout, or invalid account configuration.`;
717+
575718
throw new Error(errorMessage);
576719
}
577720

578721
if (!isValidSig) {
579-
const errorMessage = `Invalid signature. \`ACCOUNT_ADDRESS_${networkName.toUpperCase()}\` is not match with \`PRIVATE_KEY_${networkName.toUpperCase()}\`.`;
580-
console.error(red(errorMessage));
722+
const errorMessage = `Invalid signature. \`ACCOUNT_ADDRESS_${networkName.toUpperCase()}\` does not match \`PRIVATE_KEY_${networkName.toUpperCase()}\`.\n Please verify that your account address and private key are correctly configured in \`.env\`.`;
723+
581724
throw new Error(errorMessage);
582725
}
583726
};

packages/snfoundry/scripts-ts/deploy.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
assertRpcNetworkActive,
88
assertDeployerSignable,
99
} from "./deploy-contract";
10-
import { green } from "./helpers/colorize-log";
10+
import { green, red } from "./helpers/colorize-log";
1111

1212
/**
1313
* Deploy a contract using the specified parameters.
@@ -65,7 +65,11 @@ const main = async (): Promise<void> => {
6565

6666
console.log(green("All Setup Done!"));
6767
} catch (err) {
68-
console.log(err);
68+
if (err instanceof Error) {
69+
console.error(red(err.message));
70+
} else {
71+
console.error(err);
72+
}
6973
process.exit(1); //exit with error so that non subsequent scripts are run
7074
}
7175
};

packages/snfoundry/scripts-ts/helpers/deploy-wrapper.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ function main() {
5555

5656
execSync(command, { stdio: "inherit" });
5757
} catch (error) {
58-
console.error("Error during deployment:", error);
58+
if (error instanceof Error) {
59+
console.error("Error during deployment:", error.message);
60+
} else {
61+
console.error("Error during deployment:", error);
62+
}
5963
process.exit(1);
6064
}
6165
}

0 commit comments

Comments
 (0)