Skip to content

Commit

Permalink
paymaster support
Browse files Browse the repository at this point in the history
  • Loading branch information
code-z2 committed Feb 24, 2024
1 parent f4fa0da commit ad157be
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 280 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.0.8

* Add paymaster as a plugin
* Rename plugins.dart to mixins
* Improve gas and nonce calculation process.

## 0.0.7

* Deprecate passing wallet address via constructor as fields will be made final
Expand Down
4 changes: 2 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Future<void> main() async {
final Chain chain = Chain(
ethRpcUrl: rpcUrl,
bundlerUrl: bundlerUrl,
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
accountFactory:
EthereumAddress.fromHex("0xCCaE5F64307D86346B83E55e7865f77906F9c7b4"),
chainId: 1337,
Expand Down Expand Up @@ -81,7 +81,7 @@ Future<void> main() async {
print("account nonce: ${nonce.toInt()}");

// check if a smart wallet has been deployed
final bool deployed = await simpleSmartAccount.deployed;
final bool deployed = await simpleSmartAccount.isDeployed;
print("account deployed: $deployed");

// get the init code of the smart wallet
Expand Down
70 changes: 36 additions & 34 deletions lib/src/4337/chains.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@ class Chain {
EthereumAddress? accountFactory;
String? ethRpcUrl;
String? bundlerUrl;
String? paymasterUrl;

Chain({
required this.chainId,
required this.explorer,
required this.entrypoint,
this.accountFactory,
this.ethRpcUrl,
this.bundlerUrl,
});
Chain(
{required this.chainId,
required this.explorer,
required this.entrypoint,
this.accountFactory,
this.ethRpcUrl,
this.bundlerUrl,
this.paymasterUrl});

/// asserts that [ethRpcUrl] and [bundlerUrl] is provided
Chain validate() {
require(isURL(ethRpcUrl),
"Chain Congig Error: please provide a valid eth rpc url");
"Chain Config Error: please provide a valid eth rpc url");
require(isURL(bundlerUrl),
"Chain Config Error: please provide a valid bundler url");
require(accountFactory != null,
Expand All @@ -36,133 +37,133 @@ class Chains {
chainId: 1,
explorer: "https://etherscan.io/",
ethRpcUrl: "https://rpc.ankr.com/eth",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.polygon: Chain(
chainId: 137,
explorer: "https://polygonscan.com/",
ethRpcUrl: "https://polygon-rpc.com/",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.optimism: Chain(
chainId: 10,
explorer: "https://explorer.optimism.io",
ethRpcUrl: "https://mainnet.optimism.io",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.base: Chain(
chainId: 8453,
explorer: "https://basescan.org",
ethRpcUrl: "https://mainnet.base.org",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.arbitrumOne: Chain(
chainId: 42161,
explorer: "https://arbiscan.io/",
ethRpcUrl: "https://arb1.arbitrum.io/rpc",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.mantle: Chain(
chainId: 5000,
explorer: "https://explorer.mantle.xyz/",
ethRpcUrl: "https://rpc.mantle.xyz/",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.linea: Chain(
chainId: 59144,
explorer: "https://lineascan.build/",
ethRpcUrl: "https://rpc.linea.build",
entrypoint: Constants.entrypoint),
entrypoint: Constants.entrypointv06),
Network.avalanche: Chain(
chainId: 43114,
explorer: "https://snowtrace.io/",
ethRpcUrl: "https://api.avax.network/ext/bc/C/rpc",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.gnosis: Chain(
chainId: 100,
explorer: "https://gnosisscan.io/",
ethRpcUrl: "https://rpc.ankr.com/gnosis",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.celo: Chain(
chainId: 42220,
explorer: "https://celoscan.io/",
ethRpcUrl: "https://forno.celo.org",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.fantom: Chain(
chainId: 250,
explorer: "https://ftmscan.com/",
ethRpcUrl: "https://rpc.fantom.network",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.opBnB: Chain(
chainId: 204,
explorer: "http://opbnbscan.com/",
ethRpcUrl: "https://opbnb-mainnet-rpc.bnbchain.org",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.arbitrumNova: Chain(
chainId: 42170,
explorer: "https://nova.arbiscan.io/",
ethRpcUrl: "https://nova.arbitrum.io/rpc",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.polygonzkEvm: Chain(
chainId: 1101,
explorer: "https://zkevm.polygonscan.com/",
ethRpcUrl: "https://polygonzkevm-mainnet.g.alchemy.com/v2/demo",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.scroll: Chain(
chainId: 534352,
explorer: "https://scrollscan.com/",
ethRpcUrl: "https://rpc.scroll.io/",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.mode: Chain(
chainId: 34443,
explorer: "https://explorer.mode.network/",
ethRpcUrl: "https://mainnet.mode.network/",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.sepolia: Chain(
chainId: 11155111,
explorer: "https://sepolia.etherscan.io/",
ethRpcUrl: "https://rpc.sepolia.org",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.mumbai: Chain(
chainId: 80001,
explorer: "https://mumbai.polygonscan.com/",
ethRpcUrl: "https://rpc-mumbai.maticvigil.com/",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.baseTestent: Chain(
chainId: 84531,
explorer: "https://sepolia.basescan.org",
ethRpcUrl: "https://api-sepolia.basescan.org/api",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.fuji: Chain(
chainId: 43113,
explorer: "https://testnet.snowtrace.io/",
ethRpcUrl: "https://api.avax-test.network/ext/bc/C/rpc",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.katla: Chain(
chainId: 167008,
explorer: "https://explorer.katla.taiko.xyz/",
ethRpcUrl: "https://rpc.katla.taiko.xyz",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
),
Network.localhost: Chain(
chainId: 1337,
explorer: "http://localhost:8545",
ethRpcUrl: "http://localhost:8545",
bundlerUrl: "http://localhost:3000/rpc",
entrypoint: Constants.entrypoint,
entrypoint: Constants.entrypointv06,
)
};

Expand All @@ -174,9 +175,10 @@ class Chains {
}

class Constants {
static EthereumAddress entrypoint = EthereumAddress.fromHex(
"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
enforceEip55: true);
static EthereumAddress entrypointv06 =
EthereumAddress.fromHex("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789");
static EthereumAddress entrypoint =
EthereumAddress.fromHex("0x0000000071727De22E5E9d8BAf0edAc6f37da032");
static EthereumAddress zeroAddress =
EthereumAddress.fromHex("0x0000000000000000000000000000000000000000");

Expand Down
54 changes: 52 additions & 2 deletions lib/src/4337/paymaster.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
part of '../../variance.dart';

abstract class PaymasterBase {}
class PaymasterResponse {
final Uint8List paymasterAndData;
final BigInt preVerificationGas;
final BigInt verificationGasLimit;
final BigInt callGasLimit;

class Paymaster {}
PaymasterResponse({
required this.paymasterAndData,
required this.preVerificationGas,
required this.verificationGasLimit,
required this.callGasLimit,
});

factory PaymasterResponse.fromMap(Map<String, dynamic> map) {
return PaymasterResponse(
paymasterAndData: hexToBytes(map['paymasterAndData']),
preVerificationGas: BigInt.parse(map['preVerificationGas']),
verificationGasLimit: BigInt.parse(map['verificationGasLimit']),
callGasLimit: BigInt.parse(map['callGasLimit']),
);
}
}

class Paymaster {
final RPCProviderBase _rpc;
final Chain _chain;
Map<String, String>? _context;

set context(Map<String, String>? context) {
_context = context;
}

Paymaster(this._chain, this._rpc, [this._context]);

Future<UserOperation> intercept(UserOperation operation) async {
final paymasterResponse = await sponsorUserOperation(
operation.toMap(), _chain.entrypoint, _context);

return operation.copyWith(
paymasterAndData: paymasterResponse.paymasterAndData,
preVerificationGas: paymasterResponse.preVerificationGas,
verificationGasLimit: paymasterResponse.verificationGasLimit,
callGasLimit: paymasterResponse.callGasLimit,
);
}

Future<PaymasterResponse> sponsorUserOperation(Map<String, dynamic> userOp,
EthereumAddress entrypoint, Map<String, String>? context) async {
final response = await _rpc.send<Map<String, dynamic>>(
'pm_sponsorUserOperation', [userOp, entrypoint.hex, context]);
return PaymasterResponse.fromMap(response);
}
}
Loading

0 comments on commit ad157be

Please sign in to comment.