diff --git a/lib/controller/wallet_connect_controller.dart b/lib/controller/wallet_connect_controller.dart index 8291a4c..53e46c8 100644 --- a/lib/controller/wallet_connect_controller.dart +++ b/lib/controller/wallet_connect_controller.dart @@ -8,7 +8,7 @@ import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; import 'package:candide_mobile_app/models/paymaster/paymaster_response.dart'; import 'package:candide_mobile_app/screens/home/activity/components/transaction_activity_details_card.dart'; -import 'package:candide_mobile_app/screens/home/components/transaction_review_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/transaction_review_sheet.dart'; import 'package:candide_mobile_app/screens/home/send/components/send_review_leading.dart'; import 'package:candide_mobile_app/screens/home/wallet_connect/components/wc_activity_bundle_status_leading.dart'; import 'package:candide_mobile_app/screens/home/wallet_connect/components/wc_review_leading.dart'; diff --git a/lib/models/batch.dart b/lib/models/batch.dart index 470c75e..f958403 100644 --- a/lib/models/batch.dart +++ b/lib/models/batch.dart @@ -6,6 +6,7 @@ import 'package:candide_mobile_app/controller/signers_controller.dart'; import 'package:candide_mobile_app/models/gas.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; import 'package:candide_mobile_app/models/paymaster/fee_token.dart'; +import 'package:candide_mobile_app/models/paymaster/gas_back_data.dart'; import 'package:candide_mobile_app/models/paymaster/paymaster_response.dart'; import 'package:candide_mobile_app/services/paymaster.dart'; import 'package:candide_mobile_app/utils/constants.dart'; @@ -25,6 +26,7 @@ class Batch { Network network; // GasEstimate? gasEstimate; + GasBackData? gasBack; FeeToken? _selectedFeeToken; late PaymasterResponse _paymasterResponse; List transactions = []; @@ -61,7 +63,7 @@ class Batch { Future _adjustFeeCurrencyCosts() async{ - for (FeeToken feeToken in _paymasterResponse.tokens){ + for (FeeToken feeToken in _paymasterResponse.tokens.reversed){ bool isEther = feeToken.token.symbol == network.nativeCurrency && feeToken.token.address == Constants.addressZeroHex; UserOperation op = await toUserOperation( BigInt.from(PersistentData.accountStatus.nonce), @@ -69,7 +71,7 @@ class Batch { skipPaymasterData: true, feeToken: feeToken, ); - BigInt maxCost = FeeCurrencyUtils.calculateFee(op, feeToken.exchangeRate, isEther); + BigInt maxCost = feeToken.calculateFee(op, network); if (!isEther){ maxCost = maxCost.scale(1.05); // todo check } @@ -86,6 +88,10 @@ class Batch { } Future _addPaymasterToUserOp(UserOperation userOp, int chainId) async { + if (gasBack?.gasBackApplied ?? false){ + userOp.paymasterAndData = gasBack!.paymasterAndData; + return; + } String? paymasterData = await Paymaster.getPaymasterData(userOp, selectedFeeToken!.token.address, chainId); if (paymasterData == null){ // todo network: handle fetching errors userOp.paymasterAndData = "0x"; @@ -169,6 +175,11 @@ class Batch { userOp.verificationGasLimit = _gasEstimate.verificationGasLimit.scale(2); userOp.maxFeePerGas = _gasEstimate.maxFeePerGas; userOp.maxPriorityFeePerGas = _gasEstimate.maxPriorityFeePerGas; + if (gasBack == null){ + FeeToken _tempGasToken = feeToken ?? paymasterResponse.tokens.first; + BigInt maxETHCost = _tempGasToken.calculateETHFee(userOp, network); + gasBack = await GasBackData.getGasBackData(account, paymasterResponse.paymasterData.paymaster, network, maxETHCost); + } if (userOp.initCode != "0x"){ userOp.verificationGasLimit += BigInt.from(350000); // higher than normal for deployment userOp.callGasLimit += multiSendTransaction?.suggestedGasLimit ?? userOp.callGasLimit; // todo remove when first simulateHandleOp is implemented @@ -177,7 +188,7 @@ class Batch { if (_includesPaymaster(feeToken)){ userOp.verificationGasLimit += BigInt.from(35000); } - if (_includesPaymaster(feeToken) && !skipPaymasterData){ + if ((_includesPaymaster(feeToken) || gasBack!.gasBackApplied) && !skipPaymasterData){ await _addPaymasterToUserOp(userOp, account.chainId); } // diff --git a/lib/models/gas.dart b/lib/models/gas.dart index 1367553..51e2639 100644 --- a/lib/models/gas.dart +++ b/lib/models/gas.dart @@ -1,16 +1,19 @@ class GasEstimate { BigInt callGasLimit; + BigInt basePreVerificationGas; BigInt preVerificationGas; BigInt verificationGasLimit; BigInt maxPriorityFeePerGas; BigInt maxFeePerGas; + late BigInt extraPreVerificationGas; //specific for L2s late BigInt l1GasUsed; //specific for L2s late BigInt l1BaseFee; //specific for L2s GasEstimate( - {required this.callGasLimit, - required this.preVerificationGas, - required this.verificationGasLimit, + {required this.callGasLimit, // set by bundler + required this.basePreVerificationGas, // set by bundler + required this.preVerificationGas, // calculated/adjusted for chain + required this.verificationGasLimit, // set by bundler required this.maxPriorityFeePerGas, required this.maxFeePerGas, BigInt? l1GasUsed, @@ -22,6 +25,7 @@ class GasEstimate { GasEstimate copy() { return GasEstimate( callGasLimit: callGasLimit, + basePreVerificationGas: basePreVerificationGas, preVerificationGas: preVerificationGas, verificationGasLimit: verificationGasLimit, maxPriorityFeePerGas: maxPriorityFeePerGas, diff --git a/lib/models/gas_estimators/l1_gas_estimator.dart b/lib/models/gas_estimators/l1_gas_estimator.dart index dfe09c8..e9464f4 100644 --- a/lib/models/gas_estimators/l1_gas_estimator.dart +++ b/lib/models/gas_estimators/l1_gas_estimator.dart @@ -51,6 +51,7 @@ class L1GasEstimator extends GasEstimator { }else{ gasEstimate = prevEstimate.copy(); } + gasEstimate.preVerificationGas = gasEstimate.basePreVerificationGas; if (includesPaymaster){ gasEstimate.preVerificationGas += BigInt.from(84); // To accommodate for GnosisTransaction.approveAmount which would be 0 before estimation gasEstimate.preVerificationGas += BigInt.from(2496); // to accommodate for paymasterAndData (156 bytes * 16) diff --git a/lib/models/gas_estimators/l2_gas_estimator.dart b/lib/models/gas_estimators/l2_gas_estimator.dart index 8e6fdf8..3801832 100644 --- a/lib/models/gas_estimators/l2_gas_estimator.dart +++ b/lib/models/gas_estimators/l2_gas_estimator.dart @@ -60,16 +60,16 @@ class L2GasEstimator extends GasEstimator { gasEstimate.l1BaseFee = l1BaseFee; gasEstimate.l1GasUsed = l1GasUsed; } - + BigInt l1GasUsed = gasEstimate.l1GasUsed; if (includesPaymaster){ - gasEstimate.l1GasUsed += BigInt.from(84); // To accommodate for GnosisTransaction.approveAmount which would be 0 before estimation - gasEstimate.l1GasUsed += BigInt.from(2496); // to accommodate for paymasterAndData (156 bytes * 16) + l1GasUsed += BigInt.from(84); // To accommodate for GnosisTransaction.approveAmount which would be 0 before estimation + l1GasUsed += BigInt.from(2496); // to accommodate for paymasterAndData (156 bytes * 16) } BigInt scale = gasEstimate.l1BaseFee ~/ gasEstimate.maxFeePerGas; if (scale == BigInt.zero){ scale = BigInt.one; } - gasEstimate.preVerificationGas += gasEstimate.l1GasUsed * (scale); + gasEstimate.preVerificationGas = gasEstimate.basePreVerificationGas + (l1GasUsed * (scale)); // return gasEstimate; } diff --git a/lib/models/paymaster/fee_token.dart b/lib/models/paymaster/fee_token.dart index acd7b5c..d05d5ea 100644 --- a/lib/models/paymaster/fee_token.dart +++ b/lib/models/paymaster/fee_token.dart @@ -1,20 +1,28 @@ +import 'package:candide_mobile_app/config/network.dart'; import 'package:candide_mobile_app/controller/token_info_storage.dart'; +import 'package:candide_mobile_app/utils/constants.dart'; import 'package:wallet_dart/wallet/user_operation.dart'; class FeeToken { TokenInfo token; BigInt fee; + BigInt paymasterFee; BigInt exchangeRate; - FeeToken({required this.token, required this.fee, required this.exchangeRate}); -} + FeeToken({required this.token, required this.fee, required this.paymasterFee, required this.exchangeRate}); -class FeeCurrencyUtils { static final BigInt costOfPost = BigInt.from(45000); // todo shouldn't be hardcoded - static BigInt calculateFee(UserOperation op, BigInt exchangeRate, bool isEther) { - BigInt operationMaxEthCostUsingPaymaster = op.maxFeePerGas * (costOfPost + op.callGasLimit + (op.verificationGasLimit * BigInt.from(isEther ? 1 : 3)) + op.preVerificationGas); - BigInt tokenToEthPrice = (operationMaxEthCostUsingPaymaster * exchangeRate) ~/ BigInt.from(10).pow(18); - return tokenToEthPrice; + BigInt calculateETHFee(UserOperation op, Network network) { + bool isEther = token.symbol == network.nativeCurrency && token.address == Constants.addressZeroHex; + BigInt operationMaxEthCost = op.maxFeePerGas * (costOfPost + op.callGasLimit + (op.verificationGasLimit * BigInt.from(isEther ? 1 : 3)) + op.preVerificationGas); + return operationMaxEthCost; + } + + BigInt calculateFee(UserOperation op, Network network) { + BigInt operationMaxEthCost = calculateETHFee(op, network); + BigInt tokenFee = (operationMaxEthCost * exchangeRate) ~/ BigInt.from(10).pow(18); + tokenFee += paymasterFee; + return tokenFee; } } \ No newline at end of file diff --git a/lib/models/paymaster/gas_back_data.dart b/lib/models/paymaster/gas_back_data.dart new file mode 100644 index 0000000..30022f3 --- /dev/null +++ b/lib/models/paymaster/gas_back_data.dart @@ -0,0 +1,34 @@ +import 'package:candide_mobile_app/config/network.dart'; +import 'package:candide_mobile_app/models/paymaster/source/paymaster_contract.g.dart'; +import 'package:candide_mobile_app/utils/constants.dart'; +import 'package:wallet_dart/wallet/account.dart'; +import 'package:web3dart/credentials.dart'; + +class GasBackData { + EthereumAddress paymaster; + String paymasterAndData; + bool gasBackApplied; + + GasBackData({required this.paymaster, required this.paymasterAndData, required this.gasBackApplied}); + + static Future getGasBackData(Account account, EthereumAddress _paymaster, Network network, BigInt maxETHCost) async { + PaymasterContract paymasterContract = PaymasterContract(address: _paymaster, client: network.client); + BigInt accountGasBack = await paymasterContract.gasBackBalances(account.address); + bool gasBackApplied = accountGasBack >= maxETHCost; + String paymasterAndData = "0x"; + if (gasBackApplied){ + paymasterAndData += _paymaster.hexNo0x; + paymasterAndData += Constants.addressZero.hexNo0x; // no token + paymasterAndData += BigInt.from(2).toRadixString(16).padLeft(2, '0'); // paymaster mode = 2 (GAS_BACK) + paymasterAndData += BigInt.from(0).toRadixString(16).padLeft(12, '0'); // validUntil = 0 (48 bits = 6 bytes = 12 hex chars) + paymasterAndData += BigInt.from(0).toRadixString(16).padLeft(64, '0'); // fee = 0 (256 bits = 32 bytes = 64 hex chars) + paymasterAndData += BigInt.from(0).toRadixString(16).padLeft(64, '0'); // exchangeRate = 0 + } + return GasBackData( + paymaster: _paymaster, + paymasterAndData: paymasterAndData, + gasBackApplied: gasBackApplied, + ); + } + +} \ No newline at end of file diff --git a/lib/models/paymaster/source/paymaster_contract.abi.json b/lib/models/paymaster/source/paymaster_contract.abi.json new file mode 100644 index 0000000..fe9f7c7 --- /dev/null +++ b/lib/models/paymaster/source/paymaster_contract.abi.json @@ -0,0 +1,540 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "contract IEntryPoint", + "name": "_entryPoint", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cost", + "type": "uint256" + } + ], + "name": "UserOperationSponsored", + "type": "event" + }, + { + "inputs": [], + "name": "COST_OF_POST", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "unstakeDelaySec", + "type": "uint32" + } + ], + "name": "addStake", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gasBackBasePoints", + "type": "uint256" + } + ], + "name": "changeGasBackBasePoints", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "entryPoint", + "outputs": [ + { + "internalType": "contract IEntryPoint", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "gasBackBalances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasBackBasePoints", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "callGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct UserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "token", + "type": "address" + }, + { + "internalType": "enum CandidePaymaster.SponsoringMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exchangeRate", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct CandidePaymaster.PaymasterData", + "name": "paymasterData", + "type": "tuple" + } + ], + "name": "getHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + } + ], + "name": "parsePaymasterAndData", + "outputs": [ + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "token", + "type": "address" + }, + { + "internalType": "enum CandidePaymaster.SponsoringMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exchangeRate", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct CandidePaymaster.PaymasterData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IPaymaster.PostOpMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "actualGasCost", + "type": "uint256" + } + ], + "name": "postOp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unlockStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "callGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct UserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxCost", + "type": "uint256" + } + ], + "name": "validatePaymasterUserOp", + "outputs": [ + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "validationData", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "withdrawAddress", + "type": "address" + } + ], + "name": "withdrawStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "withdrawAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20Metadata", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawTokensTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} \ No newline at end of file diff --git a/lib/models/paymaster/source/paymaster_contract.g.dart b/lib/models/paymaster/source/paymaster_contract.g.dart new file mode 100644 index 0000000..a85d9e2 --- /dev/null +++ b/lib/models/paymaster/source/paymaster_contract.g.dart @@ -0,0 +1,220 @@ +// Generated code, do not modify. Run `build_runner build` to re-generate! +// @dart=2.12 +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:web3dart/web3dart.dart' as _i1; +import 'dart:typed_data' as _i2; + +final _contractAbi = _i1.ContractAbi.fromJson( + '[{"inputs":[{"internalType":"contract IEntryPoint","name":"_entryPoint","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"UserOperationSponsored","type":"event"},{"inputs":[],"name":"COST_OF_POST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"unstakeDelaySec","type":"uint32"}],"name":"addStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasBackBasePoints","type":"uint256"}],"name":"changeGasBackBasePoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"gasBackBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasBackBasePoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"components":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"internalType":"enum CandidePaymaster.SponsoringMode","name":"mode","type":"uint8"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CandidePaymaster.PaymasterData","name":"paymasterData","type":"tuple"}],"name":"getHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"paymasterAndData","type":"bytes"}],"name":"parsePaymasterAndData","outputs":[{"components":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"internalType":"enum CandidePaymaster.SponsoringMode","name":"mode","type":"uint8"},{"internalType":"uint48","name":"validUntil","type":"uint48"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CandidePaymaster.PaymasterData","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum IPaymaster.PostOpMode","name":"mode","type":"uint8"},{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"uint256","name":"actualGasCost","type":"uint256"}],"name":"postOp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"maxCost","type":"uint256"}],"name":"validatePaymasterUserOp","outputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"}],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTokensTo","outputs":[],"stateMutability":"nonpayable","type":"function"}]', + 'Paymaster_contract', +); + +class PaymasterContract extends _i1.GeneratedContract { + PaymasterContract({ + required _i1.EthereumAddress address, + required _i1.Web3Client client, + int? chainId, + }) : super( + _i1.DeployedContract( + _contractAbi, + address, + ), + client, + chainId, + ); + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future COST_OF_POST({_i1.BlockNum? atBlock}) async { + final function = self.abi.functions[1]; + assert(checkSignature(function, '796d4371')); + final params = []; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as BigInt); + } + + /// The optional [transaction] parameter can be used to override parameters + /// like the gas price, nonce and max gas. The `data` and `to` fields will be + /// set by the contract. + Future deposit({ + required _i1.Credentials credentials, + _i1.Transaction? transaction, + }) async { + final function = self.abi.functions[4]; + assert(checkSignature(function, 'd0e30db0')); + final params = []; + return write( + credentials, + transaction, + function, + params, + ); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future<_i1.EthereumAddress> entryPoint({_i1.BlockNum? atBlock}) async { + final function = self.abi.functions[5]; + assert(checkSignature(function, 'b0d691fe')); + final params = []; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as _i1.EthereumAddress); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future gasBackBalances( + _i1.EthereumAddress $param2, { + _i1.BlockNum? atBlock, + }) async { + final function = self.abi.functions[6]; + assert(checkSignature(function, 'c3fb940e')); + final params = [$param2]; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as BigInt); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future gasBackBasePoints({_i1.BlockNum? atBlock}) async { + final function = self.abi.functions[7]; + assert(checkSignature(function, 'ca09ebdb')); + final params = []; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as BigInt); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future getDeposit({_i1.BlockNum? atBlock}) async { + final function = self.abi.functions[8]; + assert(checkSignature(function, 'c399ec88')); + final params = []; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as BigInt); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future<_i2.Uint8List> getHash( + dynamic userOp, + dynamic paymasterData, { + _i1.BlockNum? atBlock, + }) async { + final function = self.abi.functions[9]; + assert(checkSignature(function, 'b5766ebc')); + final params = [ + userOp, + paymasterData, + ]; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as _i2.Uint8List); + } + + /// The optional [atBlock] parameter can be used to view historical data. When + /// set, the function will be evaluated in the specified block. By default, the + /// latest on-chain block will be used. + Future parsePaymasterAndData( + _i2.Uint8List paymasterAndData, { + _i1.BlockNum? atBlock, + }) async { + final function = self.abi.functions[11]; + assert(checkSignature(function, '94d4ad60')); + final params = [paymasterAndData]; + final response = await read( + function, + params, + atBlock, + ); + return (response[0] as dynamic); + } + + /// The optional [transaction] parameter can be used to override parameters + /// like the gas price, nonce and max gas. The `data` and `to` fields will be + /// set by the contract. + Future validatePaymasterUserOp( + dynamic userOp, + _i2.Uint8List userOpHash, + BigInt maxCost, { + required _i1.Credentials credentials, + _i1.Transaction? transaction, + }) async { + final function = self.abi.functions[16]; + assert(checkSignature(function, 'f465c77e')); + final params = [ + userOp, + userOpHash, + maxCost, + ]; + return write( + credentials, + transaction, + function, + params, + ); + } + + /// Returns a live stream of all UserOperationSponsored events emitted by this contract. + Stream userOperationSponsoredEvents({ + _i1.BlockNum? fromBlock, + _i1.BlockNum? toBlock, + }) { + final event = self.event('UserOperationSponsored'); + final filter = _i1.FilterOptions.events( + contract: self, + event: event, + fromBlock: fromBlock, + toBlock: toBlock, + ); + return client.events(filter).map((_i1.FilterEvent result) { + final decoded = event.decodeResults( + result.topics!, + result.data!, + ); + return UserOperationSponsored(decoded); + }); + } +} + +class UserOperationSponsored { + UserOperationSponsored(List response) + : sender = (response[0] as _i1.EthereumAddress), + token = (response[1] as _i1.EthereumAddress), + cost = (response[2] as BigInt); + + final _i1.EthereumAddress sender; + + final _i1.EthereumAddress token; + + final BigInt cost; +} diff --git a/lib/screens/components/token_fee_selector.dart b/lib/screens/components/token_fee_selector.dart index 0c49b78..6c82a55 100644 --- a/lib/screens/components/token_fee_selector.dart +++ b/lib/screens/components/token_fee_selector.dart @@ -2,7 +2,8 @@ import 'package:candide_mobile_app/config/theme.dart'; import 'package:candide_mobile_app/controller/persistent_data.dart'; import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/paymaster/fee_token.dart'; -import 'package:candide_mobile_app/screens/home/components/fee_currency_selection_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/fee_currency_selection_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/gas_back_sheet.dart'; import 'package:candide_mobile_app/utils/currency.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -40,6 +41,17 @@ class _TokenFeeSelectorState extends State { ); } + showGasBackSheet(){ + showBarModalBottomSheet( + context: context, + backgroundColor: Get.theme.canvasColor, + builder: (context) => SingleChildScrollView( + controller: ModalScrollController.of(context), + child: const GasBackSheet(), + ), + ); + } + @override void initState() { super.initState(); @@ -58,7 +70,11 @@ class _TokenFeeSelectorState extends State { ), child: InkWell( onTap: (){ - showFeeCurrencySelectionModal(); + if (widget.batch.gasBack?.gasBackApplied ?? false){ + showGasBackSheet(); + }else{ + showFeeCurrencySelectionModal(); + } }, child: Container( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 5), @@ -71,17 +87,12 @@ class _TokenFeeSelectorState extends State { Text("Transaction fee", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, color: Colors.grey),), SizedBox( width: Get.width*0.5, - child: Text("pay transaction fees with one of the supported tokens", style: TextStyle(fontFamily: AppThemes.fonts.gilroy, color: Colors.grey, fontSize: 11),) + child: Text("choose preferred token for transaction fees", style: TextStyle(fontFamily: AppThemes.fonts.gilroy, color: Colors.grey, fontSize: 11),) ), ], ), const Spacer(), - Column( - children: [ - Text(widget.batch.selectedFeeToken != null ? CurrencyUtils.formatCurrency(widget.batch.selectedFeeToken!.fee, widget.batch.selectedFeeToken!.token, formatSmallDecimals: true) : "-", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, color: Colors.white)), - Text(widget.batch.selectedFeeToken != null ? "\$${CurrencyUtils.convertToQuote(widget.batch.selectedFeeToken!.token.address.toLowerCase(), PersistentData.accountBalance.quoteCurrency, widget.batch.selectedFeeToken!.fee).toPrecision(3)}" : "-", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, color: Colors.grey, fontSize: 12)), - ], - ), + !widget.batch.gasBack!.gasBackApplied ? _TokenFeeDisplay(batch: widget.batch,) : const _FreeCardIndicator(), const SizedBox(width: 5,), const Icon(PhosphorIcons.caretRightBold, size: 15, color: Colors.white,), const SizedBox(width: 5,), @@ -91,4 +102,50 @@ class _TokenFeeSelectorState extends State { ), ); } -} \ No newline at end of file +} + +class _TokenFeeDisplay extends StatelessWidget { + final Batch batch; + const _TokenFeeDisplay({Key? key, required this.batch}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text(batch.selectedFeeToken != null ? CurrencyUtils.formatCurrency(batch.selectedFeeToken!.fee, batch.selectedFeeToken!.token, formatSmallDecimals: true) : "-", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, color: Colors.white)), + Text(batch.selectedFeeToken != null ? "\$${CurrencyUtils.convertToQuote(batch.selectedFeeToken!.token.address.toLowerCase(), PersistentData.accountBalance.quoteCurrency, batch.selectedFeeToken!.fee).toPrecision(3)}" : "-", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, color: Colors.grey, fontSize: 12)), + ], + ); + } +} + +class _FreeCardIndicator extends StatelessWidget { + const _FreeCardIndicator({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 3, + shadowColor: Colors.green.withOpacity(0.2), + color: Colors.green.withOpacity(0.2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + side: const BorderSide( + color: Colors.green, + width: 1.2 + ) + ), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(PhosphorIcons.lightningBold, size: 15,), + const SizedBox(width: 5,), + Text("FREE", textAlign: TextAlign.center, style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold),), + ], + ), + ), + ); + } +} diff --git a/lib/screens/home/components/currency_selection_sheet.dart b/lib/screens/home/components/transaction/currency_selection_sheet.dart similarity index 100% rename from lib/screens/home/components/currency_selection_sheet.dart rename to lib/screens/home/components/transaction/currency_selection_sheet.dart diff --git a/lib/screens/home/components/fee_currency_selection_sheet.dart b/lib/screens/home/components/transaction/fee_currency_selection_sheet.dart similarity index 100% rename from lib/screens/home/components/fee_currency_selection_sheet.dart rename to lib/screens/home/components/transaction/fee_currency_selection_sheet.dart diff --git a/lib/screens/home/components/transaction/gas_back_sheet.dart b/lib/screens/home/components/transaction/gas_back_sheet.dart new file mode 100644 index 0000000..3acc436 --- /dev/null +++ b/lib/screens/home/components/transaction/gas_back_sheet.dart @@ -0,0 +1,32 @@ +import 'package:animated_emoji/animated_emoji.dart'; +import 'package:candide_mobile_app/config/theme.dart'; +import 'package:flutter/material.dart'; + +class GasBackSheet extends StatelessWidget { + const GasBackSheet({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 15), + child: Column( + children: [ + const SizedBox(height: 20,), + const AnimatedEmoji( + AnimatedEmojis.partyingFace, + size: 85, + ), + const SizedBox(height: 10,), + Text("Congratulations!", style: TextStyle(fontFamily: AppThemes.fonts.gilroyBold, fontSize: 22),), + const SizedBox(height: 5,), + const Text( + "You're quite the explorer!\nYou just earned a special gift, a FREE transaction.\nEnjoy fee-free transactions and keep exploring!", + textAlign: TextAlign.center, + style: TextStyle(color: Colors.grey), + ), + const SizedBox(height: 35,), + ], + ), + ); + } +} diff --git a/lib/screens/home/components/transaction_review_sheet.dart b/lib/screens/home/components/transaction/transaction_review_sheet.dart similarity index 100% rename from lib/screens/home/components/transaction_review_sheet.dart rename to lib/screens/home/components/transaction/transaction_review_sheet.dart diff --git a/lib/screens/home/send/send_amount_sheet.dart b/lib/screens/home/send/send_amount_sheet.dart index 3e988a4..c9bfc6e 100644 --- a/lib/screens/home/send/send_amount_sheet.dart +++ b/lib/screens/home/send/send_amount_sheet.dart @@ -1,7 +1,7 @@ import 'package:candide_mobile_app/config/theme.dart'; import 'package:candide_mobile_app/controller/persistent_data.dart'; import 'package:candide_mobile_app/controller/token_info_storage.dart'; -import 'package:candide_mobile_app/screens/home/components/currency_selection_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/currency_selection_sheet.dart'; import 'package:candide_mobile_app/utils/constants.dart'; import 'package:candide_mobile_app/utils/currency.dart'; import 'package:candide_mobile_app/utils/extensions/decimal_extensions.dart'; diff --git a/lib/screens/home/send/send_sheet.dart b/lib/screens/home/send/send_sheet.dart index d6507fa..496f596 100644 --- a/lib/screens/home/send/send_sheet.dart +++ b/lib/screens/home/send/send_sheet.dart @@ -6,7 +6,7 @@ import 'package:candide_mobile_app/controller/send_controller.dart'; import 'package:candide_mobile_app/controller/token_info_storage.dart'; import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; -import 'package:candide_mobile_app/screens/home/components/transaction_review_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/transaction_review_sheet.dart'; import 'package:candide_mobile_app/screens/home/send/components/send_review_leading.dart'; import 'package:candide_mobile_app/screens/home/send/send_amount_sheet.dart'; import 'package:candide_mobile_app/screens/home/send/send_to_sheet.dart'; diff --git a/lib/screens/home/swap/swap_main_sheet.dart b/lib/screens/home/swap/swap_main_sheet.dart index 4e81053..28a3313 100644 --- a/lib/screens/home/swap/swap_main_sheet.dart +++ b/lib/screens/home/swap/swap_main_sheet.dart @@ -5,7 +5,7 @@ import 'package:candide_mobile_app/controller/persistent_data.dart'; import 'package:candide_mobile_app/controller/token_info_storage.dart'; import 'package:candide_mobile_app/screens/components/continous_input_border.dart'; import 'package:candide_mobile_app/screens/components/summary_table.dart'; -import 'package:candide_mobile_app/screens/home/components/currency_selection_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/currency_selection_sheet.dart'; import 'package:candide_mobile_app/services/explorer.dart'; import 'package:candide_mobile_app/utils/currency.dart'; import 'package:candide_mobile_app/utils/extensions/decimal_extensions.dart'; diff --git a/lib/screens/home/swap/swap_sheet.dart b/lib/screens/home/swap/swap_sheet.dart index 907bfcc..60ef37f 100644 --- a/lib/screens/home/swap/swap_sheet.dart +++ b/lib/screens/home/swap/swap_sheet.dart @@ -7,7 +7,7 @@ import 'package:candide_mobile_app/controller/swap_controller.dart'; import 'package:candide_mobile_app/controller/token_info_storage.dart'; import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; -import 'package:candide_mobile_app/screens/home/components/transaction_review_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/transaction_review_sheet.dart'; import 'package:candide_mobile_app/screens/home/swap/components/swap_review_leading.dart'; import 'package:candide_mobile_app/screens/home/swap/swap_main_sheet.dart'; import 'package:candide_mobile_app/utils/currency.dart'; diff --git a/lib/screens/home/wallet_connect/components/wc_signature_reject_dialog.dart b/lib/screens/home/wallet_connect/components/wc_signature_reject_dialog.dart index a454643..f53db0b 100644 --- a/lib/screens/home/wallet_connect/components/wc_signature_reject_dialog.dart +++ b/lib/screens/home/wallet_connect/components/wc_signature_reject_dialog.dart @@ -3,7 +3,7 @@ import 'package:candide_mobile_app/config/theme.dart'; import 'package:candide_mobile_app/controller/persistent_data.dart'; import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; -import 'package:candide_mobile_app/screens/home/components/transaction_review_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/transaction_review_sheet.dart'; import 'package:candide_mobile_app/screens/home/wallet_connect/components/wallet_deployment_leading.dart'; import 'package:candide_mobile_app/utils/constants.dart'; import 'package:candide_mobile_app/utils/utils.dart'; diff --git a/lib/services/bundler.dart b/lib/services/bundler.dart index 135ec0c..14a823b 100644 --- a/lib/services/bundler.dart +++ b/lib/services/bundler.dart @@ -70,7 +70,8 @@ class Bundler { return GasEstimate( callGasLimit: _decodeBigInt(response.data["result"]["callGasLimit"]).scale(1.2), verificationGasLimit: _decodeBigInt(response.data["result"]["verificationGas"]), - preVerificationGas: _decodeBigInt(response.data["result"]["preVerificationGas"]), + basePreVerificationGas: _decodeBigInt(response.data["result"]["preVerificationGas"]), + preVerificationGas: BigInt.zero, maxFeePerGas: BigInt.zero, maxPriorityFeePerGas: BigInt.zero, ); diff --git a/lib/services/paymaster.dart b/lib/services/paymaster.dart index aea2eb7..25831e9 100644 --- a/lib/services/paymaster.dart +++ b/lib/services/paymaster.dart @@ -20,6 +20,7 @@ class Paymaster { result.add(FeeToken( token: _ethereum!, fee: BigInt.zero, + paymasterFee: BigInt.zero, exchangeRate: BigInt.parse("1000000000000000000") )); // @@ -45,9 +46,6 @@ class Paymaster { "method": "pm_getApprovedTokens", }) ); - // - // - // EthereumAddress paymasterAddress = Constants.addressZero; for (Map tokenData in response.data['result']){ @@ -58,6 +56,7 @@ class Paymaster { FeeToken( token: _token, fee: BigInt.zero, + paymasterFee: tokenData["fee"].runtimeType == String ? BigInt.parse(tokenData["fee"]) : BigInt.from(tokenData["fee"]), exchangeRate: tokenData["exchangeRate"].runtimeType == String ? BigInt.parse(tokenData["exchangeRate"]) : BigInt.from(tokenData["exchangeRate"]) ) ); diff --git a/lib/utils/guardian_helpers.dart b/lib/utils/guardian_helpers.dart index df520b9..68f7ad7 100644 --- a/lib/utils/guardian_helpers.dart +++ b/lib/utils/guardian_helpers.dart @@ -11,7 +11,7 @@ import 'package:candide_mobile_app/models/batch.dart'; import 'package:candide_mobile_app/models/gnosis_transaction.dart'; import 'package:candide_mobile_app/models/guardian_operation.dart'; import 'package:candide_mobile_app/models/recovery_request.dart'; -import 'package:candide_mobile_app/screens/home/components/transaction_review_sheet.dart'; +import 'package:candide_mobile_app/screens/home/components/transaction/transaction_review_sheet.dart'; import 'package:candide_mobile_app/screens/home/guardians/components/guardian_review_leading.dart'; import 'package:candide_mobile_app/screens/home/home_screen.dart'; import 'package:candide_mobile_app/services/security.dart'; diff --git a/pubspec.lock b/pubspec.lock index c8beb51..1e1c8df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_emoji: + dependency: "direct main" + description: + name: animated_emoji + sha256: "5f4fdbe846824bf1a3c61563c7c8cf2748e8afdeb4cc4d8097936c5e316899bb" + url: "https://pub.dev" + source: hosted + version: "1.0.1+2" animations: dependency: "direct main" description: @@ -189,10 +197,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8" + sha256: "347d56c26d63519552ef9a569f2a593dda99a81fdbdff13c584b7197cfe05059" url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "5.1.2" dotenv: dependency: transitive description: @@ -524,10 +532,10 @@ packages: dependency: "direct main" description: name: lottie - sha256: "893da7a0022ec2fcaa616f34529a081f617e86cc501105b856e5a3184c58c7c2" + sha256: "23522951540d20a57a60202ed7022e6376bed206a4eee1c347a91f58bd57eb9f" url: "https://pub.dev" source: hosted - version: "1.4.3" + version: "2.3.2" magic_sdk: dependency: "direct main" description: @@ -756,10 +764,10 @@ packages: dependency: "direct main" description: name: pinput - sha256: e6aabd1571dde622f9b942f62ac2c80f84b0b50f95fa209a93e78f7d621e1f82 + sha256: "1773743c188cdd2f8d0398ea708ec72645bb41ac9311755c4f7bb03a4184bdcf" url: "https://pub.dev" source: hosted - version: "2.2.23" + version: "2.2.31" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 48e422d..bb442da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: ref: 247af6f807c259ff85e09803250e9ccb0889d8cd ens_dart: ^1.0.0 magic_sdk: ^2.0.2 - dio: ^4.0.6 + dio: ^5.1.2 eth_sig_util: ^0.0.9 walletconnect_dart: ^0.0.11 # Auth @@ -48,12 +48,12 @@ dependencies: flutter_secure_storage: ^8.0.0 # UI animations: ^2.0.3 - pinput: ^2.2.23 + pinput: ^2.2.31 flutter_awesome_alert_box: ^2.1.1 bot_toast: ^4.0.2 modal_bottom_sheet: ^3.0.0-pre qr_flutter: ^4.0.0 - lottie: ^1.4.1 + lottie: ^2.0.0 salomon_bottom_bar: ^3.3.1 pull_to_refresh_flutter3: ^2.0.1 blockies: ^0.1.2 @@ -62,6 +62,7 @@ dependencies: cached_network_image: ^3.2.3 expandable: ^5.0.1 info_popup: ^2.4.6 + animated_emoji: ^1.0.1+2 # Typography phosphor_flutter: ^1.4.0 font_awesome_flutter: ^10.1.0