FilOzone / FilOzone/filecoin-nova
nova ens: check wallet balance before submitting setContenthash tx
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`nova ens --ens ` submits the `setContenthash` transaction without first checking the wallet's ETH balance. When the wallet is underfunded:
1. The RPC accepts the raw tx and returns a hash (most public RPCs skip balance checks at submission time).
2. Block builders reject the tx when trying to include it (not enough ETH to cover `gas × gasPrice`).
3. Nova waits 120s for confirmation, times out, and reports: *"Transaction not confirmed within 120s. It may have been dropped (gas too low) or is still pending."*
That message lists plausible causes but misses the actual one. In CI with an automatic retry loop, this wastes 120s × N retries per deploy without ever succeeding — and each retry sends a new tx with the next nonce, burning through any remaining balance trying.
## Reproduction
Wallet with <0.0005 ETH on mainnet:
```bash
NOVA_ENS_KEY=0x... NOVA_RPC_URL=https://ethereum-rpc.publicnode.com \
nova ens bafybeicvntbhmsx3ybwd7brva6upxz4mabm7ei72of2k44endly53myfo4 \
--ens .eth
```
Output:
```
┃ ✔ Connected to Ethereum
┃ ✔ Wallet 0x...
┃ ✔ Resolver 0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63
┃ ⏳ Updating .eth
┃ tx: 0x...
┃ ⏳ Waiting for confirmation...
┗━━
✘ ENS update failed: Transaction not confirmed within 120s.
It may have been dropped (gas too low) or is still pending.
```
Check the tx hash on etherscan or via `eth_getTransactionByHash` — it's nowhere. The correct error should have been "wallet is underfunded" before any tx was ever broadcast.
Submitting the same tx with explicit gas overrides via a standalone script surfaces the real error:
```
insufficient funds for intrinsic transaction cost
```
## Expected behavior
Before calling `resolverContract.setContenthash(node, contenthash)` in `src/ens.ts`, compute the upper bound on gas cost (`gasEstimate × maxFeePerGas`) and compare against `provider.getBalance(wallet.address)`. If insufficient, throw a clear error including:
- Current balance in ETH
- Required balance in ETH
- Wallet address (so the user can send ETH to it)
Example:
```
✘ Wallet 0x244d2454... has 0.000114 ETH, needs ~0.00056 ETH for gas.
Top up: send at least 0.001 ETH to 0x244d2454...
```
## Proposed fix
In `src/ens.ts` `updateEnsContenthash`, between the resolver-is-found check and the `staticCall` dry-run, add:
```ts
const gasEstimate = await resolverContract.setContenthash.estimateGas(node, contenthash)
const feeData = await provider.getFeeData()
const maxCost = gasEstimate * (feeData.maxFeePerGas ?? feeData.gasPrice ?? 0n)
const balance = await provider.getBalance(wallet.address)
if (balance < maxCost) {
throw new Error(
`Wallet ${wallet.address} is underfunded.\n\n` +
` Balance: ${ethers.formatEther(balance)} ETH\n` +
` Needed: ~${ethers.formatEther(maxCost)} ETH\n\n` +
` Top up by sending ETH to ${wallet.address}.`
)
}
```
This also makes CI fail fast with actionable output instead of wasting retry budget on doomed submissions.
## Additional context
Observed in a GitHub Actions CI loop that retries `nova ens` 3× with 15s backoff on failure. Three consecutive 120s waits (≈6 minutes of CI time) produced three tx hashes, none ever mined, wallet balance unchanged, before the workflow gave up.
`NOVA_RPC_URL=https://ethereum-rpc.publicnode.com` was used, but the issue is not RPC-specific — any node that accepts raw txs without balance validation shows the same symptom.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.