diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e66c3c..ab394b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## 0.1.0-r2 + +* Fix safe transaction encoding +* Remove _checkDeployment function in counterfactual creation +* Add getBlockInformation in JsonRPCProvider + +## 0.1.0-r1 + +* Mainnet Pre-release +* refactor sdk to use the factory method for creating smart-accounts +* add safe smart accounts via safe plugin +* reduce external dependencies to 3 +* implement custom errors and add logger for debugging +* update contract abis, adding more erc20/erc721 abi snippets +* fix paymaster plugin context incompatibility +* add utility for packing and unpacking uint256 values +* update chain configuration to surpport minimal modest chains +* update example to a real flutter example +* rename library name from variance to variance_dart for consistency +* update API refs and README to reflect new changes + ## 0.0.9 * Add support for entrypoint v0.7 in parrallel. diff --git a/README.md b/README.md index 7cd7d2a..27ddb28 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,11 @@ Variance is a Dart SDK designed to simplify interaction with Ethereum-based bloc open your terminal and run the following command: ```sh -flutter pub get variance_dart -flutter pub get web3_signers +flutter pub add variance_dart +flutter pub add web3_signers + +# optionally +flutter pub add web3dart ``` ### Usage @@ -26,7 +29,7 @@ flutter pub get web3_signers ```dart // Import the package import 'package:web3_signers/web3_signers.dart'; -import 'package:variance_dart/variance.dart'; +import 'package:variance_dart/variance_dart.dart'; // optionally import 'package:web3dart/web3dart.dart'; @@ -56,11 +59,11 @@ chain.entrypoint = entrypointAddress; Also if wish to use paymasters with your smart wallet you can do so by specifying the endpoint of the paymaster. By default the paymaster is set to null. This would add a paymaster Plugin to the smart wallet. ```dart -final String paymasterUrl = 'https://pimlico.io/...'; +final String paymasterUrl = 'https://api.pimlico.io/v2/84532/rpc?apikey=...'; chain.paymasterUrl = paymasterUrl; ``` -If you have additional context for the paymaster, you will be able to add it to the smart wallet. +If you have additional context for the paymaster, you will be able to add it to the smart wallet after creation or before initiating a transaction. ```dart wallet.plugin('paymaster').context = {'key': 'value'}; @@ -153,7 +156,7 @@ await wallet.send( ); ``` -For detailed usage and examples, refer to the [documentation](https://docs.variance.space). Additional refer to the [demo](https://github.com/vaariance/variancedemo) for use in a flutter app. +For detailed usage and examples, refer to the [documentation](https://docs.variance.space). Additional refer to the [example](./example/) for use in a flutter app. ## API Reference diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index bc1d45b..64e1869 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5d..87131a0 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ _errorMessage; + final EthereumAddress nft = + EthereumAddress.fromHex("0x4B509a7e891Dc8fd45491811d67a8B9e7ef547B9"); + final EthereumAddress erc20 = + EthereumAddress.fromHex("0xAEaF19097D8a8da728438D6B57edd9Bc5DAc4795"); + final EthereumAddress deployer = + EthereumAddress.fromHex("0x218F6Bbc32Ef28F547A67c70AbCF8c2ea3b468BA"); + WalletProvider() : _chain = Chains.getChain(Network.baseTestnet) ..accountFactory = EthereumAddress.fromHex( "0x402A266e92993EbF04a5B3fd6F0e2b21bFC83070") - ..bundlerUrl = - "https://base-sepolia.g.alchemy.com/v2/RWbMhXe00ZY-SjGQF72kyCVQJ_nQopba" - ..jsonRpcUrl = - "https://base-sepolia.g.alchemy.com/v2/RWbMhXe00ZY-SjGQF72kyCVQJ_nQopba"; + ..bundlerUrl = "https://api.pimlico.io/v2/84532/rpc?apikey=" + ..paymasterUrl = "https://paymaster.optimism.io/v1/84532/rpc"; Future registerWithPassKey(String name, {bool? requiresUserVerification}) async { @@ -33,19 +38,20 @@ class WalletProvider extends ChangeNotifier { PassKeySigner("webauthn.io", "webauthn", "https://webauthn.io"); final hwdSigner = HardwareSigner.withTag(name); - final SmartWalletFactory walletFactory = - SmartWalletFactory(_chain, pkpSigner); - final salt = Uint256.fromHex( hexlify(w3d.keccak256(Uint8List.fromList(utf8.encode(name))))); try { // uses passkeys on android, secure enclave on iOS if (Platform.isAndroid) { + final SmartWalletFactory walletFactory = + SmartWalletFactory(_chain, pkpSigner); final keypair = await pkpSigner.register(name, name); _wallet = await walletFactory.createP256Account(keypair, salt); } else if (Platform.isIOS) { + final SmartWalletFactory walletFactory = + SmartWalletFactory(_chain, hwdSigner); final keypair = await hwdSigner.generateKeyPair(); _wallet = await walletFactory.createP256Account( keypair, salt); @@ -59,6 +65,49 @@ class WalletProvider extends ChangeNotifier { } } + Future createEOAWallet() async { + _chain.accountFactory = Constants.simpleAccountFactoryAddress; + + final signer = EOAWallet.createWallet(); + log("signer: ${signer.getAddress()}"); + + final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer); + final salt = Uint256.fromHex(hexlify(w3d + .keccak256(EthereumAddress.fromHex(signer.getAddress()).addressBytes))); + + try { + _wallet = await walletFactory.createSimpleAccount(salt); + log("wallet created ${_wallet?.address.hex} "); + } catch (e) { + _errorMessage = e.toString(); + notifyListeners(); + log("something happened: $e"); + } + } + + Future createPrivateKeyWallet() async { + _chain.accountFactory = Constants.simpleAccountFactoryAddress; + + final signer = PrivateKeySigner.createRandom("123456"); + log("signer: ${signer.getAddress()}"); + + final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer); + + final salt = Uint256.fromHex(hexlify(w3d + .keccak256(EthereumAddress.fromHex(signer.getAddress()).addressBytes))); + + log("salt: ${salt.toHex()}"); + + try { + _wallet = await walletFactory.createSimpleAccount(salt); + log("wallet created ${_wallet?.address.hex} "); + } catch (e) { + _errorMessage = e.toString(); + notifyListeners(); + log("something happened: $e"); + } + } + Future createSafeWallet() async { _chain.accountFactory = Constants.safeProxyFactoryAddress; @@ -80,12 +129,56 @@ class WalletProvider extends ChangeNotifier { } } - Future mintNFt() async {} + Future mintNFt() async { + // mints nft + final tx1 = await _wallet?.sendTransaction( + nft, + Contract.encodeFunctionCall("safeMint", nft, + ContractAbis.get("ERC721_SafeMint"), [_wallet?.address])); + await tx1?.wait(); + + // mints erc20 tokens + final tx2 = await _wallet?.sendTransaction( + erc20, + Contract.encodeFunctionCall( + "mint", erc20, ContractAbis.get("ERC20_Mint"), [ + _wallet?.address, + w3d.EtherAmount.fromInt(w3d.EtherUnit.ether, 20).getInWei + ])); + await tx2?.wait(); + + // transfers the tokens + final tx3 = await _wallet?.sendTransaction( + erc20, + Contract.encodeERC20TransferCall( + erc20, deployer, w3d.EtherAmount.fromInt(w3d.EtherUnit.ether, 18))); + await tx3?.wait(); + log("trying batched transaction"); + await sendBatchedTransaction(); + } + + Future sendBatchedTransaction() async { + final tx = await _wallet?.sendBatchedTransaction([ + erc20, + erc20 + ], [ + Contract.encodeFunctionCall( + "mint", erc20, ContractAbis.get("ERC20_Mint"), [ + _wallet?.address, + w3d.EtherAmount.fromInt(w3d.EtherUnit.ether, 20).getInWei + ]), + Contract.encodeERC20TransferCall( + erc20, deployer, w3d.EtherAmount.fromInt(w3d.EtherUnit.ether, 20)) + ]); + + await tx?.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 response = await _wallet?.send(EthereumAddress.fromHex(recipient), etherAmount); final receipt = await response?.wait(); diff --git a/example/lib/screens/home/home_screen.dart b/example/lib/screens/home/home_screen.dart index 7f34217..1ddac2f 100644 --- a/example/lib/screens/home/home_screen.dart +++ b/example/lib/screens/home/home_screen.dart @@ -46,7 +46,9 @@ class _WalletHomeState extends State { label: const Text(' Receive')), 50.horizontalSpace, TextButton.icon( - onPressed: () {}, + onPressed: () { + context.read().mintNFt(); + }, style: TextButton.styleFrom( backgroundColor: const Color(0xffE1FF01)), icon: const Icon( diff --git a/example/pubspec.lock b/example/pubspec.lock index 751e951..128a764 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -364,18 +364,18 @@ packages: dependency: transitive description: name: passkeys - sha256: "79f07498b44d8372a569904d5e3e1de238d83abcf83b79d583a06394b98d2789" + sha256: "59e50b21746aff90cbc56145174caa3b99523f449e42f7d8aa2199ec09c511cd" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" passkeys_android: dependency: transitive description: name: passkeys_android - sha256: ab245d18d88040409d3aa93c3359a4c10c569894361c56929cb367d4b892bbaf + sha256: "9dc0b84dad03329ff2f3be18bedecf1b8de9309c8e9cda6ef821dc88556a126d" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" passkeys_ios: dependency: transitive description: @@ -629,14 +629,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - string_validator: - dependency: transitive - description: - name: string_validator - sha256: "54d4f42cd6878ae72793a58a529d9a18ebfdfbfebd9793bbe55c9b28935e8543" - url: "https://pub.dev" - source: hosted - version: "1.0.2" term_glyph: dependency: transitive description: @@ -691,7 +683,7 @@ packages: path: ".." relative: true source: path - version: "0.0.9" + version: "0.1.0-r1" vector_math: dependency: transitive description: @@ -720,10 +712,10 @@ packages: dependency: "direct main" description: name: web3_signers - sha256: "7dc7f83d2eba5e78eb0310fcdf0cb4c0b167c27abafc86c8027383913dd64488" + sha256: fd2a4ee394537f2140c08a395eadd8611aa713e04699c29b6aaba75e11264faf url: "https://pub.dev" source: hosted - version: "0.0.6-r2" + version: "0.0.6" web3dart: dependency: "direct main" description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b660c99..03b61bb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -20,10 +20,10 @@ dependencies: web3dart: ^2.7.2 shared_preferences: ^2.2.2 path_provider: ^2.1.1 - web3_signers: ^0.0.6-r2 fluttertoast: ^8.2.4 variance_dart: path: ../ + web3_signers: ^0.0.6 dev_dependencies: flutter_test: diff --git a/lib/src/4337/chains.dart b/lib/src/4337/chains.dart index c141c61..2c9ef66 100644 --- a/lib/src/4337/chains.dart +++ b/lib/src/4337/chains.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// Represents an Ethereum-based blockchain chain. class Chain { diff --git a/lib/src/4337/factory.dart b/lib/src/4337/factory.dart index 32f4e25..f17beff 100644 --- a/lib/src/4337/factory.dart +++ b/lib/src/4337/factory.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A factory class for creating various types of Ethereum smart wallets. /// {@inheritDoc SmartWalletFactoryBase} @@ -31,6 +31,13 @@ class SmartWalletFactory implements SmartWalletFactoryBase { chainId: _chain.chainId, rpc: _jsonRpc.rpc); + /// A getter for the SafePlugin instance. + _SafePlugin get _safePlugin => _SafePlugin( + address: + Safe4337ModuleAddress.fromVersion(_chain.entrypoint.version).address, + chainId: _chain.chainId, + client: _safeProxyFactory.client); + /// A getter for the SafeProxyFactory contract instance. _SafeProxyFactory get _safeProxyFactory => _SafeProxyFactory( address: _chain.accountFactory!, @@ -43,13 +50,6 @@ class SmartWalletFactory implements SmartWalletFactoryBase { chainId: _chain.chainId, rpc: _jsonRpc.rpc); - /// A getter for the SafePlugin instance. - _SafePlugin get _safePlugin => _SafePlugin( - address: - Safe4337ModuleAddress.fromVersion(_chain.entrypoint.version).address, - chainId: _chain.chainId, - client: _safeProxyFactory.client); - @override Future createP256Account(T keyPair, Uint256 salt, [EthereumAddress? recoveryAddress]) { @@ -67,15 +67,11 @@ class SmartWalletFactory implements SmartWalletFactoryBase { } @override - Future createSafeAccount(Uint256 salt, - [List? owners, int? threshold]) async { + Future createSafeAccount(Uint256 salt) async { final signer = EthereumAddress.fromHex(_signer.getAddress()); - final ownerSet = owners != null ? {signer, ...owners} : [signer]; // Get the initializer data for the Safe account - final initializer = _safeProxyFactory.getInitializer( - ownerSet, - threshold ?? 1, + final initializer = _safeProxyFactory.getInitializer([signer], 1, Safe4337ModuleAddress.fromVersion(_chain.entrypoint.version)); // Get the proxy creation code for the Safe account diff --git a/lib/src/4337/paymaster.dart b/lib/src/4337/paymaster.dart index 031de41..f5cbe84 100644 --- a/lib/src/4337/paymaster.dart +++ b/lib/src/4337/paymaster.dart @@ -1,27 +1,4 @@ -part of '../../variance.dart'; - -class PaymasterResponse { - final Uint8List paymasterAndData; - final BigInt preVerificationGas; - final BigInt verificationGasLimit; - final BigInt callGasLimit; - - PaymasterResponse({ - required this.paymasterAndData, - required this.preVerificationGas, - required this.verificationGasLimit, - required this.callGasLimit, - }); - - factory PaymasterResponse.fromMap(Map map) { - return PaymasterResponse( - paymasterAndData: hexToBytes(map['paymasterAndData']), - preVerificationGas: BigInt.parse(map['preVerificationGas']), - verificationGasLimit: BigInt.parse(map['verificationGasLimit']), - callGasLimit: BigInt.parse(map['callGasLimit']), - ); - } -} +part of '../../variance_dart.dart'; /// Represents a Paymaster contract for sponsoring user operations. class Paymaster implements PaymasterBase { @@ -34,11 +11,6 @@ class Paymaster implements PaymasterBase { /// information to the Paymaster when sponsoring user operations. Map? _context; - @override - set context(Map? context) { - _context = context; - } - /// Creates a new instance of the [Paymaster] class. /// /// [_chain] is the Ethereum chain configuration. @@ -47,10 +19,15 @@ class Paymaster implements PaymasterBase { /// Throws an [InvalidPaymasterUrl] exception if the paymaster URL in the /// provided chain configuration is not a valid URL. Paymaster(this._chain, [this._context]) - : assert(isURL(_chain.paymasterUrl), + : assert(_chain.paymasterUrl.isURL(), InvalidPaymasterUrl(_chain.paymasterUrl)), _rpc = RPCBase(_chain.paymasterUrl!); + @override + set context(Map? context) { + _context = context; + } + @override Future intercept(UserOperation operation) async { final paymasterResponse = await sponsorUserOperation( @@ -62,16 +39,56 @@ class Paymaster implements PaymasterBase { preVerificationGas: paymasterResponse.preVerificationGas, verificationGasLimit: paymasterResponse.verificationGasLimit, callGasLimit: paymasterResponse.callGasLimit, + maxFeePerGas: paymasterResponse.maxFeePerGas ?? operation.maxFeePerGas, + maxPriorityFeePerGas: paymasterResponse.maxPriorityFeePerGas ?? + operation.maxPriorityFeePerGas, ); } @override Future sponsorUserOperation(Map userOp, EntryPointAddress entrypoint, Map? context) async { + final request = [userOp, entrypoint.address.hex]; + if (context != null) { + request.add(context); + } final response = await _rpc.send>( - 'pm_sponsorUserOperation', [userOp, entrypoint.address.hex, context]); + 'pm_sponsorUserOperation', request); // Parse the response into a PaymasterResponse object return PaymasterResponse.fromMap(response); } } + +class PaymasterResponse { + final Uint8List paymasterAndData; + final BigInt preVerificationGas; + final BigInt verificationGasLimit; + final BigInt callGasLimit; + final BigInt? maxFeePerGas; + final BigInt? maxPriorityFeePerGas; + + PaymasterResponse({ + required this.paymasterAndData, + required this.preVerificationGas, + required this.verificationGasLimit, + required this.callGasLimit, + this.maxFeePerGas, + this.maxPriorityFeePerGas, + }); + + factory PaymasterResponse.fromMap(Map map) { + return PaymasterResponse( + paymasterAndData: hexToBytes(map['paymasterAndData']), + preVerificationGas: BigInt.parse(map['preVerificationGas']), + verificationGasLimit: BigInt.parse(map['verificationGasLimit']), + callGasLimit: BigInt.parse(map['callGasLimit']), + maxFeePerGas: map['maxFeePerGas'] != null + ? BigInt.parse(map['maxFeePerGas']) + : null, + maxPriorityFeePerGas: map['maxPriorityFeePerGas'] != null + ? BigInt.parse(map['maxPriorityFeePerGas']) + : null, + ); + } +} diff --git a/lib/src/4337/providers.dart b/lib/src/4337/providers.dart index ed0f40f..29b1153 100644 --- a/lib/src/4337/providers.dart +++ b/lib/src/4337/providers.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A class that implements the `BundlerProviderBase` interface and provides methods /// for interacting with a bundler for sending and tracking user operations on @@ -7,6 +7,9 @@ class BundlerProvider implements BundlerProviderBase { /// The remote procedure call (RPC) client used to communicate with the bundler. final RPCBase rpc; + /// A flag indicating whether the initialization process was successful. + late final bool _initialized; + /// Creates a new instance of the BundlerProvider class. /// /// [chain] is an object representing the blockchain chain configuration. @@ -16,7 +19,7 @@ class BundlerProvider implements BundlerProviderBase { /// retrieve the chain ID and verifies that it matches the expected chain ID. /// If the chain IDs don't match, the _initialized flag is set to false. BundlerProvider(Chain chain) - : assert(isURL(chain.bundlerUrl), InvalidBundlerUrl(chain.bundlerUrl)), + : assert(chain.bundlerUrl.isURL(), InvalidBundlerUrl(chain.bundlerUrl)), rpc = RPCBase(chain.bundlerUrl!) { rpc .send('eth_chainId') @@ -25,9 +28,6 @@ class BundlerProvider implements BundlerProviderBase { .then((value) => _initialized = value); } - /// A flag indicating whether the initialization process was successful. - late final bool _initialized; - @override Future estimateUserOperationGas( Map userOp, EntryPointAddress entrypoint) async { @@ -87,7 +87,7 @@ class JsonRPCProvider implements JsonRPCProviderBase { /// The constructor checks if the JSON-RPC URL is a valid URL and initializes /// the RPC client with the JSON-RPC URL. JsonRPCProvider(Chain chain) - : assert(isURL(chain.jsonRpcUrl), InvalidJsonRpcUrl(chain.jsonRpcUrl)), + : assert(chain.jsonRpcUrl.isURL(), InvalidJsonRpcUrl(chain.jsonRpcUrl)), rpc = RPCBase(chain.jsonRpcUrl!); @override @@ -105,6 +105,17 @@ class JsonRPCProvider implements JsonRPCProviderBase { .then((value) => value.toInt()); } + @override + Future getBlockInformation({ + String blockNumber = 'latest', + bool isContainFullObj = true, + }) { + return rpc.send>( + 'eth_getBlockByNumber', + [blockNumber, isContainFullObj], + ).then((json) => BlockInformation.fromJson(json)); + } + @override Future> getEip1559GasPrice() async { final fee = await rpc.send("eth_maxPriorityFeePerGas"); diff --git a/lib/src/4337/safe.dart b/lib/src/4337/safe.dart index 95d4c4f..7f024ca 100644 --- a/lib/src/4337/safe.dart +++ b/lib/src/4337/safe.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A class that extends the Safe4337Module and implements the Safe4337ModuleBase interface. /// It provides functionality related to Safe accounts and user operations on an Ethereum-like blockchain. @@ -14,14 +14,43 @@ class _SafePlugin extends Safe4337Module implements Safe4337ModuleBase { required super.client, }); + /// Encodes the signature of a user operation with a validity period. + /// + /// [signature] is the signature of the user operation. + /// [blockInfo] is the current blockInformation including the timestamp and baseFee. + /// + /// Returns a HexString representing the encoded signature with a validity period. + String getSafeSignature(String signature, BlockInformation blockInfo) { + final timestamp = blockInfo.timestamp.millisecondsSinceEpoch ~/ 1000; + + String validAfter = (timestamp - 3600).toRadixString(16); + validAfter = '0' * (12 - validAfter.length) + validAfter; + + String validUntil = (timestamp + 3600).toRadixString(16); + validUntil = '0' * (12 - validUntil.length) + validUntil; + + int v = int.parse(signature.substring(130, 132), radix: 16); + + if (v >= 27 && v <= 30) { + v += 4; + } + + String modifiedV = v.toRadixString(16); + if (modifiedV.length == 1) { + modifiedV = '0$modifiedV'; + } + + return '0x$validAfter$validUntil${signature.substring(2, 130)}$modifiedV'; + } + /// Computes the hash of a Safe UserOperation. /// /// [op] is an object representing the user operation details. - /// [currentTimestamp] is the current timestamp in seconds. + /// [blockInfo] is the current timestamp in seconds. /// /// Returns a Future that resolves to the hash of the user operation as a Uint8List. - Future getUserOperationHash( - UserOperation op, int currentTimestamp) async => + Future getSafeOperationHash( + UserOperation op, BlockInformation blockInfo) async => getOperationHash([ op.sender, op.nonce, @@ -33,22 +62,6 @@ class _SafePlugin extends Safe4337Module implements Safe4337ModuleBase { op.maxFeePerGas, op.maxPriorityFeePerGas, op.paymasterAndData, - hexToBytes(getEncodedSignature(op.signature, currentTimestamp)) + hexToBytes(getSafeSignature(op.signature, blockInfo)) ]); - - /// Encodes the signature of a user operation with a validity period. - /// - /// [signature] is the signature of the user operation. - /// [currentTimestamp] is the current timestamp in seconds. - /// - /// Returns a HexString representing the encoded signature with a validity period. - String getEncodedSignature(String signature, int currentTimestamp) { - String validAfter = currentTimestamp.toRadixString(16); - validAfter = '0' * (12 - validAfter.length) + validAfter; - - String validUntil = (currentTimestamp + 3600).toRadixString(16); - validUntil = '0' * (12 - validUntil.length) + validUntil; - - return '0x$validAfter$validUntil${signature.substring(2)}'; - } } diff --git a/lib/src/4337/userop.dart b/lib/src/4337/userop.dart index 72fa654..1bf2ab8 100644 --- a/lib/src/4337/userop.dart +++ b/lib/src/4337/userop.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A class that implements the user operation struct defined in EIP4337. class UserOperation implements UserOperationBase { @@ -357,22 +357,23 @@ class UserOperationResponse { RangeError.value( timeout.inSeconds, "timeout", "timeout must be > pollInterval")); - return await Isolate.run(() async { - Duration count = Duration.zero; + Duration count = Duration.zero; - while (count < timeout) { - await Future.delayed(pollInterval); + while (count < timeout) { + await Future.delayed(pollInterval); + try { final receipt = await _callback(userOpHash); if (receipt != null) { return receipt; } - + count += pollInterval; + } catch (e) { count += pollInterval; } + } - throw TimeoutException( - "can't find useroperation with hash $userOpHash", timeout); - }); + throw TimeoutException( + "can't find useroperation with hash $userOpHash", timeout); } } diff --git a/lib/src/4337/wallet.dart b/lib/src/4337/wallet.dart index affb7e1..1333b73 100644 --- a/lib/src/4337/wallet.dart +++ b/lib/src/4337/wallet.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A class that represents a Smart Wallet on an Ethereum-like blockchain. /// @@ -154,12 +154,12 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { Future signUserOperation(UserOperation op, {int? index}) async { final isSafe = hasPlugin('safe'); - final currentTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; + final blockInfo = + await plugin('jsonRpc').getBlockInformation(); // Calculate the operation hash final opHash = isSafe - ? await plugin<_SafePlugin>('safe') - .getUserOperationHash(op, currentTimestamp) + ? await plugin<_SafePlugin>('safe').getSafeOperationHash(op, blockInfo) : op.hash(_chain); // Sign the operation hash using the 'signer' plugin @@ -169,8 +169,7 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { // Append the signature validity period if the 'safe' plugin is enabled op.signature = isSafe - ? plugin<_SafePlugin>('safe') - .getEncodedSignature(signatureHex, currentTimestamp) + ? plugin<_SafePlugin>('safe').getSafeSignature(signatureHex, blockInfo) : signatureHex; return op; @@ -203,7 +202,7 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase { ]).then((responses) { op = op.copyWith( nonce: op.nonce > BigInt.zero ? op.nonce : responses[0].value, - initCode: responses[0].value > BigInt.zero ? Uint8List(0) : null, + initCode: responses[0] > Uint256.zero ? Uint8List(0) : null, signature: dummySignature); return _updateUserOperationGas(op, feePerGas: responses[1]); }); diff --git a/lib/src/abis/contract_abis.dart b/lib/src/abis/contract_abis.dart index db9e08f..022f519 100644 --- a/lib/src/abis/contract_abis.dart +++ b/lib/src/abis/contract_abis.dart @@ -46,6 +46,10 @@ class ContractAbis { abi = '[{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"}]'; break; + case 'ERC721_SafeMint': + abi = + '[{"type":"function","name":"safeMint","inputs":[{"name":"to","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"}]'; + break; case 'ERC721_SafeTransferFrom': abi = '[{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]'; diff --git a/lib/src/common/contract.dart b/lib/src/common/contract.dart index 5fe0854..85e7bec 100644 --- a/lib/src/common/contract.dart +++ b/lib/src/common/contract.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A wrapper for interacting with deployed Ethereum contracts through [JsonRPCProvider]. class Contract { @@ -9,47 +9,6 @@ class Contract { this.rpc, ); - /// Asynchronously calls a function on a smart contract with the provided parameters. - /// - /// Parameters: - /// - `contractAddress`: The [EthereumAddress] of the smart contract. - /// - `abi`: The [ContractAbi] representing the smart contract's ABI. - /// - `methodName`: The name of the method to call on the smart contract. - /// - `params`: Optional parameters for the function call. - /// - `sender`: The [EthereumAddress] of the sender, if applicable. - /// - /// Returns: - /// A [Future] that completes with a list of dynamic values representing the result of the function call. - /// - /// Example: - /// ```dart - /// var result = await read( - /// EthereumAddress.fromHex('0x9876543210abcdef9876543210abcdef98765432'), - /// myErc20ContractAbi, - /// 'balanceOf', - /// params: [ EthereumAddress.fromHex('0x9876543210abcdef9876543210abcdef98765432')], - /// ); - /// ``` - /// This method uses the an Ethereum jsonRPC to `staticcall` a function on the specified smart contract. - /// **Note:** This method does not support contract calls with state changes. - Future> read( - EthereumAddress contractAddress, ContractAbi abi, String methodName, - {List? params, EthereumAddress? sender}) { - final function = getContractFunction(methodName, contractAddress, abi); - final calldata = { - 'to': contractAddress.hex, - 'data': params != null - ? bytesToHex(function.encodeCall(params), - include0x: true, padToEvenLength: true) - : "0x", - if (sender != null) 'from': sender.hex, - }; - return rpc.send('eth_call', [ - calldata, - BlockNum.current().toBlockParam() - ]).then((value) => function.decodeReturnValues(value)); - } - /// Asynchronously checks whether a smart contract is deployed at the specified address. /// /// Parameters: @@ -107,6 +66,47 @@ class Contract { .then((value) => EtherAmount.fromBigInt(EtherUnit.wei, value)); } + /// Asynchronously calls a function on a smart contract with the provided parameters. + /// + /// Parameters: + /// - `contractAddress`: The [EthereumAddress] of the smart contract. + /// - `abi`: The [ContractAbi] representing the smart contract's ABI. + /// - `methodName`: The name of the method to call on the smart contract. + /// - `params`: Optional parameters for the function call. + /// - `sender`: The [EthereumAddress] of the sender, if applicable. + /// + /// Returns: + /// A [Future] that completes with a list of dynamic values representing the result of the function call. + /// + /// Example: + /// ```dart + /// var result = await read( + /// EthereumAddress.fromHex('0x9876543210abcdef9876543210abcdef98765432'), + /// myErc20ContractAbi, + /// 'balanceOf', + /// params: [ EthereumAddress.fromHex('0x9876543210abcdef9876543210abcdef98765432')], + /// ); + /// ``` + /// This method uses the an Ethereum jsonRPC to `staticcall` a function on the specified smart contract. + /// **Note:** This method does not support contract calls with state changes. + Future> read( + EthereumAddress contractAddress, ContractAbi abi, String methodName, + {List? params, EthereumAddress? sender}) { + final function = getContractFunction(methodName, contractAddress, abi); + final calldata = { + 'to': contractAddress.hex, + 'data': params != null + ? bytesToHex(function.encodeCall(params), + include0x: true, padToEvenLength: true) + : "0x", + if (sender != null) 'from': sender.hex, + }; + return rpc.send('eth_call', [ + calldata, + BlockNum.current().toBlockParam() + ]).then((value) => function.decodeReturnValues(value)); + } + /// Encodes an ERC-20 token approval function call. /// /// Parameters: diff --git a/lib/src/common/factories.dart b/lib/src/common/factories.dart index bf397ad..bce3614 100644 --- a/lib/src/common/factories.dart +++ b/lib/src/common/factories.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// A class that extends [P256AccountFactory] and implements [P256AccountFactoryBase]. /// It creates an instance of [P256AccountFactory] with a custom [RPCBase] client. diff --git a/lib/src/common/logger.dart b/lib/src/common/logger.dart index f8df5db..8659048 100644 --- a/lib/src/common/logger.dart +++ b/lib/src/common/logger.dart @@ -11,20 +11,17 @@ class Logger { /// The ANSI escape code to reset the color. static final _resetColor = '\x1B[0m'; - /// Logs a warning message. - /// - /// [message] is the warning message to be logged. - static void warning(String message) { - _logMessage('WARNING', _warningColor, message); - } - - /// Logs an error message. + /// Logs an error message if a condition is met. /// - /// [message] is the error message to be logged. + /// [condition] is the condition to check. + /// [message] is the error message to be logged if the condition is true. /// [error] is an optional error object associated with the error message. /// [stackTrace] is an optional stack trace associated with the error message. - static void error(String message, [Object? error, StackTrace? stackTrace]) { - _logError('ERROR', _errorColor, message, error, stackTrace); + static void conditionalError(bool condition, String message, + [Object? error, StackTrace? stackTrace]) { + if (condition) { + _logError('ERROR', _errorColor, message, error, stackTrace); + } } /// Logs a warning message if a condition is met. @@ -37,26 +34,38 @@ class Logger { } } - /// Logs an error message if a condition is met. + /// Logs an error message. /// - /// [condition] is the condition to check. - /// [message] is the error message to be logged if the condition is true. + /// [message] is the error message to be logged. /// [error] is an optional error object associated with the error message. /// [stackTrace] is an optional stack trace associated with the error message. - static void conditionalError(bool condition, String message, - [Object? error, StackTrace? stackTrace]) { - if (condition) { - _logError('ERROR', _errorColor, message, error, stackTrace); - } + static void error(String message, [Object? error, StackTrace? stackTrace]) { + _logError('ERROR', _errorColor, message, error, stackTrace); } - /// Logs a message with the specified level and color. + /// Logs a warning message. + /// + /// [message] is the warning message to be logged. + static void warning(String message) { + _logMessage('WARNING', _warningColor, message); + } + + /// Logs a message with the specified level, color, and timestamp. /// /// [level] is the log level (e.g., WARNING, ERROR). /// [color] is the ANSI escape code for the color. /// [message] is the message to be logged. - static void _logMessage(String level, String color, String message) { - _log(level, color, message); + static void _log(String level, String color, String message) { + final now = DateTime.now(); + final formattedTime = '${now.year.toString().padLeft(4, '0')}-' + '${now.month.toString().padLeft(2, '0')}-' + '${now.day.toString().padLeft(2, '0')} ' + '${now.hour.toString().padLeft(2, '0')}:' + '${now.minute.toString().padLeft(2, '0')}:' + '${now.second.toString().padLeft(2, '0')}'; + + final logMessage = '$formattedTime [$color$level$_resetColor] $message'; + log(logMessage); } /// Logs an error message with additional error and stack trace information. @@ -78,21 +87,12 @@ class Logger { _log(level, color, errorMessage); } - /// Logs a message with the specified level, color, and timestamp. + /// Logs a message with the specified level and color. /// /// [level] is the log level (e.g., WARNING, ERROR). /// [color] is the ANSI escape code for the color. /// [message] is the message to be logged. - static void _log(String level, String color, String message) { - final now = DateTime.now(); - final formattedTime = '${now.year.toString().padLeft(4, '0')}-' - '${now.month.toString().padLeft(2, '0')}-' - '${now.day.toString().padLeft(2, '0')} ' - '${now.hour.toString().padLeft(2, '0')}:' - '${now.minute.toString().padLeft(2, '0')}:' - '${now.second.toString().padLeft(2, '0')}'; - - final logMessage = '$formattedTime [$color$level$_resetColor] $message'; - log(logMessage); + static void _logMessage(String level, String color, String message) { + _log(level, color, message); } } diff --git a/lib/src/common/mixins.dart b/lib/src/common/mixins.dart index 4609373..a8414ce 100644 --- a/lib/src/common/mixins.dart +++ b/lib/src/common/mixins.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; typedef Percent = double; @@ -43,7 +43,7 @@ mixin _GasSettings { /// [gasParams] is an instance of the [GasSettings] class containing the gas settings. set setGasParams(GasSettings gasParams) => _gasParams = gasParams; - /// Applies the gas settings to a user operation. + /// Applies the gas settings to a user operation, by multiplying the gas limits by a certain percentage. /// /// [op] is the user operation to which the gas settings should be applied. /// @@ -84,6 +84,17 @@ mixin _PluginManager { _plugins[name] = module; } + /// checks if a plugin exists + /// + /// Parameters: + /// - `name`: The name of the plugin to check + /// + /// Returns: + /// true if the plugin exists + bool hasPlugin(String name) { + return _plugins.containsKey(name); + } + /// Gets a plugin by name. /// /// Parameters: @@ -102,17 +113,6 @@ mixin _PluginManager { return _plugins[name] as T; } - /// checks if a plugin exists - /// - /// Parameters: - /// - `name`: The name of the plugin to check - /// - /// Returns: - /// true if the plugin exists - bool hasPlugin(String name) { - return _plugins.containsKey(name); - } - /// Removes an unwanted plugin by name. /// /// Parameters: diff --git a/lib/src/common/pack.dart b/lib/src/common/pack.dart index d3c551b..eef4813 100644 --- a/lib/src/common/pack.dart +++ b/lib/src/common/pack.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; /// Packs two 128-bit unsigned integers into a 32-byte array. /// diff --git a/lib/src/common/string.dart b/lib/src/common/string.dart new file mode 100644 index 0000000..62018df --- /dev/null +++ b/lib/src/common/string.dart @@ -0,0 +1,148 @@ +part of '../../variance_dart.dart'; + +RegExp _ipv4Maybe = RegExp(r'^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$'); +RegExp _ipv6 = + RegExp(r'^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$'); + +bool isFQDN(String str, Map options) { + final parts = str.split('.'); + if (options['require_tld'] as bool) { + var tld = parts.removeLast(); + if (parts.isEmpty || !RegExp(r'^[a-z]{2,}$').hasMatch(tld)) { + return false; + } + } + + for (final part in parts) { + if (options['allow_underscores'] as bool) { + if (part.contains('__')) { + return false; + } + } + if (!RegExp(r'^[a-z\\u00a1-\\uffff0-9-]+$').hasMatch(part)) { + return false; + } + if (part[0] == '-' || + part[part.length - 1] == '-' || + part.contains('---')) { + return false; + } + } + return true; +} + +bool isIP(String str, [Object? version]) { + assert(version == null || version is String || version is int); + version = version.toString(); + if (version == 'null') { + return isIP(str, 4) || isIP(str, 6); + } else if (version == '4') { + if (!_ipv4Maybe.hasMatch(str)) { + return false; + } + var parts = str.split('.'); + parts.sort((a, b) => int.parse(a) - int.parse(b)); + return int.parse(parts[3]) <= 255; + } + return version == '6' && _ipv6.hasMatch(str); +} + +String? _shift(List elements) { + if (elements.isEmpty) return null; + return elements.removeAt(0); +} + +extension StringExtension on String? { + bool isURL() { + var str = this; + if (str == null || + str.isEmpty || + str.length > 2083 || + str.indexOf('mailto:') == 0) { + return false; + } + + final Map options = { + 'protocols': ['http', 'https', 'ftp'], + 'require_tld': true, + 'require_protocol': false, + 'allow_underscores': false, + }; + + var split = str.split('://'); + if (split.length > 1) { + final protocol = _shift(split); + final protocols = options['protocols'] as List; + if (!protocols.contains(protocol)) { + return false; + } + } else if (options['require_protocol'] == true) { + return false; + } + str = split.join('://'); + + // check hash + split = str.split('#'); + str = _shift(split); + final hash = split.join('#'); + if (hash.isNotEmpty && RegExp(r'\s').hasMatch(hash)) { + return false; + } + + // check query params + split = str?.split('?') ?? []; + str = _shift(split); + final query = split.join('?'); + if (query != "" && RegExp(r'\s').hasMatch(query)) { + return false; + } + + // check path + split = str?.split('/') ?? []; + str = _shift(split); + final path = split.join('/'); + if (path != "" && RegExp(r'\s').hasMatch(path)) { + return false; + } + + // check auth type urls + split = str?.split('@') ?? []; + if (split.length > 1) { + final auth = _shift(split); + if (auth != null && auth.contains(':')) { + // final auth = auth.split(':'); + final parts = auth.split(':'); + final user = _shift(parts); + if (user == null || !RegExp(r'^\S+$').hasMatch(user)) { + return false; + } + final pass = parts.join(':'); + if (!RegExp(r'^\S*$').hasMatch(pass)) { + return false; + } + } + } + + // check hostname + final hostname = split.join('@'); + split = hostname.split(':'); + final host = _shift(split); + if (split.isNotEmpty) { + final portStr = split.join(':'); + final port = int.tryParse(portStr, radix: 10); + if (!RegExp(r'^[0-9]+$').hasMatch(portStr) || + port == null || + port <= 0 || + port > 65535) { + return false; + } + } + + if (host == null || + !isIP(host) && !isFQDN(host, options) && host != 'localhost') { + return false; + } + + return true; + } +} diff --git a/lib/src/errors/wallet_errors.dart b/lib/src/errors/wallet_errors.dart index 009d032..cab5efc 100644 --- a/lib/src/errors/wallet_errors.dart +++ b/lib/src/errors/wallet_errors.dart @@ -1,4 +1,4 @@ -part of '../../variance.dart'; +part of '../../variance_dart.dart'; class GasEstimationError extends Error { final String message; diff --git a/lib/src/interfaces/interfaces.dart b/lib/src/interfaces/interfaces.dart index bbb15e2..583bc8e 100644 --- a/lib/src/interfaces/interfaces.dart +++ b/lib/src/interfaces/interfaces.dart @@ -3,7 +3,7 @@ import 'dart:typed_data'; import 'package:web3_signers/web3_signers.dart' show PassKeyPair, Uint256; import 'package:web3dart/web3dart.dart'; -import '../../variance.dart' +import '../../variance_dart.dart' show Chain, EntryPointAddress, @@ -18,10 +18,9 @@ import '../../variance.dart' part 'account_factories.dart'; part 'bundler_provider.dart'; - part 'json_rpc_provider.dart'; -part 'smart_wallet_factory.dart'; -part 'smart_wallet.dart'; +part 'paymaster.dart'; part 'safe_module.dart'; +part 'smart_wallet.dart'; +part 'smart_wallet_factory.dart'; part 'user_operations.dart'; -part 'paymaster.dart'; diff --git a/lib/src/interfaces/json_rpc_provider.dart b/lib/src/interfaces/json_rpc_provider.dart index 02cc99e..e7662f3 100644 --- a/lib/src/interfaces/json_rpc_provider.dart +++ b/lib/src/interfaces/json_rpc_provider.dart @@ -39,6 +39,26 @@ abstract class JsonRPCProviderBase { /// This method uses an ethereum jsonRPC to fetch the current block number from the Ethereum node. Future getBlockNumber(); + /// Asynchronously retrieves information about the specified block. + /// If no block number is provided, it defaults to the latest block. + /// If `isContainFullObj` is set to `true`, the full block object will be returned. + /// + /// Parameters: + /// - `blockNumber`: The block number to retrieve information for. + /// - `isContainFullObj`: Whether to return the full block object. + /// + /// Returns: + /// A [Future] that completes with a [BlockInformation] object containing the block information. + /// + /// Example: + /// ```dart + /// var blockInfo = await getBlockInformation(); + /// ``` + Future getBlockInformation({ + String blockNumber = 'latest', + bool isContainFullObj = true, + }); + /// Asynchronously retrieves the EIP-1559 gas prices, including `maxFeePerGas` and `maxPriorityFeePerGas`. /// /// Returns: diff --git a/lib/src/interfaces/smart_wallet_factory.dart b/lib/src/interfaces/smart_wallet_factory.dart index 805ed89..5004038 100644 --- a/lib/src/interfaces/smart_wallet_factory.dart +++ b/lib/src/interfaces/smart_wallet_factory.dart @@ -19,14 +19,11 @@ abstract class SmartWalletFactoryBase { /// Creates a new Safe account with the provided salt and optional owners and threshold. /// /// [salt] is the salt value used in the account creation process. - /// [owners] is an optional list of owner addresses for the Safe account. - /// [threshold] is an optional threshold value for the Safe account. /// /// Returns a [Future] that resolves to a [SmartWallet] instance representing /// the created Safe account. - Future createSafeAccount(Uint256 salt, - [List? owners, int? threshold]); + Future createSafeAccount(Uint256 salt); /// Creates a new simple account with the provided salt and optional index. /// diff --git a/lib/variance.dart b/lib/variance_dart.dart similarity index 88% rename from lib/variance.dart rename to lib/variance_dart.dart index a6d4a25..15ab5f8 100644 --- a/lib/variance.dart +++ b/lib/variance_dart.dart @@ -2,12 +2,9 @@ library; import 'dart:async'; import 'dart:convert'; -import 'dart:isolate'; -import 'dart:developer'; import 'dart:typed_data'; import 'package:http/http.dart' as http; -import 'package:string_validator/string_validator.dart'; import 'package:web3_signers/web3_signers.dart'; import 'package:web3dart/crypto.dart'; import 'package:web3dart/json_rpc.dart'; @@ -17,15 +14,18 @@ import 'src/abis/abis.dart'; import 'src/common/logger.dart'; import 'src/interfaces/interfaces.dart'; +export 'src/abis/abis.dart' show ContractAbis; + part 'src/4337/chains.dart'; part 'src/4337/factory.dart'; part 'src/4337/paymaster.dart'; part 'src/4337/providers.dart'; +part 'src/4337/safe.dart'; part 'src/4337/userop.dart'; part 'src/4337/wallet.dart'; part 'src/common/contract.dart'; part 'src/common/factories.dart'; part 'src/common/mixins.dart'; part 'src/common/pack.dart'; -part 'src/4337/safe.dart'; +part 'src/common/string.dart'; part 'src/errors/wallet_errors.dart'; diff --git a/pubspec.lock b/pubspec.lock index 70f7886..07c8696 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -93,18 +93,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.0" built_collection: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: built_value - sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.8.1" + version: "8.9.2" characters: dependency: transitive description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.6" eip1559: dependency: transitive description: @@ -234,10 +234,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" flutter_web_plugins: dependency: transitive description: flutter @@ -247,10 +247,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -271,10 +271,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" http_multi_server: dependency: transitive description: @@ -375,10 +375,10 @@ packages: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" mockito: dependency: "direct dev" description: @@ -407,18 +407,18 @@ packages: dependency: transitive description: name: passkeys - sha256: "79f07498b44d8372a569904d5e3e1de238d83abcf83b79d583a06394b98d2789" + sha256: "59e50b21746aff90cbc56145174caa3b99523f449e42f7d8aa2199ec09c511cd" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" passkeys_android: dependency: transitive description: name: passkeys_android - sha256: ab245d18d88040409d3aa93c3359a4c10c569894361c56929cb367d4b892bbaf + sha256: "9dc0b84dad03329ff2f3be18bedecf1b8de9309c8e9cda6ef821dc88556a126d" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" passkeys_ios: dependency: transitive description: @@ -463,10 +463,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" pool: dependency: transitive description: @@ -576,14 +576,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - string_validator: - dependency: "direct main" - description: - name: string_validator - sha256: "54d4f42cd6878ae72793a58a529d9a18ebfdfbfebd9793bbe55c9b28935e8543" - url: "https://pub.dev" - source: hosted - version: "1.0.2" term_glyph: dependency: transitive description: @@ -628,10 +620,10 @@ packages: dependency: transitive description: name: uuid - sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.3.3" vector_math: dependency: transitive description: @@ -668,18 +660,18 @@ packages: dependency: "direct main" description: name: web3_signers - sha256: "7dc7f83d2eba5e78eb0310fcdf0cb4c0b167c27abafc86c8027383913dd64488" + sha256: fd2a4ee394537f2140c08a395eadd8611aa713e04699c29b6aaba75e11264faf url: "https://pub.dev" source: hosted - version: "0.0.6-r2" + version: "0.0.6" web3dart: dependency: "direct main" description: name: web3dart - sha256: "31f93cf84b8c874d7ffb363959249d7e479115fe12cf46f30b037dcad6750b22" + sha256: "885e5e8f0cc3c87c09f160a7fce6279226ca41316806f7ece2001959c62ecced" url: "https://pub.dev" source: hosted - version: "2.7.2" + version: "2.7.3" web3dart_builders: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 6eb6376..a47100e 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.0.9 +version: 0.1.0-r2 documentation: https://docs.variance.space homepage: https://variance.space repository: https://github.com/vaariance/variance-dart @@ -20,8 +20,7 @@ dependencies: sdk: flutter web3dart: ^2.7.2 http: ^1.1.0 - string_validator: ^1.0.2 - web3_signers: ^0.0.6-r2 + web3_signers: ^0.0.6 dev_dependencies: web3dart_builders: ^0.0.7