near-safe 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/lib/bundler.d.ts +4 -1
- package/dist/cjs/lib/bundler.js +15 -5
- package/dist/cjs/lib/multisend.d.ts +3 -0
- package/dist/cjs/lib/multisend.js +40 -0
- package/dist/cjs/lib/safe.d.ts +9 -9
- package/dist/cjs/lib/safe.js +22 -18
- package/dist/cjs/tx-manager.d.ts +24 -23
- package/dist/cjs/tx-manager.js +63 -48
- package/dist/cjs/types.d.ts +34 -27
- package/dist/cjs/types.js +6 -0
- package/dist/cjs/util.d.ts +8 -7
- package/dist/cjs/util.js +10 -10
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lib/bundler.d.ts +4 -1
- package/dist/esm/lib/bundler.js +17 -5
- package/dist/esm/lib/multisend.d.ts +3 -0
- package/dist/esm/lib/multisend.js +36 -0
- package/dist/esm/lib/safe.d.ts +9 -9
- package/dist/esm/lib/safe.js +22 -18
- package/dist/esm/tx-manager.d.ts +24 -23
- package/dist/esm/tx-manager.js +67 -53
- package/dist/esm/types.d.ts +34 -27
- package/dist/esm/types.js +5 -1
- package/dist/esm/util.d.ts +8 -7
- package/dist/esm/util.js +10 -10
- package/package.json +10 -4
- package/dist/cjs/lib/near.d.ts +0 -3
- package/dist/cjs/lib/near.js +0 -14
- package/dist/esm/lib/near.d.ts +0 -3
- package/dist/esm/lib/near.js +0 -11
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
@@ -3,7 +3,10 @@ import { GasPrices, PaymasterData, UnsignedUserOperation, UserOperation, UserOpe
|
|
3
3
|
export declare class Erc4337Bundler {
|
4
4
|
provider: ethers.JsonRpcProvider;
|
5
5
|
entryPointAddress: string;
|
6
|
-
|
6
|
+
apiKey: string;
|
7
|
+
chainId: number;
|
8
|
+
constructor(entryPointAddress: string, apiKey: string, chainId: number);
|
9
|
+
client(chainId: number): ethers.JsonRpcProvider;
|
7
10
|
getPaymasterData(rawUserOp: UnsignedUserOperation, usePaymaster: boolean, safeNotDeployed: boolean): Promise<PaymasterData>;
|
8
11
|
sendUserOperation(userOp: UserOperation): Promise<string>;
|
9
12
|
getGasPrice(): Promise<GasPrices>;
|
package/dist/esm/lib/bundler.js
CHANGED
@@ -1,11 +1,23 @@
|
|
1
|
+
// TODO: Ethers dependency is only for Generic HTTP Provider
|
1
2
|
import { ethers } from "ethers";
|
3
|
+
import { toHex } from "viem";
|
2
4
|
import { PLACEHOLDER_SIG } from "../util";
|
5
|
+
function bundlerUrl(chainId, apikey) {
|
6
|
+
return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
|
7
|
+
}
|
3
8
|
export class Erc4337Bundler {
|
4
9
|
provider;
|
5
10
|
entryPointAddress;
|
6
|
-
|
11
|
+
apiKey;
|
12
|
+
chainId;
|
13
|
+
constructor(entryPointAddress, apiKey, chainId) {
|
7
14
|
this.entryPointAddress = entryPointAddress;
|
8
|
-
this.
|
15
|
+
this.apiKey = apiKey;
|
16
|
+
this.chainId = chainId;
|
17
|
+
this.provider = new ethers.JsonRpcProvider(bundlerUrl(chainId, apiKey));
|
18
|
+
}
|
19
|
+
client(chainId) {
|
20
|
+
return new ethers.JsonRpcProvider(bundlerUrl(chainId, this.apiKey));
|
9
21
|
}
|
10
22
|
async getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed) {
|
11
23
|
// TODO: Keep this option out of the bundler
|
@@ -51,8 +63,8 @@ export class Erc4337Bundler {
|
|
51
63
|
// TODO(bh2smith) Should probably get reasonable estimates here:
|
52
64
|
const defaultPaymasterData = (safeNotDeployed) => {
|
53
65
|
return {
|
54
|
-
verificationGasLimit:
|
55
|
-
callGasLimit:
|
56
|
-
preVerificationGas:
|
66
|
+
verificationGasLimit: toHex(safeNotDeployed ? 500000 : 100000),
|
67
|
+
callGasLimit: toHex(100000),
|
68
|
+
preVerificationGas: toHex(100000),
|
57
69
|
};
|
58
70
|
};
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { encodeFunctionData, encodePacked, parseAbi, size, } from "viem";
|
2
|
+
import { OperationType } from "../types";
|
3
|
+
export const MULTI_SEND_ABI = ["function multiSend(bytes memory transactions)"];
|
4
|
+
const MULTISEND_141 = "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526";
|
5
|
+
const MULTISEND_CALLONLY_141 = "0x9641d764fc13c8B624c04430C7356C1C7C8102e2";
|
6
|
+
/// Encodes the transaction as packed bytes of:
|
7
|
+
/// - `operation` as a `uint8` with `0` for a `call` or `1` for a `delegatecall` (=> 1 byte),
|
8
|
+
/// - `to` as an `address` (=> 20 bytes),
|
9
|
+
/// - `value` as a `uint256` (=> 32 bytes),
|
10
|
+
/// - length of `data` as a `uint256` (=> 32 bytes),
|
11
|
+
/// - `data` as `bytes`.
|
12
|
+
const encodeMetaTx = (tx) => encodePacked(["uint8", "address", "uint256", "uint256", "bytes"], [
|
13
|
+
tx.operation || OperationType.Call,
|
14
|
+
tx.to,
|
15
|
+
BigInt(tx.value),
|
16
|
+
BigInt(size(tx.data)),
|
17
|
+
tx.data,
|
18
|
+
]);
|
19
|
+
const remove0x = (hexString) => hexString.slice(2);
|
20
|
+
// Encodes a batch of module transactions into a single multiSend module transaction.
|
21
|
+
// A module transaction is an object with fields corresponding to a Gnosis Safe's (i.e., Zodiac IAvatar's) `execTransactionFromModule` method parameters.
|
22
|
+
export function encodeMulti(transactions, multiSendContractAddress = transactions.some((t) => t.operation === OperationType.DelegateCall)
|
23
|
+
? MULTISEND_141
|
24
|
+
: MULTISEND_CALLONLY_141) {
|
25
|
+
const encodedTransactions = "0x" + transactions.map(encodeMetaTx).map(remove0x).join("");
|
26
|
+
return {
|
27
|
+
operation: OperationType.DelegateCall,
|
28
|
+
to: multiSendContractAddress,
|
29
|
+
value: "0x00",
|
30
|
+
data: encodeFunctionData({
|
31
|
+
abi: parseAbi(MULTI_SEND_ABI),
|
32
|
+
functionName: "multiSend",
|
33
|
+
args: [encodedTransactions],
|
34
|
+
}),
|
35
|
+
};
|
36
|
+
}
|
package/dist/esm/lib/safe.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ethers } from "ethers";
|
2
|
-
import {
|
3
|
-
import { MetaTransaction } from "
|
2
|
+
import { Address, Hash, Hex } from "viem";
|
3
|
+
import { GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
|
4
4
|
/**
|
5
5
|
* All contracts used in account creation & execution
|
6
6
|
*/
|
@@ -12,13 +12,13 @@ export declare class ContractSuite {
|
|
12
12
|
moduleSetup: ethers.Contract;
|
13
13
|
entryPoint: ethers.Contract;
|
14
14
|
constructor(provider: ethers.JsonRpcProvider, singleton: ethers.Contract, proxyFactory: ethers.Contract, m4337: ethers.Contract, moduleSetup: ethers.Contract, entryPoint: ethers.Contract);
|
15
|
-
static init(
|
16
|
-
addressForSetup(setup: ethers.BytesLike, saltNonce?: string): Promise<
|
17
|
-
getSetup(owners: string[]): Promise<
|
18
|
-
getOpHash(unsignedUserOp: UserOperation): Promise<
|
15
|
+
static init(): Promise<ContractSuite>;
|
16
|
+
addressForSetup(setup: ethers.BytesLike, saltNonce?: string): Promise<Address>;
|
17
|
+
getSetup(owners: string[]): Promise<Hex>;
|
18
|
+
getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
|
19
19
|
factoryDataForSetup(safeNotDeployed: boolean, setup: string, safeSaltNonce: string): {
|
20
|
-
factory?:
|
21
|
-
factoryData?:
|
20
|
+
factory?: Address;
|
21
|
+
factoryData?: Hex;
|
22
22
|
};
|
23
|
-
buildUserOp(txData: MetaTransaction, safeAddress:
|
23
|
+
buildUserOp(txData: MetaTransaction, safeAddress: Address, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
|
24
24
|
}
|
package/dist/esm/lib/safe.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { ethers } from "ethers";
|
2
1
|
import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from "@safe-global/safe-deployments";
|
3
2
|
import { getSafe4337ModuleDeployment, getSafeModuleSetupDeployment, } from "@safe-global/safe-modules-deployments";
|
3
|
+
import { ethers } from "ethers";
|
4
4
|
import { PLACEHOLDER_SIG, packGas, packPaymasterData } from "../util";
|
5
5
|
/**
|
6
6
|
* All contracts used in account creation & execution
|
@@ -20,16 +20,12 @@ export class ContractSuite {
|
|
20
20
|
this.moduleSetup = moduleSetup;
|
21
21
|
this.entryPoint = entryPoint;
|
22
22
|
}
|
23
|
-
static async init(
|
23
|
+
static async init() {
|
24
|
+
// TODO - this is a cheeky hack.
|
25
|
+
const provider = new ethers.JsonRpcProvider("https://rpc2.sepolia.org");
|
24
26
|
const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
|
25
27
|
const m4337Deployment = async (fn) => {
|
26
|
-
|
27
|
-
return await getDeployment(fn, { provider, version: "0.3.0" });
|
28
|
-
}
|
29
|
-
catch (error) {
|
30
|
-
console.warn(error.message, "using v0.2.0");
|
31
|
-
return getDeployment(fn, { provider, version: "0.2.0" });
|
32
|
-
}
|
28
|
+
return getDeployment(fn, { provider, version: "0.3.0" });
|
33
29
|
};
|
34
30
|
// Need this first to get entryPoint address
|
35
31
|
const m4337 = await m4337Deployment(getSafe4337ModuleDeployment);
|
@@ -76,16 +72,15 @@ export class ContractSuite {
|
|
76
72
|
]);
|
77
73
|
return setup;
|
78
74
|
}
|
79
|
-
async getOpHash(unsignedUserOp
|
80
|
-
|
81
|
-
) {
|
75
|
+
async getOpHash(unsignedUserOp) {
|
76
|
+
const { factory, factoryData, verificationGasLimit, callGasLimit, maxPriorityFeePerGas, maxFeePerGas, } = unsignedUserOp;
|
82
77
|
return this.m4337.getOperationHash({
|
83
78
|
...unsignedUserOp,
|
84
|
-
initCode:
|
85
|
-
? ethers.solidityPacked(["address", "bytes"], [
|
79
|
+
initCode: factory
|
80
|
+
? ethers.solidityPacked(["address", "bytes"], [factory, factoryData])
|
86
81
|
: "0x",
|
87
|
-
accountGasLimits: packGas(
|
88
|
-
gasFees: packGas(
|
82
|
+
accountGasLimits: packGas(verificationGasLimit, callGasLimit),
|
83
|
+
gasFees: packGas(maxPriorityFeePerGas, maxFeePerGas),
|
89
84
|
paymasterAndData: packPaymasterData(unsignedUserOp),
|
90
85
|
signature: PLACEHOLDER_SIG,
|
91
86
|
});
|
@@ -118,8 +113,17 @@ export class ContractSuite {
|
|
118
113
|
async function getDeployment(fn, { provider, version }) {
|
119
114
|
const { chainId } = await provider.getNetwork();
|
120
115
|
const deployment = fn({ version });
|
121
|
-
if (!deployment
|
116
|
+
if (!deployment) {
|
122
117
|
throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
|
123
118
|
}
|
124
|
-
|
119
|
+
let address = deployment.networkAddresses[`${chainId}`];
|
120
|
+
if (!address) {
|
121
|
+
// console.warn(
|
122
|
+
// `Deployment asset ${fn.name} not listed on chainId ${chainId}, using likely fallback. For more info visit https://github.com/safe-global/safe-modules-deployments`
|
123
|
+
// );
|
124
|
+
// TODO: This is a cheeky hack. Real solution proposed in
|
125
|
+
// https://github.com/Mintbase/near-safe/issues/42
|
126
|
+
address = deployment.networkAddresses["11155111"];
|
127
|
+
}
|
128
|
+
return new ethers.Contract(address, deployment.abi, provider);
|
125
129
|
}
|
package/dist/esm/tx-manager.d.ts
CHANGED
@@ -1,42 +1,43 @@
|
|
1
|
-
import {
|
1
|
+
import { FinalExecutionOutcome } from "near-api-js/lib/providers";
|
2
2
|
import { NearEthAdapter, NearEthTxData, BaseTx } from "near-ca";
|
3
|
+
import { Address, Hash, Hex } from "viem";
|
3
4
|
import { Erc4337Bundler } from "./lib/bundler";
|
4
|
-
import { UserOperation, UserOperationReceipt } from "./types";
|
5
|
-
import { MetaTransaction } from "ethers-multisend";
|
6
5
|
import { ContractSuite } from "./lib/safe";
|
6
|
+
import { MetaTransaction, UserOperation, UserOperationReceipt } from "./types";
|
7
7
|
export declare class TransactionManager {
|
8
|
-
readonly provider: ethers.JsonRpcProvider;
|
9
8
|
readonly nearAdapter: NearEthAdapter;
|
9
|
+
readonly address: Address;
|
10
|
+
readonly entryPointAddress: Address;
|
10
11
|
private safePack;
|
11
|
-
private bundler;
|
12
12
|
private setup;
|
13
|
-
|
14
|
-
readonly chainId: number;
|
13
|
+
private pimlicoKey;
|
15
14
|
private safeSaltNonce;
|
16
|
-
private
|
17
|
-
constructor(
|
15
|
+
private deployedChains;
|
16
|
+
constructor(nearAdapter: NearEthAdapter, safePack: ContractSuite, pimlicoKey: string, setup: string, safeAddress: Address, entryPointAddress: Address, safeSaltNonce: string);
|
18
17
|
static create(config: {
|
19
|
-
|
18
|
+
accountId: string;
|
19
|
+
mpcContractId: string;
|
20
20
|
pimlicoKey: string;
|
21
|
-
|
21
|
+
privateKey?: string;
|
22
22
|
safeSaltNonce?: string;
|
23
23
|
}): Promise<TransactionManager>;
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
pimlicoKey: string;
|
28
|
-
}): Promise<TransactionManager>;
|
29
|
-
get safeNotDeployed(): boolean;
|
30
|
-
get mpcAddress(): `0x${string}`;
|
31
|
-
getSafeBalance(): Promise<bigint>;
|
24
|
+
get mpcAddress(): Address;
|
25
|
+
getBalance(chainId: number): Promise<bigint>;
|
26
|
+
bundlerForChainId(chainId: number): Erc4337Bundler;
|
32
27
|
buildTransaction(args: {
|
28
|
+
chainId: number;
|
33
29
|
transactions: MetaTransaction[];
|
34
30
|
usePaymaster: boolean;
|
35
31
|
}): Promise<UserOperation>;
|
36
|
-
signTransaction(safeOpHash:
|
37
|
-
opHash(userOp: UserOperation): Promise<
|
32
|
+
signTransaction(safeOpHash: Hex): Promise<Hex>;
|
33
|
+
opHash(userOp: UserOperation): Promise<Hash>;
|
38
34
|
encodeSignRequest(tx: BaseTx): Promise<NearEthTxData>;
|
39
|
-
executeTransaction(userOp: UserOperation): Promise<UserOperationReceipt>;
|
35
|
+
executeTransaction(chainId: number, userOp: UserOperation): Promise<UserOperationReceipt>;
|
36
|
+
safeDeployed(chainId: number): Promise<boolean>;
|
40
37
|
addOwnerTx(address: string): MetaTransaction;
|
41
|
-
safeSufficientlyFunded(transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
|
38
|
+
safeSufficientlyFunded(chainId: number, transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
|
39
|
+
broadcastEvm(chainId: number, outcome: FinalExecutionOutcome, unsignedUserOp: UserOperation): Promise<{
|
40
|
+
signature: Hex;
|
41
|
+
receipt: UserOperationReceipt;
|
42
|
+
}>;
|
42
43
|
}
|
package/dist/esm/tx-manager.js
CHANGED
@@ -1,88 +1,76 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
1
|
+
import { Network, setupAdapter, signatureFromOutcome, } from "near-ca";
|
2
|
+
import { serializeSignature } from "viem";
|
3
3
|
import { Erc4337Bundler } from "./lib/bundler";
|
4
|
-
import {
|
5
|
-
import { getNearSignature } from "./lib/near";
|
6
|
-
import { encodeMulti } from "ethers-multisend";
|
4
|
+
import { encodeMulti } from "./lib/multisend";
|
7
5
|
import { ContractSuite } from "./lib/safe";
|
6
|
+
import { packSignature } from "./util";
|
8
7
|
export class TransactionManager {
|
9
|
-
provider;
|
10
8
|
nearAdapter;
|
9
|
+
address;
|
10
|
+
entryPointAddress;
|
11
11
|
safePack;
|
12
|
-
bundler;
|
13
12
|
setup;
|
14
|
-
|
15
|
-
chainId;
|
13
|
+
pimlicoKey;
|
16
14
|
safeSaltNonce;
|
17
|
-
|
18
|
-
constructor(
|
19
|
-
this.provider = provider;
|
15
|
+
deployedChains;
|
16
|
+
constructor(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, safeSaltNonce) {
|
20
17
|
this.nearAdapter = nearAdapter;
|
21
18
|
this.safePack = safePack;
|
22
|
-
this.
|
19
|
+
this.pimlicoKey = pimlicoKey;
|
20
|
+
this.entryPointAddress = entryPointAddress;
|
23
21
|
this.setup = setup;
|
24
|
-
this.chainId = chainId;
|
25
22
|
this.address = safeAddress;
|
26
23
|
this.safeSaltNonce = safeSaltNonce;
|
27
|
-
this.
|
24
|
+
this.deployedChains = new Set();
|
28
25
|
}
|
29
26
|
static async create(config) {
|
30
|
-
const {
|
31
|
-
const
|
32
|
-
|
33
|
-
|
27
|
+
const { pimlicoKey } = config;
|
28
|
+
const [nearAdapter, safePack] = await Promise.all([
|
29
|
+
setupAdapter({ ...config }),
|
30
|
+
ContractSuite.init(),
|
31
|
+
]);
|
34
32
|
console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
|
35
|
-
const bundler = new Erc4337Bundler(`https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoKey}`, await safePack.entryPoint.getAddress());
|
36
33
|
const setup = await safePack.getSetup([nearAdapter.address]);
|
37
34
|
const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
|
38
|
-
const
|
39
|
-
console.log(`Safe Address: ${safeAddress}
|
40
|
-
return new TransactionManager(
|
41
|
-
}
|
42
|
-
static async fromChainId(args) {
|
43
|
-
const { pimlicoKey, nearAdapter } = args;
|
44
|
-
return TransactionManager.create({
|
45
|
-
ethRpc: Network.fromChainId(args.chainId).rpcUrl,
|
46
|
-
pimlicoKey,
|
47
|
-
nearAdapter,
|
48
|
-
});
|
49
|
-
}
|
50
|
-
get safeNotDeployed() {
|
51
|
-
return this._safeNotDeployed;
|
35
|
+
const entryPointAddress = (await safePack.entryPoint.getAddress());
|
36
|
+
console.log(`Safe Address: ${safeAddress}`);
|
37
|
+
return new TransactionManager(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, config.safeSaltNonce || "0");
|
52
38
|
}
|
53
39
|
get mpcAddress() {
|
54
40
|
return this.nearAdapter.address;
|
55
41
|
}
|
56
|
-
async
|
57
|
-
|
42
|
+
async getBalance(chainId) {
|
43
|
+
const provider = Network.fromChainId(chainId).client;
|
44
|
+
return await provider.getBalance({ address: this.address });
|
45
|
+
}
|
46
|
+
bundlerForChainId(chainId) {
|
47
|
+
return new Erc4337Bundler(this.entryPointAddress, this.pimlicoKey, chainId);
|
58
48
|
}
|
59
49
|
async buildTransaction(args) {
|
60
|
-
const { transactions, usePaymaster } = args;
|
61
|
-
const
|
62
|
-
|
50
|
+
const { transactions, usePaymaster, chainId } = args;
|
51
|
+
const bundler = this.bundlerForChainId(chainId);
|
52
|
+
const gasFees = (await bundler.getGasPrice()).fast;
|
63
53
|
// Build Singular MetaTransaction for Multisend from transaction list.
|
64
54
|
if (transactions.length === 0) {
|
65
55
|
throw new Error("Empty transaction set!");
|
66
56
|
}
|
67
57
|
const tx = transactions.length > 1 ? encodeMulti(transactions) : transactions[0];
|
68
|
-
const
|
69
|
-
const
|
58
|
+
const safeNotDeployed = !(await this.safeDeployed(chainId));
|
59
|
+
const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, safeNotDeployed, this.safeSaltNonce);
|
60
|
+
const paymasterData = await bundler.getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed);
|
70
61
|
const unsignedUserOp = { ...rawUserOp, ...paymasterData };
|
71
62
|
return unsignedUserOp;
|
72
63
|
}
|
73
64
|
async signTransaction(safeOpHash) {
|
74
|
-
const signature = await
|
65
|
+
const signature = await this.nearAdapter.sign(safeOpHash);
|
75
66
|
return packSignature(signature);
|
76
67
|
}
|
77
68
|
async opHash(userOp) {
|
78
69
|
return this.safePack.getOpHash(userOp);
|
79
70
|
}
|
80
71
|
async encodeSignRequest(tx) {
|
81
|
-
// TODO - This is sloppy and ignores ChainId!
|
82
|
-
if (tx.chainId !== this.chainId) {
|
83
|
-
throw new Error(`Transaciton request for invalid ChainId ${tx.chainId} != ${this.chainId}`);
|
84
|
-
}
|
85
72
|
const unsignedUserOp = await this.buildTransaction({
|
73
|
+
chainId: tx.chainId,
|
86
74
|
transactions: [
|
87
75
|
{
|
88
76
|
to: tx.to,
|
@@ -103,16 +91,27 @@ export class TransactionManager {
|
|
103
91
|
evmMessage: JSON.stringify(unsignedUserOp),
|
104
92
|
};
|
105
93
|
}
|
106
|
-
async executeTransaction(userOp) {
|
107
|
-
const
|
94
|
+
async executeTransaction(chainId, userOp) {
|
95
|
+
const bundler = this.bundlerForChainId(chainId);
|
96
|
+
const userOpHash = await bundler.sendUserOperation(userOp);
|
108
97
|
console.log("UserOp Hash", userOpHash);
|
109
|
-
const userOpReceipt = await
|
98
|
+
const userOpReceipt = await bundler.getUserOpReceipt(userOpHash);
|
110
99
|
console.log("userOp Receipt", userOpReceipt);
|
111
100
|
// Update safeNotDeployed after the first transaction
|
112
|
-
this.
|
113
|
-
(await this.provider.getCode(this.address)) === "0x";
|
101
|
+
this.safeDeployed(chainId);
|
114
102
|
return userOpReceipt;
|
115
103
|
}
|
104
|
+
async safeDeployed(chainId) {
|
105
|
+
if (chainId in this.deployedChains) {
|
106
|
+
return true;
|
107
|
+
}
|
108
|
+
const provider = Network.fromChainId(chainId).client;
|
109
|
+
const deployed = (await provider.getCode({ address: this.address })) !== "0x";
|
110
|
+
if (deployed) {
|
111
|
+
this.deployedChains.add(chainId);
|
112
|
+
}
|
113
|
+
return deployed;
|
114
|
+
}
|
116
115
|
addOwnerTx(address) {
|
117
116
|
return {
|
118
117
|
to: this.address,
|
@@ -120,12 +119,27 @@ export class TransactionManager {
|
|
120
119
|
data: this.safePack.singleton.interface.encodeFunctionData("addOwnerWithThreshold", [address, 1]),
|
121
120
|
};
|
122
121
|
}
|
123
|
-
async safeSufficientlyFunded(transactions, gasCost) {
|
122
|
+
async safeSufficientlyFunded(chainId, transactions, gasCost) {
|
124
123
|
const txValue = transactions.reduce((acc, tx) => acc + BigInt(tx.value), 0n);
|
125
124
|
if (txValue + gasCost === 0n) {
|
126
125
|
return true;
|
127
126
|
}
|
128
|
-
const safeBalance = await this.
|
127
|
+
const safeBalance = await this.getBalance(chainId);
|
129
128
|
return txValue + gasCost < safeBalance;
|
130
129
|
}
|
130
|
+
async broadcastEvm(chainId, outcome, unsignedUserOp) {
|
131
|
+
const signature = packSignature(serializeSignature(signatureFromOutcome(outcome)));
|
132
|
+
try {
|
133
|
+
return {
|
134
|
+
signature,
|
135
|
+
receipt: await this.executeTransaction(chainId, {
|
136
|
+
...unsignedUserOp,
|
137
|
+
signature,
|
138
|
+
}),
|
139
|
+
};
|
140
|
+
}
|
141
|
+
catch (error) {
|
142
|
+
throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
|
143
|
+
}
|
144
|
+
}
|
131
145
|
}
|
package/dist/esm/types.d.ts
CHANGED
@@ -1,30 +1,30 @@
|
|
1
|
-
import {
|
1
|
+
import { Address, Hex } from "viem";
|
2
2
|
export interface UnsignedUserOperation {
|
3
|
-
sender:
|
3
|
+
sender: Address;
|
4
4
|
nonce: string;
|
5
|
-
factory?:
|
6
|
-
factoryData?:
|
7
|
-
callData:
|
8
|
-
maxPriorityFeePerGas:
|
9
|
-
maxFeePerGas:
|
5
|
+
factory?: Address;
|
6
|
+
factoryData?: Hex;
|
7
|
+
callData: Hex;
|
8
|
+
maxPriorityFeePerGas: Hex;
|
9
|
+
maxFeePerGas: Hex;
|
10
10
|
}
|
11
11
|
/**
|
12
12
|
* Supported Representation of UserOperation for EntryPoint v0.7
|
13
13
|
*/
|
14
14
|
export interface UserOperation extends UnsignedUserOperation {
|
15
|
-
verificationGasLimit:
|
16
|
-
callGasLimit:
|
17
|
-
preVerificationGas:
|
18
|
-
signature?:
|
15
|
+
verificationGasLimit: Hex;
|
16
|
+
callGasLimit: Hex;
|
17
|
+
preVerificationGas: Hex;
|
18
|
+
signature?: Hex;
|
19
19
|
}
|
20
20
|
export interface PaymasterData {
|
21
|
-
paymaster?:
|
22
|
-
paymasterData?:
|
23
|
-
paymasterVerificationGasLimit?:
|
24
|
-
paymasterPostOpGasLimit?:
|
25
|
-
verificationGasLimit:
|
26
|
-
callGasLimit:
|
27
|
-
preVerificationGas:
|
21
|
+
paymaster?: Address;
|
22
|
+
paymasterData?: Hex;
|
23
|
+
paymasterVerificationGasLimit?: Hex;
|
24
|
+
paymasterPostOpGasLimit?: Hex;
|
25
|
+
verificationGasLimit: Hex;
|
26
|
+
callGasLimit: Hex;
|
27
|
+
preVerificationGas: Hex;
|
28
28
|
}
|
29
29
|
export interface UserOptions {
|
30
30
|
usePaymaster: boolean;
|
@@ -32,10 +32,7 @@ export interface UserOptions {
|
|
32
32
|
mpcContractId: string;
|
33
33
|
recoveryAddress?: string;
|
34
34
|
}
|
35
|
-
export type
|
36
|
-
export type Address = ethers.AddressLike;
|
37
|
-
export type Hex = `0x${string}`;
|
38
|
-
export type Hash = `0x${string}`;
|
35
|
+
export type TxStatus = "success" | "reverted";
|
39
36
|
interface Log {
|
40
37
|
logIndex: string;
|
41
38
|
transactionIndex: string;
|
@@ -49,19 +46,19 @@ interface Log {
|
|
49
46
|
interface Receipt {
|
50
47
|
transactionHash: Hex;
|
51
48
|
transactionIndex: bigint;
|
52
|
-
blockHash:
|
49
|
+
blockHash: Hex;
|
53
50
|
blockNumber: bigint;
|
54
51
|
from: Address;
|
55
|
-
to
|
52
|
+
to?: Address;
|
56
53
|
cumulativeGasUsed: bigint;
|
57
|
-
status:
|
54
|
+
status: TxStatus;
|
58
55
|
gasUsed: bigint;
|
59
|
-
contractAddress
|
56
|
+
contractAddress?: Address;
|
60
57
|
logsBloom: Hex;
|
61
58
|
effectiveGasPrice: bigint;
|
62
59
|
}
|
63
60
|
export type UserOperationReceipt = {
|
64
|
-
userOpHash:
|
61
|
+
userOpHash: Hex;
|
65
62
|
entryPoint: Address;
|
66
63
|
sender: Address;
|
67
64
|
nonce: bigint;
|
@@ -82,4 +79,14 @@ export interface GasPrice {
|
|
82
79
|
maxFeePerGas: Hex;
|
83
80
|
maxPriorityFeePerGas: Hex;
|
84
81
|
}
|
82
|
+
export declare enum OperationType {
|
83
|
+
Call = 0,
|
84
|
+
DelegateCall = 1
|
85
|
+
}
|
86
|
+
export interface MetaTransaction {
|
87
|
+
readonly to: string;
|
88
|
+
readonly value: string;
|
89
|
+
readonly data: string;
|
90
|
+
readonly operation?: OperationType;
|
91
|
+
}
|
85
92
|
export {};
|
package/dist/esm/types.js
CHANGED
package/dist/esm/util.d.ts
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
import { PaymasterData } from "./types";
|
3
|
-
|
4
|
-
|
5
|
-
export declare const packGas: (hi:
|
6
|
-
export declare function packSignature(signature: string
|
7
|
-
export declare function packPaymasterData(data: PaymasterData):
|
1
|
+
import { Hex } from "viem";
|
2
|
+
import { PaymasterData, MetaTransaction } from "./types";
|
3
|
+
export declare const PLACEHOLDER_SIG: `0x${string}`;
|
4
|
+
type IntLike = Hex | bigint | string | number;
|
5
|
+
export declare const packGas: (hi: IntLike, lo: IntLike) => string;
|
6
|
+
export declare function packSignature(signature: `0x${string}`, validFrom?: number, validTo?: number): Hex;
|
7
|
+
export declare function packPaymasterData(data: PaymasterData): Hex;
|
8
8
|
export declare function containsValue(transactions: MetaTransaction[]): boolean;
|
9
|
+
export {};
|
package/dist/esm/util.js
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
import {
|
2
|
-
export const PLACEHOLDER_SIG =
|
3
|
-
export const packGas = (hi, lo) =>
|
1
|
+
import { concatHex, encodePacked, toHex } from "viem";
|
2
|
+
export const PLACEHOLDER_SIG = encodePacked(["uint48", "uint48"], [0, 0]);
|
3
|
+
export const packGas = (hi, lo) => encodePacked(["uint128", "uint128"], [BigInt(hi), BigInt(lo)]);
|
4
4
|
export function packSignature(signature, validFrom = 0, validTo = 0) {
|
5
|
-
return
|
5
|
+
return encodePacked(["uint48", "uint48", "bytes"], [validFrom, validTo, signature]);
|
6
6
|
}
|
7
7
|
export function packPaymasterData(data) {
|
8
|
-
return data.paymaster
|
9
|
-
?
|
8
|
+
return (data.paymaster
|
9
|
+
? concatHex([
|
10
10
|
data.paymaster,
|
11
|
-
|
12
|
-
|
11
|
+
toHex(BigInt(data.paymasterVerificationGasLimit || 0n), { size: 16 }),
|
12
|
+
toHex(BigInt(data.paymasterPostOpGasLimit || 0n), { size: 16 }),
|
13
13
|
data.paymasterData || "0x",
|
14
|
-
])
|
15
|
-
: "0x";
|
14
|
+
])
|
15
|
+
: "0x");
|
16
16
|
}
|
17
17
|
export function containsValue(transactions) {
|
18
18
|
return transactions.some((tx) => tx.value !== "0");
|