Skip to content

Commit

Permalink
feat: linea (#2665)
Browse files Browse the repository at this point in the history
* chore: update snapshots

* feat: Add support for linea_estimateGas

* fix: fix returns

* fix: lineaEstimateGas refactoring

* chore: tweaks

* chore: lint

---------

Co-authored-by: wantedsystem <amine.harty@consensys.net>
  • Loading branch information
jxom and wantedsystem committed Aug 29, 2024
1 parent 86228ee commit 2e05c52
Show file tree
Hide file tree
Showing 21 changed files with 531 additions and 78 deletions.
5 changes: 5 additions & 0 deletions .changeset/slimy-melons-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": minor
---

Added built-in support for Linea gas & fee estimations.
5 changes: 5 additions & 0 deletions .changeset/wise-planets-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": minor
---

Deprecated `chain.fees.defaultPriorityFee`, use `chain.fees.maxPriorityFeePerGas` instead.
23 changes: 15 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/actions/public/estimateFeesPerGas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type Eip1559FeesNotSupportedErrorType,
} from '../../errors/fee.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Account } from '../../types/account.js'
import type { Block } from '../../types/block.js'
import type {
Chain,
Expand Down Expand Up @@ -99,7 +100,7 @@ export async function internal_estimateFeesPerGas<
client: Client<Transport, chain>,
args: EstimateFeesPerGasParameters<chain, chainOverride, type> & {
block?: Block | undefined
request?: PrepareTransactionRequestParameters | undefined
request?: PrepareTransactionRequestParameters<Chain, Account> | undefined
},
): Promise<EstimateFeesPerGasReturnType<type>> {
const {
Expand Down
54 changes: 42 additions & 12 deletions src/actions/public/estimateMaxPriorityFeePerGas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test('fallback', async () => {
expect(await estimateMaxPriorityFeePerGas(client_1)).toBeDefined()
})

test('args: chain `defaultPriorityFee` override', async () => {
test('args: chain `priorityFee` override', async () => {
// value
const client_1 = createPublicClient({
transport: http(anvilMainnet.rpcUrl.http),
Expand All @@ -41,7 +41,7 @@ test('args: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: 69420n,
maxPriorityFeePerGas: 69420n,
},
},
}),
Expand All @@ -56,7 +56,7 @@ test('args: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: () => 69420n,
maxPriorityFeePerGas: () => 69420n,
},
},
}),
Expand All @@ -71,7 +71,7 @@ test('args: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: async () => 69420n,
maxPriorityFeePerGas: async () => 69420n,
},
},
}),
Expand All @@ -86,7 +86,7 @@ test('args: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: 0n,
maxPriorityFeePerGas: 0n,
},
},
}),
Expand All @@ -101,20 +101,50 @@ test('args: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: async () => 0n,
maxPriorityFeePerGas: async () => 0n,
},
},
}),
).toBe(0n)

// fallback
const client_6 = createPublicClient({
transport: http(anvilMainnet.rpcUrl.http),
})
expect(
await estimateMaxPriorityFeePerGas(client_6, {
chain: {
...anvilMainnet.chain,
fees: {
maxPriorityFeePerGas: async () => null,
},
},
}),
).toBeDefined()

// deprecated `defaultPriorityFee`
const client_7 = createPublicClient({
transport: http(anvilMainnet.rpcUrl.http),
})
expect(
await estimateMaxPriorityFeePerGas(client_7, {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: async () => 69420n,
},
},
}),
).toBe(69420n)
})

test('client: chain `defaultPriorityFee` override', async () => {
test('client: chain `priorityFee` override', async () => {
// value
const client_1 = createPublicClient({
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: 69420n,
maxPriorityFeePerGas: 69420n,
},
},
transport: http(),
Expand All @@ -126,7 +156,7 @@ test('client: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: () => 69420n,
maxPriorityFeePerGas: () => 69420n,
},
},
transport: http(),
Expand All @@ -138,7 +168,7 @@ test('client: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: async () => 69420n,
maxPriorityFeePerGas: async () => 69420n,
},
},
transport: http(),
Expand All @@ -150,7 +180,7 @@ test('client: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: 0n,
maxPriorityFeePerGas: 0n,
},
},
transport: http(),
Expand All @@ -162,7 +192,7 @@ test('client: chain `defaultPriorityFee` override', async () => {
chain: {
...anvilMainnet.chain,
fees: {
defaultPriorityFee: async () => 0n,
maxPriorityFeePerGas: async () => 0n,
},
},
transport: http(),
Expand Down
28 changes: 17 additions & 11 deletions src/actions/public/estimateMaxPriorityFeePerGas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,25 @@ export async function internal_estimateMaxPriorityFeePerGas<
},
): Promise<EstimateMaxPriorityFeePerGasReturnType> {
const { block: block_, chain = client.chain, request } = args || {}
if (typeof chain?.fees?.defaultPriorityFee === 'function') {
const block = block_ || (await getAction(client, getBlock, 'getBlock')({}))
return chain.fees.defaultPriorityFee({
block,
client,
request,
} as ChainFeesFnParameters)
}

if (typeof chain?.fees?.defaultPriorityFee !== 'undefined')
return chain?.fees?.defaultPriorityFee

try {
const maxPriorityFeePerGas =
chain?.fees?.maxPriorityFeePerGas ?? chain?.fees?.defaultPriorityFee

if (typeof maxPriorityFeePerGas === 'function') {
const block =
block_ || (await getAction(client, getBlock, 'getBlock')({}))
const maxPriorityFeePerGas_ = await maxPriorityFeePerGas({
block,
client,
request,
} as ChainFeesFnParameters)
if (maxPriorityFeePerGas_ === null) throw new Error()
return maxPriorityFeePerGas_
}

if (typeof maxPriorityFeePerGas !== 'undefined') return maxPriorityFeePerGas

const maxPriorityFeePerGasHex = await client.request({
method: 'eth_maxPriorityFeePerGas',
})
Expand Down
2 changes: 1 addition & 1 deletion src/actions/public/getTransactionReceipt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ test('chain w/ custom block type', async () => {
"transactionLogIndex": 10,
},
],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logsBloom": "0x10880004000400000000000000000000000040000000020000000000000400120000000000100000000080000001000000000000000000000000000000804000004000101002040000000008000000200000000000000000001000000000080000840000020000000000100000000800000000020100000000000010000000000000000400000000000004000040000000000000280000000000002000000000000000004000120000000200000000000000000000000000000000200000800000001002008008000000000000000000000000200000800000000000000020001800000000000000000000001000000000000000000000000000000000000000",
"root": "0xc621ee95e2d4ab65ecf499805dba770b20297c64029816b18c618fc49fe3d748",
"status": "success",
"to": "0x54de43b6ba21a5553697a2b78338e046dd7e0278",
Expand Down
2 changes: 2 additions & 0 deletions src/chains/definitions/linea.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { chainConfig } from '../../linea/chainConfig.js'
import { defineChain } from '../../utils/chain/defineChain.js'

export const linea = /*#__PURE__*/ defineChain({
...chainConfig,
id: 59_144,
name: 'Linea Mainnet',
nativeCurrency: { name: 'Linea Ether', symbol: 'ETH', decimals: 18 },
Expand Down
2 changes: 2 additions & 0 deletions src/chains/definitions/lineaSepolia.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { chainConfig } from '../../linea/chainConfig.js'
import { defineChain } from '../../utils/chain/defineChain.js'

export const lineaSepolia = /*#__PURE__*/ defineChain({
...chainConfig,
id: 59_141,
name: 'Linea Sepolia Testnet',
nativeCurrency: { name: 'Linea Ether', symbol: 'ETH', decimals: 18 },
Expand Down
3 changes: 2 additions & 1 deletion src/errors/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ export type InsufficientFundsErrorType = InsufficientFundsError & {
name: 'InsufficientFundsError'
}
export class InsufficientFundsError extends BaseError {
static nodeMessage = /insufficient funds/
static nodeMessage =
/insufficient funds|exceeds transaction sender account balance/
constructor({ cause }: { cause?: BaseError | undefined } = {}) {
super(
[
Expand Down
56 changes: 56 additions & 0 deletions src/linea/actions/estimateGas.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { expect, test } from 'vitest'

import { accounts } from '../../../test/src/constants.js'
import { createClient } from '../../clients/createClient.js'
import { http } from '../../clients/transports/http.js'
import { parseEther } from '../../utils/unit/parseEther.js'
import { lineaSepolia } from '../chains.js'
import { estimateGas } from './estimateGas.js'

const client = createClient({
chain: lineaSepolia,
transport: http(),
})

test('default', async () => {
const { baseFeePerGas, gasLimit, priorityFeePerGas } = await estimateGas(
client,
{
account: '0x0000000000000000000000000000000000000000',
to: '0x0000000000000000000000000000000000000000',
value: parseEther('0.0001'),
},
)
expect(baseFeePerGas).toBeGreaterThan(0n)
expect(gasLimit).toBe(21000n)
expect(priorityFeePerGas).toBeGreaterThan(0n)
})

test('error: insufficient balance', async () => {
await expect(() =>
estimateGas(client, {
account: accounts[0].address,
to: '0x0000000000000000000000000000000000000000',
value: parseEther('0.0001'),
}),
).rejects.toThrowErrorMatchingInlineSnapshot(`
[CallExecutionError: The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account.
This error could arise when the account does not have enough funds to:
- pay for the total gas fee,
- pay for the value to send.
The cost of the transaction is calculated as \`gas * gas fee + value\`, where:
- \`gas\` is the amount of gas needed for transaction to execute,
- \`gas fee\` is the gas fee,
- \`value\` is the amount of ether to send to the recipient.
Raw Call Arguments:
from: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
to: 0x0000000000000000000000000000000000000000
value: 0.0001 ETH
Details: transaction up-front cost 0x5af31cfe9880 exceeds transaction sender account balance 0x0
Version: viem@x.y.z]
`)
})
Loading

0 comments on commit 2e05c52

Please sign in to comment.