From 707023cb6b6d415c77ec841ab8934a14606d4799 Mon Sep 17 00:00:00 2001 From: Peter Anyaogu Date: Fri, 11 Oct 2024 20:41:19 +0100 Subject: [PATCH] fix gas fee errors --- CHANGELOG.md | 8 ++++ example/lib/providers/wallet_provider.dart | 51 ++++++---------------- example/lib/screens/home/home_widgets.dart | 1 - lib/src/4337/providers.dart | 44 +++++++------------ lib/src/4337/userop.dart | 8 ++-- lib/src/4337/wallet.dart | 18 +++----- lib/src/common/constants.dart | 2 +- lib/src/common/mixins.dart | 2 + lib/src/interfaces/interfaces.dart | 1 + lib/src/interfaces/json_rpc_provider.dart | 36 +++++---------- lib/src/interfaces/user_operations.dart | 5 +-- lib/variance_dart.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 3 +- 14 files changed, 69 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57161c8..6572704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.1.5 + +* improve gas fees estimation +* reduce copywith trigger in gas settings +* change position of custom gas overrides to post sponsor useroperation +* default to p256 precompile over contract verifiers. +* revert to direct balance checking + ## 0.1.4 * add surpport for web3_signers v0.1+ diff --git a/example/lib/providers/wallet_provider.dart b/example/lib/providers/wallet_provider.dart index cdc65f1..c20a7c7 100644 --- a/example/lib/providers/wallet_provider.dart +++ b/example/lib/providers/wallet_provider.dart @@ -23,8 +23,7 @@ class WalletProvider extends ChangeNotifier { EthereumAddress.fromHex("0xf5bb7f874d8e3f41821175c0aa9910d30d10e193"); final salt = Uint256.zero; - static const rpc = - "https://api.pimlico.io/v2/84532/rpc?apikey=pim_NuuL4a9tBdyfoogF5LtP5A"; + static const rpc = "https://api.pimlico.io/v2/84532/rpc?apikey=API_KEY"; WalletProvider() : _chain = Chains.getChain(Network.baseTestnet) @@ -67,8 +66,6 @@ class WalletProvider extends ChangeNotifier { Future createEOAWallet() async { final signer = EOAWallet.createWallet( WordLength.word_12, const SignatureOptions(prefix: [0])); - log("signer: ${signer.getAddress()}"); - final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer); try { @@ -87,14 +84,11 @@ class WalletProvider extends ChangeNotifier { final signer = PrivateKeySigner.create(privateKey, "123456", random, options: const SignatureOptions(prefix: [0])); - log("signer: ${signer.getAddress()}"); - log("pk: ${hexlify(privateKey.privateKey)}"); - final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer); try { _wallet = await walletFactory.createAlchemyLightAccount(salt); - log("pk wallet created ${_wallet?.address.hex} "); + log("wallet created ${_wallet?.address.hex} "); } catch (e) { _errorMessage = e.toString(); notifyListeners(); @@ -106,40 +100,26 @@ class WalletProvider extends ChangeNotifier { _chain.accountFactory = Constants.safeProxyFactoryAddress; final signer = EOAWallet.createWallet(); - log("signer: ${signer.getAddress()}"); - final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer); try { _wallet = await walletFactory.createSafeAccount(salt); - log("safe created ${_wallet?.address.hex} "); + log("wallet created ${_wallet?.address.hex} "); } catch (e) { log("something happened: $e"); } } Future mintNFt() async { - // pimlico requires us to get the gasfees from their bundler. - // that cannot be built into the sdk so we modify the internal fees manually - if (_chain.entrypoint.version == 0.7) { - _wallet?.gasSettings = GasSettings( - gasMultiplierPercentage: 5, - userDefinedMaxFeePerGas: BigInt.parse("0x524e1909"), - userDefinedMaxPriorityFeePerGas: BigInt.parse("0x52412100")); - } - // mints nft - log(DateTime.timestamp().toString()); + // simple tx final tx1 = await _wallet?.sendTransaction( nft, Contract.encodeFunctionCall("safeMint", nft, ContractAbis.get("ERC721_SafeMint"), [_wallet?.address])); await tx1?.wait(); - await sendBatchedTransaction(); - } - - Future sendBatchedTransaction() async { - final tx = await _wallet?.sendBatchedTransaction([ + // batch tx + final tx2 = await _wallet?.sendBatchedTransaction([ erc20, erc20 ], [ @@ -152,21 +132,18 @@ class WalletProvider extends ChangeNotifier { erc20, deployer, w3d.EtherAmount.fromInt(w3d.EtherUnit.ether, 20)) ]); - await tx?.wait(); + await tx2?.wait(); } Future sendTransaction(String recipient, String amount) async { - if (_wallet != null) { - final etherAmount = w3d.EtherAmount.fromBigInt(w3d.EtherUnit.wei, - BigInt.from(double.parse(amount) * math.pow(10, 18))); + final etherAmount = w3d.EtherAmount.fromBigInt(w3d.EtherUnit.wei, + BigInt.from(double.parse(amount) * math.pow(10, 18))); - final response = - await _wallet?.send(EthereumAddress.fromHex(recipient), etherAmount); - final receipt = await response?.wait(); + final response = await _wallet?.send( + EthereumAddress.fromHex("0xF5bB7F874D8e3f41821175c0Aa9910d30d10e193"), + etherAmount); + final receipt = await response?.wait(); - log("Transaction receipt Hash: ${receipt?.userOpHash}"); - } else { - log("No wallet available to send transaction"); - } + log("Transaction receipt Hash: ${receipt?.userOpHash}"); } } diff --git a/example/lib/screens/home/home_widgets.dart b/example/lib/screens/home/home_widgets.dart index 0e54fd8..79122be 100644 --- a/example/lib/screens/home/home_widgets.dart +++ b/example/lib/screens/home/home_widgets.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'dart:ui' as ui; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; diff --git a/lib/src/4337/providers.dart b/lib/src/4337/providers.dart index a9bbd7e..0e381b9 100644 --- a/lib/src/4337/providers.dart +++ b/lib/src/4337/providers.dart @@ -100,38 +100,26 @@ class JsonRPCProvider implements JsonRPCProviderBase { } @override - Future> getEip1559GasPrice() async { - final fee = await rpc.send("eth_maxPriorityFeePerGas"); - final tip = Uint256.fromHex(fee); - final mul = Uint256(BigInt.from(100 * 13)); - final buffer = tip / mul; - final maxPriorityFeePerGas = tip + buffer; - final maxFeePerGas = maxPriorityFeePerGas; - return { - 'maxFeePerGas': EtherAmount.fromBigInt(EtherUnit.wei, maxFeePerGas.value), - 'maxPriorityFeePerGas': - EtherAmount.fromBigInt(EtherUnit.wei, maxPriorityFeePerGas.value) - }; - } - - @override - Future> getGasPrice() async { + Future getGasPrice([GasEstimation rate = GasEstimation.normal]) async { try { - return await getEip1559GasPrice(); + final [low, medium, high] = await getGasInEIP1559(rpc.url); + switch (rate) { + case GasEstimation.low: + return low; + case GasEstimation.normal: + return medium; + case GasEstimation.high: + return high; + } } catch (e) { - final value = await getLegacyGasPrice(); - return { - 'maxFeePerGas': value, - 'maxPriorityFeePerGas': value, - }; + final data = await rpc.send('eth_gasPrice'); + final gasPrice = hexToInt(data); + return Fee( + maxPriorityFeePerGas: gasPrice, + maxFeePerGas: gasPrice, + estimatedGas: gasPrice); } } - - @override - Future getLegacyGasPrice() async { - final data = await rpc.send('eth_gasPrice'); - return EtherAmount.fromBigInt(EtherUnit.wei, hexToInt(data)); - } } class RPCBase extends JsonRPC { diff --git a/lib/src/4337/userop.dart b/lib/src/4337/userop.dart index c650b8b..a855a35 100644 --- a/lib/src/4337/userop.dart +++ b/lib/src/4337/userop.dart @@ -252,15 +252,13 @@ class UserOperation implements UserOperationBase { } @override - UserOperation updateOpGas( - UserOperationGas? opGas, Map? feePerGas) { + UserOperation updateOpGas([UserOperationGas? opGas, Fee? fee]) { return copyWith( callGasLimit: opGas?.callGasLimit, verificationGasLimit: opGas?.verificationGasLimit, preVerificationGas: opGas?.preVerificationGas, - maxFeePerGas: (feePerGas?["maxFeePerGas"] as EtherAmount?)?.getInWei, - maxPriorityFeePerGas: - (feePerGas?["maxPriorityFeePerGas"] as EtherAmount?)?.getInWei, + maxFeePerGas: fee?.maxFeePerGas, + maxPriorityFeePerGas: fee?.maxPriorityFeePerGas, ); } diff --git a/lib/src/4337/wallet.dart b/lib/src/4337/wallet.dart index 5360114..b29536b 100644 --- a/lib/src/4337/wallet.dart +++ b/lib/src/4337/wallet.dart @@ -158,6 +158,7 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { op = await plugin('paymaster').intercept(op); } + op = applyCustomGasSettings(op); // Validate the user operation op.validate(op.nonce > BigInt.zero, initCode); @@ -209,14 +210,11 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { .then((value) => Uint256(value[0])) .catchError((e) => throw NonceError(e.toString(), _walletAddress))); - /// Returns the balance for the Smart Wallet address from the entrypoint. + /// Returns the balance for the Smart Wallet address. /// /// If an error occurs during the balance retrieval process, a [FetchBalanceError] exception is thrown. Future _getBalance() => plugin("contract") - .read(_chain.entrypoint.address, ContractAbis.get('getBalance'), - "balanceOf", - params: [_walletAddress]) - .then((value) => EtherAmount.fromBigInt(EtherUnit.wei, value[0])) + .getBalance(_walletAddress) .catchError((e) => throw FetchBalanceError(e.toString(), _walletAddress)); /// Updates the user operation with the latest nonce and gas prices. @@ -234,23 +232,21 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { initCode: responses[0] > Uint256.zero ? Uint8List(0) : null, signature: dummySignature); - return _updateUserOperationGas(op, feePerGas: responses[1]); + return _updateUserOperationGas(op, responses[1]); }); /// Updates the gas information for the user operation. /// /// [op] is the user operation to update. - /// [feePerGas] is an optional map containing the gas prices. + /// [fee] is an optional Fee containing the gas prices. /// /// Returns a [Future] that resolves to the updated [UserOperation] object. /// /// If an error occurs during the gas estimation process, a [GasEstimationError] exception is thrown. - Future _updateUserOperationGas(UserOperation op, - {Map? feePerGas}) => + Future _updateUserOperationGas(UserOperation op, Fee fee) => plugin('bundler') .estimateUserOperationGas( op.toMap(_chain.entrypoint.version), _chain.entrypoint) - .then((opGas) => op.updateOpGas(opGas, feePerGas)) - .then((op) => applyCustomGasSettings(op)) + .then((opGas) => op.updateOpGas(opGas, fee)) .catchError((e) => throw GasEstimationError(e.toString(), op)); } diff --git a/lib/src/common/constants.dart b/lib/src/common/constants.dart index f68f892..c34bde7 100644 --- a/lib/src/common/constants.dart +++ b/lib/src/common/constants.dart @@ -28,7 +28,7 @@ class Constants { static final EthereumAddress safeMultiSendaddress = EthereumAddress.fromHex("0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526"); static final EthereumAddress p256VerifierAddress = - EthereumAddress.fromHex("0x445a0683e494ea0c5AF3E83c5159fBE47Cf9e765"); + EthereumAddress.fromHex("0x0000000000000000000000000000000000000100"); Constants._(); } diff --git a/lib/src/common/mixins.dart b/lib/src/common/mixins.dart index a7e833c..04fea23 100644 --- a/lib/src/common/mixins.dart +++ b/lib/src/common/mixins.dart @@ -51,6 +51,8 @@ mixin _GasSettings { UserOperation applyCustomGasSettings(UserOperation op) { final multiplier = _gasParams.gasMultiplierPercentage / 100 + 1; + if (multiplier == 1) return op; + return op.copyWith( callGasLimit: BigInt.from(op.callGasLimit.toDouble() * multiplier), verificationGasLimit: diff --git a/lib/src/interfaces/interfaces.dart b/lib/src/interfaces/interfaces.dart index 583bc8e..6717973 100644 --- a/lib/src/interfaces/interfaces.dart +++ b/lib/src/interfaces/interfaces.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import 'package:eip1559/eip1559.dart'; import 'package:web3_signers/web3_signers.dart' show PassKeyPair, Uint256; import 'package:web3dart/web3dart.dart'; diff --git a/lib/src/interfaces/json_rpc_provider.dart b/lib/src/interfaces/json_rpc_provider.dart index e7662f3..3267925 100644 --- a/lib/src/interfaces/json_rpc_provider.dart +++ b/lib/src/interfaces/json_rpc_provider.dart @@ -1,5 +1,15 @@ part of 'interfaces.dart'; +enum GasEstimation { + low(rate: 0), + normal(rate: 1), + high(rate: 2); + + final int rate; + + const GasEstimation({required this.rate}); +} + /// Abstract base class for interacting with an Bundler RPC provider. /// /// Implementations of this class are expected to provide functionality for specifically interacting @@ -59,18 +69,6 @@ abstract class JsonRPCProviderBase { bool isContainFullObj = true, }); - /// Asynchronously retrieves the EIP-1559 gas prices, including `maxFeePerGas` and `maxPriorityFeePerGas`. - /// - /// Returns: - /// A [Future] that completes with a [Map] containing the gas prices in [EtherAmount]. - /// - /// Example: - /// ```dart - /// var gasPrices = await getEip1559GasPrice(); - /// ``` - /// This method uses an ethereum jsonRPC to fetch EIP-1559 gas prices from the Ethereum node. - Future> getEip1559GasPrice(); - /// Asynchronously retrieves the gas prices, supporting both EIP-1559 and legacy gas models. /// /// Returns: @@ -81,17 +79,5 @@ abstract class JsonRPCProviderBase { /// var gasPrices = await getGasPrice(); /// ``` /// This method first attempts to fetch EIP-1559 gas prices and falls back to legacy gas prices if it fails. - Future> getGasPrice(); - - /// Asynchronously retrieves the legacy gas price from the Ethereum node. - /// - /// Returns: - /// A [Future] that completes with an [EtherAmount] representing the legacy gas price in [Wei]. - /// - /// Example: - /// ```dart - /// var legacyGasPrice = await getLegacyGasPrice(); - /// ``` - /// This method uses an ethereum jsonRPC to fetch the legacy gas price from the Ethereum node. - Future getLegacyGasPrice(); + Future getGasPrice([GasEstimation rate = GasEstimation.normal]); } diff --git a/lib/src/interfaces/user_operations.dart b/lib/src/interfaces/user_operations.dart index f205328..0f5b522 100644 --- a/lib/src/interfaces/user_operations.dart +++ b/lib/src/interfaces/user_operations.dart @@ -71,7 +71,7 @@ abstract class UserOperationBase { /// /// Parameters: /// - `opGas`: Optional parameter of type [UserOperationGas] for specifying gas-related information. - /// - `feePerGas`: Optional parameter of type [Map] for specifying maxFeePerGas and maxPriorityFeePerGas. + /// - `fee`: Optional parameter of type [Fee] for specifying maxFeePerGas and maxPriorityFeePerGas. /// /// Returns: /// A [UserOperation] instance created from the provided map. @@ -85,8 +85,7 @@ abstract class UserOperationBase { /// // Other parameters can be updated as needed. /// ); /// ``` - UserOperation updateOpGas( - UserOperationGas? opGas, Map? feePerGas); + UserOperation updateOpGas([UserOperationGas? opGas, Fee? fee]); /// Validates the user operation fields for accuracy /// diff --git a/lib/variance_dart.dart b/lib/variance_dart.dart index 55598df..499f355 100644 --- a/lib/variance_dart.dart +++ b/lib/variance_dart.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; +import 'package:eip1559/eip1559.dart'; import 'package:http/http.dart' as http; import 'package:web3_signers/web3_signers.dart'; import 'package:web3dart/crypto.dart'; @@ -13,7 +14,6 @@ import 'package:web3dart/web3dart.dart'; import 'src/abis/abis.dart'; import 'src/interfaces/interfaces.dart'; -export 'package:web3_signers/web3_signers.dart' show Logger; export 'src/abis/abis.dart' show ContractAbis; part 'src/4337/chains.dart'; diff --git a/pubspec.lock b/pubspec.lock index 310ef24..09cce85 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -178,7 +178,7 @@ packages: source: hosted version: "2.3.6" eip1559: - dependency: transitive + dependency: "direct main" description: name: eip1559 sha256: c2b81ac85f3e0e71aaf558201dd9a4600f051ece7ebacd0c5d70065c9b458004 diff --git a/pubspec.yaml b/pubspec.yaml index 2883632..c455f1e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: variance_dart description: An Account Abstraction (4337) Development kit, for quickly building mobile web3 apps and smart wallets. -version: 0.1.4 +version: 0.1.5 documentation: https://docs.variance.space homepage: https://variance.space repository: https://github.com/vaariance/variance-dart @@ -19,6 +19,7 @@ dependencies: web3dart: ^2.7.3 http: ^1.2.0 web3_signers: ^0.1.6 + eip1559: ^0.6.2 dev_dependencies: web3dart_builders: ^0.1.2