Skip to content

Commit

Permalink
feat: fix safe final sig encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
code-z2 committed Apr 2, 2024
1 parent d4ddbaa commit 5d9a1a4
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 35 deletions.
30 changes: 17 additions & 13 deletions example/lib/providers/wallet_provider.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:web3_signers/web3_signers.dart';
import 'package:variance_dart/variance.dart';
Expand Down Expand Up @@ -53,33 +54,36 @@ class WalletProvider extends ChangeNotifier {
}
}

Future<void> registerWithHDWallet() async {
Future<void> createSafeWallet() async {
_chain.accountFactory = Constants.safeProxyFactoryAddress;

final signer = EOAWallet.createWallet();
log("mnemonic: ${signer.exportMnemonic()}");
log("signer: ${signer.getAddress()}");

final SmartWalletFactory walletFactory = SmartWalletFactory(_chain, signer);

final salt = Uint256.fromHex(hexlify(w3d.keccak256(
Uint8List.fromList(utf8.encode(signer.getAddress().substring(2))))));
final salt = Uint256.fromHex(hexlify(w3d
.keccak256(EthereumAddress.fromHex(signer.getAddress()).addressBytes)));

_chain.accountFactory = Constants.safeProxyFactoryAddress;
final safe = await walletFactory.createSafeAccount(salt);
log("safe created ${safe.address.hex} ");
log("salt: ${salt.toHex()}");

try {
_chain.accountFactory = Constants.simpleAccountFactoryAddress;
_wallet = await walletFactory.createSimpleAccount(salt);
log("wallet created ${_wallet?.address.hex} ");
_wallet = await walletFactory.createSafeAccount(salt);
log("safe created ${_wallet?.address.hex} ");
} catch (e) {
log("something happened: $e");
}
}

Future<void> sendTransaction(String recipient, String amount) async {
if (_wallet != null) {
final etherAmount =
w3d.EtherAmount.fromBase10String(w3d.EtherUnit.ether, amount);
await _wallet!.send(EthereumAddress.fromHex(recipient), etherAmount);
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();

log("Transaction receipt Hash: ${receipt?.userOpHash}");
} else {
log("No wallet available to send transaction");
}
Expand Down
6 changes: 2 additions & 4 deletions example/lib/screens/create_account.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,14 @@ class _CreateAccountScreenState extends State<CreateAccountScreen> {
child: TextButton.icon(
onPressed: () {
try {
context
.read<WalletProvider>()
.registerWithHDWallet();
context.read<WalletProvider>().createSafeWallet();
Navigator.pushNamed(context, '/home');
} catch (e) {
'Something went wrong: $e';
}
},
icon: const Icon(Icons.key),
label: const Text('Generate Account with HD Key')),
label: const Text('Create Safe Smart Account')),
)
],
),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/4337/chains.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class Chains {
entrypoint: EntryPointAddress.v06,
),
Network.baseTestent: Chain(
chainId: 84531,
chainId: 84532,
explorer: "https://sepolia.basescan.org/",
jsonRpcUrl: "https://rpc.ankr.com/base_sepolia",
entrypoint: EntryPointAddress.v06,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/4337/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class BundlerProvider implements BundlerProviderBase {
.send<String>('eth_chainId')
.then(BigInt.parse)
.then((value) => value.toInt() == chain.chainId)
.then((value) => _initialized = value == true);
.then((value) => _initialized = value);
}

/// A flag indicating whether the initialization process was successful.
Expand Down
15 changes: 8 additions & 7 deletions lib/src/4337/safe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ class _SafePlugin extends Safe4337Module implements Safe4337ModuleBase {
/// Computes the hash of a Safe UserOperation.
///
/// [op] is an object representing the user operation details.
/// [currentTimestamp] is the current timestamp in seconds.
///
/// Returns a Future that resolves to the hash of the user operation as a Uint8List.
Future<Uint8List> getUserOperationHash(UserOperation op) async =>
Future<Uint8List> getUserOperationHash(
UserOperation op, int currentTimestamp) async =>
getOperationHash([
op.sender,
op.nonce,
Expand All @@ -31,23 +33,22 @@ class _SafePlugin extends Safe4337Module implements Safe4337ModuleBase {
op.maxFeePerGas,
op.maxPriorityFeePerGas,
op.paymasterAndData,
_getEncodedSignature(op.signature)
hexToBytes(getEncodedSignature(op.signature, currentTimestamp))
]);

/// 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 Uint8List representing the encoded signature with a validity period.
Uint8List _getEncodedSignature(String signature) {
final currentTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;

/// 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 hexToBytes('0x$validAfter$validUntil${signature.substring(2)}');
return '0x$validAfter$validUntil${signature.substring(2)}';
}
}
24 changes: 17 additions & 7 deletions lib/src/4337/wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,26 @@ class SmartWallet with _PluginManager, _GasSettings implements SmartWalletBase {
@override
Future<UserOperation> signUserOperation(UserOperation op,
{int? index}) async {
// Calculate the operation hash. safe accounts uses EIP712
// The hash is retrieved by calling the SafeModule with the operation and a dummy signature.
final opHash = hasPlugin("safe")
? await plugin<_SafePlugin>("safe").getUserOperationHash(op)
final isSafe = hasPlugin('safe');
final currentTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;

// Calculate the operation hash
final opHash = isSafe
? await plugin<_SafePlugin>('safe')
.getUserOperationHash(op, currentTimestamp)
: op.hash(_chain);

// Sign the operation hash using the 'signer' plugin
Uint8List signature =
final signature =
await plugin<MSI>('signer').personalSign(opHash, index: index);
op.signature = hexlify(signature);
final signatureHex = hexlify(signature);

// Append the signature validity period if the 'safe' plugin is enabled
op.signature = isSafe
? plugin<_SafePlugin>('safe')
.getEncodedSignature(signatureHex, currentTimestamp)
: signatureHex;

return op;
}

Expand Down Expand Up @@ -193,7 +203,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] > BigInt.zero ? Uint8List(0) : null,
initCode: responses[0].value > BigInt.zero ? Uint8List(0) : null,
signature: dummySignature);
return _updateUserOperationGas(op, feePerGas: responses[1]);
});
Expand Down
6 changes: 4 additions & 2 deletions lib/src/common/logger.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:developer';

/// A class that provides logging functionality with colored output for warnings and errors.
class Logger {
/// The ANSI escape code for red color.
Expand Down Expand Up @@ -66,7 +68,7 @@ class Logger {
/// [stackTrace] is an optional stack trace associated with the error message.
static void _logError(String level, String color, String message,
[Object? error, StackTrace? stackTrace]) {
String errorMessage = '$message';
String errorMessage = message;
if (error != null) {
errorMessage += '\nError: $error';
}
Expand All @@ -91,6 +93,6 @@ class Logger {
'${now.second.toString().padLeft(2, '0')}';

final logMessage = '$formattedTime [$color$level$_resetColor] $message';
print(logMessage);
log(logMessage);
}
}
1 change: 1 addition & 0 deletions lib/variance.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ library;
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'dart:developer';
import 'dart:typed_data';

import 'package:http/http.dart' as http;
Expand Down

0 comments on commit 5d9a1a4

Please sign in to comment.