@deserialize/multi-vm-wallet 1.3.2 → 1.3.4
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/.claude/settings.local.json +2 -1
- package/dist/IChainWallet.d.ts +2 -0
- package/dist/IChainWallet.js.map +1 -1
- package/dist/constant.js +60 -16
- package/dist/constant.js.map +1 -1
- package/dist/evm/aa-service/index.d.ts +1 -1
- package/dist/evm/aa-service/index.js +1 -2
- package/dist/evm/aa-service/index.js.map +1 -1
- package/dist/evm/aa-service/lib/kernel-account.d.ts +1 -1
- package/dist/evm/aa-service/lib/kernel-account.js +22 -6
- package/dist/evm/aa-service/lib/kernel-account.js.map +1 -1
- package/dist/evm/aa-service/lib/session-keys.d.ts +14 -17
- package/dist/evm/aa-service/lib/session-keys.js +40 -58
- package/dist/evm/aa-service/lib/session-keys.js.map +1 -1
- package/dist/evm/aa-service/lib/type.d.ts +2 -1
- package/dist/evm/aa-service/lib/type.js.map +1 -1
- package/dist/evm/aa-service/services/account-abstraction.d.ts +3 -29
- package/dist/evm/aa-service/services/account-abstraction.js +3 -67
- package/dist/evm/aa-service/services/account-abstraction.js.map +1 -1
- package/dist/evm/aa-service/services/bundler.js +2 -1
- package/dist/evm/aa-service/services/bundler.js.map +1 -1
- package/dist/evm/evm.d.ts +163 -1
- package/dist/evm/evm.js +259 -0
- package/dist/evm/evm.js.map +1 -1
- package/dist/evm/smartWallet.d.ts +11 -43
- package/dist/evm/smartWallet.js +136 -116
- package/dist/evm/smartWallet.js.map +1 -1
- package/dist/evm/utils.js +0 -1
- package/dist/evm/utils.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/price.d.ts +2 -0
- package/dist/price.js +33 -0
- package/dist/price.js.map +1 -0
- package/dist/price.types.d.ts +38 -0
- package/dist/price.types.js +4 -0
- package/dist/price.types.js.map +1 -0
- package/dist/privacy/artifact-manager.d.ts +117 -0
- package/dist/privacy/artifact-manager.js +251 -0
- package/dist/privacy/artifact-manager.js.map +1 -0
- package/dist/privacy/broadcaster-client.d.ts +166 -0
- package/dist/privacy/broadcaster-client.js +261 -0
- package/dist/privacy/broadcaster-client.js.map +1 -0
- package/dist/privacy/index.d.ts +34 -0
- package/dist/privacy/index.js +56 -0
- package/dist/privacy/index.js.map +1 -0
- package/dist/privacy/network-config.d.ts +57 -0
- package/dist/privacy/network-config.js +118 -0
- package/dist/privacy/network-config.js.map +1 -0
- package/dist/privacy/poi-helper.d.ts +161 -0
- package/dist/privacy/poi-helper.js +249 -0
- package/dist/privacy/poi-helper.js.map +1 -0
- package/dist/privacy/railgun-engine.d.ts +135 -0
- package/dist/privacy/railgun-engine.js +205 -0
- package/dist/privacy/railgun-engine.js.map +1 -0
- package/dist/privacy/railgun-privacy-wallet.d.ts +288 -0
- package/dist/privacy/railgun-privacy-wallet.js +539 -0
- package/dist/privacy/railgun-privacy-wallet.js.map +1 -0
- package/dist/privacy/types.d.ts +229 -0
- package/dist/privacy/types.js +26 -0
- package/dist/privacy/types.js.map +1 -0
- package/dist/savings/savings-manager.d.ts +126 -0
- package/dist/savings/savings-manager.js +234 -0
- package/dist/savings/savings-manager.js.map +1 -0
- package/dist/savings/smart-savings.d.ts +74 -0
- package/dist/savings/smart-savings.js +152 -0
- package/dist/savings/smart-savings.js.map +1 -0
- package/dist/savings/types.d.ts +125 -0
- package/dist/savings/types.js +9 -0
- package/dist/savings/types.js.map +1 -0
- package/dist/svm/svm.d.ts +18 -0
- package/dist/svm/svm.js +35 -0
- package/dist/svm/svm.js.map +1 -1
- package/dist/test.js +53 -15
- package/dist/test.js.map +1 -1
- package/dist/vm.d.ts +14 -0
- package/dist/vm.js.map +1 -1
- package/package.json +2 -1
- package/utils/IChainWallet.ts +2 -0
- package/utils/constant.ts +63 -16
- package/utils/evm/aa-service/index.ts +0 -1
- package/utils/evm/aa-service/lib/kernel-account.ts +23 -8
- package/utils/evm/aa-service/lib/session-keys.ts +58 -60
- package/utils/evm/aa-service/lib/type.ts +2 -1
- package/utils/evm/aa-service/services/account-abstraction.ts +10 -76
- package/utils/evm/aa-service/services/bundler.ts +2 -1
- package/utils/evm/evm.ts +317 -0
- package/utils/evm/smartWallet.ts +118 -128
- package/utils/evm/utils.ts +1 -1
- package/utils/index.ts +1 -0
- package/utils/price.ts +37 -0
- package/utils/price.types.ts +45 -0
- package/utils/savings/savings-manager.ts +271 -0
- package/utils/savings/smart-savings.ts +184 -0
- package/utils/savings/types.ts +135 -0
- package/utils/svm/svm.ts +43 -2
- package/utils/test.ts +84 -19
- package/utils/vm.ts +12 -1
package/utils/evm/evm.ts
CHANGED
|
@@ -37,6 +37,18 @@ import { EVMTransactionHistoryItem, getEVMTransactionHistory } from "./transacti
|
|
|
37
37
|
import { createPublicClient, Hex, http, PublicClient, parseEther, parseUnits, Call } from "viem";
|
|
38
38
|
import { EVMSmartWallet } from "./smartWallet";
|
|
39
39
|
import { SmartWalletOptions } from "./aa-service";
|
|
40
|
+
import { SavingsManager } from "../savings/savings-manager";
|
|
41
|
+
import { SmartSavingsManager } from "../savings/smart-savings";
|
|
42
|
+
import {
|
|
43
|
+
SavingsAccount,
|
|
44
|
+
SmartSavingsAccount,
|
|
45
|
+
AddressVerificationResult,
|
|
46
|
+
SavingsAuditResult,
|
|
47
|
+
TransferToSavingsOptions,
|
|
48
|
+
WithdrawFromSavingsOptions
|
|
49
|
+
} from "../savings/types";
|
|
50
|
+
import { fetchPrices } from "../price";
|
|
51
|
+
import { PriceResponse } from "../price.types";
|
|
40
52
|
|
|
41
53
|
|
|
42
54
|
interface DebonkQuoteResponse {
|
|
@@ -76,6 +88,7 @@ interface DebonkSwapResult {
|
|
|
76
88
|
|
|
77
89
|
|
|
78
90
|
export class EVMVM extends VM<string, string, JsonRpcProvider> {
|
|
91
|
+
|
|
79
92
|
derivationPath = "m/44'/60'/0'/0/"; // Default EVM derivation path
|
|
80
93
|
|
|
81
94
|
constructor(seed: string) {
|
|
@@ -97,6 +110,38 @@ export class EVMVM extends VM<string, string, JsonRpcProvider> {
|
|
|
97
110
|
const privateKey = EVMDeriveChildPrivateKey(_seed, index, derivationPath).privateKey;
|
|
98
111
|
return { privateKey, index };
|
|
99
112
|
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Derive a savings account using BIP-44 account index
|
|
116
|
+
*
|
|
117
|
+
* Uses the pattern: m/44'/60'/accountIndex'/0/0
|
|
118
|
+
* - Main wallet: m/44'/60'/0'/0/0 (account index 0)
|
|
119
|
+
* - Savings 1: m/44'/60'/1'/0/0 (account index 1)
|
|
120
|
+
* - Savings 2: m/44'/60'/2'/0/0 (account index 2)
|
|
121
|
+
*
|
|
122
|
+
* @param accountIndex - The BIP-44 account index (0 for main, 1+ for savings)
|
|
123
|
+
* @returns Object containing privateKey, address, and derivation path
|
|
124
|
+
*/
|
|
125
|
+
deriveSavingsAccount(accountIndex: number): { privateKey: string; address: string; derivationPath: string } {
|
|
126
|
+
// Use fixed address index 0 for savings accounts
|
|
127
|
+
// Vary only the account index (3rd position in BIP-44)
|
|
128
|
+
const derivationPath = `m/44'/60'/${accountIndex}'/0/0`;
|
|
129
|
+
|
|
130
|
+
// Derive the full path directly (no additional index appended)
|
|
131
|
+
const result = EVMDeriveChildPrivateKey(this.seed, 0, `m/44'/60'/${accountIndex}'/0/`);
|
|
132
|
+
const privateKey = result.privateKey;
|
|
133
|
+
|
|
134
|
+
// Derive address from private key
|
|
135
|
+
const wallet = new ethers.Wallet(privateKey);
|
|
136
|
+
const address = wallet.address;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
privateKey,
|
|
140
|
+
address,
|
|
141
|
+
derivationPath
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
100
145
|
static fromMnemonic(mnemonic: string): VM<string, string, JsonRpcProvider> {
|
|
101
146
|
const seed = VM.mnemonicToSeed(mnemonic)
|
|
102
147
|
return new EVMVM(seed)
|
|
@@ -121,6 +166,8 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
121
166
|
client: PublicClient
|
|
122
167
|
wallet: Wallet
|
|
123
168
|
private smartWallet?: EVMSmartWallet
|
|
169
|
+
private savingsManager?: SavingsManager
|
|
170
|
+
private smartSavingsManager?: SmartSavingsManager
|
|
124
171
|
|
|
125
172
|
constructor(config: ChainWalletConfig, privateKey: string, index: number) {
|
|
126
173
|
super(config, privateKey, index);
|
|
@@ -372,6 +419,20 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
372
419
|
}
|
|
373
420
|
}
|
|
374
421
|
|
|
422
|
+
async getPrices(tokenAddresses: string[]): Promise<PriceResponse> {
|
|
423
|
+
const result = await fetchPrices({
|
|
424
|
+
vm: 'EVM',
|
|
425
|
+
chainId: this.config.chainId,
|
|
426
|
+
tokenAddresses,
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
if (result.error) {
|
|
430
|
+
throw new Error(result.error.message);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return result.data as PriceResponse;
|
|
434
|
+
}
|
|
435
|
+
|
|
375
436
|
// Updated swap method signature to match base class so created another method to use it inside swap
|
|
376
437
|
async swap(
|
|
377
438
|
tokenAddress: TokenInfo,
|
|
@@ -786,4 +847,260 @@ export class EVMChainWallet extends ChainWallet<string, string, JsonRpcProvider>
|
|
|
786
847
|
const signer = this.getWallet()
|
|
787
848
|
return signer.signMessage(message)
|
|
788
849
|
}
|
|
850
|
+
|
|
851
|
+
// ============================================
|
|
852
|
+
// Savings Pocket Methods
|
|
853
|
+
// ============================================
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Get or create the SavingsManager instance (lazy initialization)
|
|
857
|
+
* @private
|
|
858
|
+
*/
|
|
859
|
+
private getSavingsManager(): SavingsManager {
|
|
860
|
+
if (!this.savingsManager) {
|
|
861
|
+
// Create a VM instance from the current wallet's seed
|
|
862
|
+
// We need to get the seed from the privateKey
|
|
863
|
+
// For now, we'll create an EVMVM from the wallet
|
|
864
|
+
// Note: This requires access to the seed, which we'll need to handle
|
|
865
|
+
throw new Error(
|
|
866
|
+
"SavingsManager requires access to the seed phrase. " +
|
|
867
|
+
"Please initialize the wallet with a seed phrase or mnemonic to use savings features."
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
return this.savingsManager;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Initialize savings functionality with a seed phrase
|
|
875
|
+
*
|
|
876
|
+
* This must be called before using any savings methods.
|
|
877
|
+
* The seed is used to derive savings accounts using BIP-44.
|
|
878
|
+
*
|
|
879
|
+
* @param seed - The wallet seed (hex string)
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* const seed = VM.mnemonicToSeed(mnemonic);
|
|
883
|
+
* wallet.initializeSavings(seed);
|
|
884
|
+
*/
|
|
885
|
+
initializeSavings(seed: string): void {
|
|
886
|
+
const vm = new EVMVM(seed);
|
|
887
|
+
this.savingsManager = new SavingsManager(vm);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Derive a new savings account from BIP-44 account index
|
|
892
|
+
*
|
|
893
|
+
* @param accountIndex - The BIP-44 account index (1+ for savings, 0 is main wallet)
|
|
894
|
+
* @returns SavingsAccount with derived address and private key
|
|
895
|
+
*
|
|
896
|
+
* @example
|
|
897
|
+
* const savingsAccount1 = wallet.deriveSavingsAccount(1); // m/44'/60'/1'/0/0
|
|
898
|
+
* const savingsAccount2 = wallet.deriveSavingsAccount(2); // m/44'/60'/2'/0/0
|
|
899
|
+
*/
|
|
900
|
+
deriveSavingsAccount(accountIndex: number): SavingsAccount {
|
|
901
|
+
return this.getSavingsManager().createSavingsAccount(accountIndex);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Transfer native tokens to a savings account
|
|
906
|
+
*
|
|
907
|
+
* Security: Always derives the destination address from accountIndex.
|
|
908
|
+
*
|
|
909
|
+
* @param accountIndex - Savings account index to deposit to
|
|
910
|
+
* @param amount - Amount in ether units (e.g., "1.5" for 1.5 ETH)
|
|
911
|
+
* @param options - Optional security and priority settings
|
|
912
|
+
* @returns Transaction result
|
|
913
|
+
*
|
|
914
|
+
* @example
|
|
915
|
+
* const result = await wallet.transferToSavings(1, "1.5"); // Send 1.5 ETH to savings account 1
|
|
916
|
+
*/
|
|
917
|
+
async transferToSavings(
|
|
918
|
+
accountIndex: number,
|
|
919
|
+
amount: string,
|
|
920
|
+
options?: TransferToSavingsOptions
|
|
921
|
+
): Promise<TransactionResult> {
|
|
922
|
+
const manager = this.getSavingsManager();
|
|
923
|
+
|
|
924
|
+
// Build transaction using derived address
|
|
925
|
+
const amountWei = parseEther(amount);
|
|
926
|
+
const txParams = manager.buildDepositTransaction(accountIndex, amountWei, options);
|
|
927
|
+
|
|
928
|
+
// Execute using existing transferNative method
|
|
929
|
+
return await this.transferNative(txParams.to, Number(amount));
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Withdraw native tokens from a savings account
|
|
934
|
+
*
|
|
935
|
+
* Security: Uses the derived private key for signing.
|
|
936
|
+
*
|
|
937
|
+
* @param accountIndex - Savings account index to withdraw from
|
|
938
|
+
* @param to - Destination address
|
|
939
|
+
* @param amount - Amount in ether units (e.g., "0.5" for 0.5 ETH)
|
|
940
|
+
* @param options - Optional security and priority settings
|
|
941
|
+
* @returns Transaction result
|
|
942
|
+
*
|
|
943
|
+
* @example
|
|
944
|
+
* const result = await wallet.withdrawFromSavings(1, destinationAddress, "0.5");
|
|
945
|
+
*/
|
|
946
|
+
async withdrawFromSavings(
|
|
947
|
+
accountIndex: number,
|
|
948
|
+
to: string,
|
|
949
|
+
amount: string,
|
|
950
|
+
options?: WithdrawFromSavingsOptions
|
|
951
|
+
): Promise<TransactionResult> {
|
|
952
|
+
const manager = this.getSavingsManager();
|
|
953
|
+
|
|
954
|
+
// Build withdrawal transaction
|
|
955
|
+
const amountWei = parseEther(amount);
|
|
956
|
+
const withdrawalParams = manager.buildWithdrawalTransaction(
|
|
957
|
+
accountIndex,
|
|
958
|
+
to as Hex,
|
|
959
|
+
amountWei,
|
|
960
|
+
options
|
|
961
|
+
);
|
|
962
|
+
|
|
963
|
+
// Create a temporary wallet with the savings account private key
|
|
964
|
+
const savingsWallet = new Wallet(withdrawalParams.privateKey, this.connection);
|
|
965
|
+
|
|
966
|
+
// Send transaction using the savings wallet
|
|
967
|
+
const tx = await savingsWallet.sendTransaction({
|
|
968
|
+
to: withdrawalParams.to,
|
|
969
|
+
value: withdrawalParams.value
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
const receipt = await tx.wait(this.config.confirmationNo || 1);
|
|
973
|
+
|
|
974
|
+
return {
|
|
975
|
+
success: receipt?.status === 1,
|
|
976
|
+
hash: receipt?.hash || tx.hash
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Verify a stored savings address matches the derived address
|
|
982
|
+
*
|
|
983
|
+
* Security: Prevents database tampering attacks.
|
|
984
|
+
*
|
|
985
|
+
* @param accountIndex - The account index to verify
|
|
986
|
+
* @param storedAddress - The address from storage/database
|
|
987
|
+
* @returns Verification result
|
|
988
|
+
*
|
|
989
|
+
* @example
|
|
990
|
+
* const result = wallet.verifySavingsAddress(1, storedAddress);
|
|
991
|
+
* if (!result.isValid) {
|
|
992
|
+
* console.error("Security alert: Address tampering detected!");
|
|
993
|
+
* }
|
|
994
|
+
*/
|
|
995
|
+
verifySavingsAddress(accountIndex: number, storedAddress: Hex): AddressVerificationResult {
|
|
996
|
+
return this.getSavingsManager().verifySavingsAddress(accountIndex, storedAddress);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Audit multiple savings addresses at once
|
|
1001
|
+
*
|
|
1002
|
+
* @param addresses - Map of accountIndex to stored address
|
|
1003
|
+
* @returns Audit result with summary and details
|
|
1004
|
+
*
|
|
1005
|
+
* @example
|
|
1006
|
+
* const addresses = new Map([[1, "0xabc..."], [2, "0xdef..."]]);
|
|
1007
|
+
* const audit = wallet.auditSavingsAddresses(addresses);
|
|
1008
|
+
* console.log(`Valid: ${audit.valid}/${audit.total}`);
|
|
1009
|
+
*/
|
|
1010
|
+
auditSavingsAddresses(addresses: Map<number, Hex>): SavingsAuditResult {
|
|
1011
|
+
return this.getSavingsManager().auditSavingsAddresses(addresses);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Get savings account information without exposing private key
|
|
1016
|
+
*
|
|
1017
|
+
* @param accountIndex - The account index
|
|
1018
|
+
* @returns Public account information (address and derivation path)
|
|
1019
|
+
*
|
|
1020
|
+
* @example
|
|
1021
|
+
* const info = wallet.getSavingsAccountInfo(1);
|
|
1022
|
+
* console.log(`Address: ${info.address}`);
|
|
1023
|
+
* console.log(`Path: ${info.derivationPath}`); // m/44'/60'/1'/0/0
|
|
1024
|
+
*/
|
|
1025
|
+
getSavingsAccountInfo(accountIndex: number): Omit<SavingsAccount, 'privateKey'> {
|
|
1026
|
+
return this.getSavingsManager().getSavingsAccountInfo(accountIndex);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// ============================================
|
|
1030
|
+
// Smart Savings Methods (EIP-7702)
|
|
1031
|
+
// ============================================
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Get or create the SmartSavingsManager instance (lazy initialization)
|
|
1035
|
+
* @private
|
|
1036
|
+
*/
|
|
1037
|
+
private getSmartSavingsManager(): SmartSavingsManager {
|
|
1038
|
+
if (!this.smartSavingsManager) {
|
|
1039
|
+
this.smartSavingsManager = new SmartSavingsManager(this.config);
|
|
1040
|
+
}
|
|
1041
|
+
return this.smartSavingsManager;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Upgrade a savings account to a smart account with EIP-7702 delegation
|
|
1046
|
+
*
|
|
1047
|
+
* This enables advanced features:
|
|
1048
|
+
* - Lock modules for time-locked savings
|
|
1049
|
+
* - Hooks for spend & save
|
|
1050
|
+
* - Session keys for periodic savings
|
|
1051
|
+
* - Sponsored transactions via paymaster
|
|
1052
|
+
*
|
|
1053
|
+
* @param accountIndex - The savings account index to upgrade
|
|
1054
|
+
* @param options - Optional smart wallet configuration
|
|
1055
|
+
* @param autoInitialize - Whether to initialize the smart wallet (default: false)
|
|
1056
|
+
* @returns SmartSavingsAccount with EVMSmartWallet instance
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* // Upgrade without initialization
|
|
1060
|
+
* const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
|
|
1061
|
+
* await smartSavings.smartWallet.initialize(); // Initialize separately
|
|
1062
|
+
*
|
|
1063
|
+
* @example
|
|
1064
|
+
* // Upgrade and initialize in one step
|
|
1065
|
+
* const smartSavings = await wallet.upgradeSavingsToSmartAccount(1, {}, true);
|
|
1066
|
+
* // Ready to use immediately
|
|
1067
|
+
*/
|
|
1068
|
+
async upgradeSavingsToSmartAccount(
|
|
1069
|
+
accountIndex: number,
|
|
1070
|
+
options?: SmartWalletOptions,
|
|
1071
|
+
autoInitialize: boolean = false
|
|
1072
|
+
): Promise<SmartSavingsAccount> {
|
|
1073
|
+
const manager = this.getSmartSavingsManager();
|
|
1074
|
+
|
|
1075
|
+
// First derive the basic savings account
|
|
1076
|
+
const basicSavings = this.deriveSavingsAccount(accountIndex);
|
|
1077
|
+
|
|
1078
|
+
// Then upgrade to smart account
|
|
1079
|
+
if (autoInitialize) {
|
|
1080
|
+
return await manager.upgradeSavingsAndInitialize(basicSavings, options);
|
|
1081
|
+
} else {
|
|
1082
|
+
return await manager.upgradeSavingsToSmartAccount(basicSavings, options);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Check if smart savings is supported on this chain
|
|
1088
|
+
*
|
|
1089
|
+
* @returns true if chain supports Account Abstraction
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* if (wallet.isSmartSavingsSupported()) {
|
|
1093
|
+
* const smartSavings = await wallet.upgradeSavingsToSmartAccount(1);
|
|
1094
|
+
* } else {
|
|
1095
|
+
* console.log("This chain doesn't support smart savings");
|
|
1096
|
+
* }
|
|
1097
|
+
*/
|
|
1098
|
+
isSmartSavingsSupported(): boolean {
|
|
1099
|
+
try {
|
|
1100
|
+
const manager = this.getSmartSavingsManager();
|
|
1101
|
+
return manager.canUpgradeToSmartAccount();
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
789
1106
|
}
|
package/utils/evm/smartWallet.ts
CHANGED
|
@@ -54,12 +54,11 @@ import type { SessionKeyPermission } from "./aa-service/lib/kernel-modules";
|
|
|
54
54
|
* - Account recovery
|
|
55
55
|
*/
|
|
56
56
|
export class EVMSmartWallet {
|
|
57
|
-
|
|
57
|
+
aaService: AccountAbstractionService | null = null;
|
|
58
58
|
private kernelAccount: KernelAccountInstance | null = null;
|
|
59
59
|
private ownerAccount: PrivateKeyAccount;
|
|
60
60
|
private chain: Chain;
|
|
61
61
|
private options: SmartWalletOptions;
|
|
62
|
-
private sessionAccount: any = null;
|
|
63
62
|
private paymasterConfig: PaymasterConfig | null = null;
|
|
64
63
|
|
|
65
64
|
constructor(
|
|
@@ -95,7 +94,7 @@ export class EVMSmartWallet {
|
|
|
95
94
|
try {
|
|
96
95
|
// Initialize AA service singleton with AA config
|
|
97
96
|
this.aaService = AccountAbstractionService.getInstance({
|
|
98
|
-
bundlerProvider: '
|
|
97
|
+
bundlerProvider: 'pimlico',
|
|
99
98
|
customBundlerUrl: this.options.bundlerUrl!,
|
|
100
99
|
aaConfig: this.options.aaConfig
|
|
101
100
|
});
|
|
@@ -202,35 +201,67 @@ export class EVMSmartWallet {
|
|
|
202
201
|
async sendTransaction(
|
|
203
202
|
to: Hex,
|
|
204
203
|
value: bigint = 0n,
|
|
205
|
-
data: Hex = '0x'
|
|
204
|
+
data: Hex = '0x',
|
|
205
|
+
options?: { sessionAccount: Omit<KernelAccountInstance, 'owner' | 'entryPoint' | 'chain'> }
|
|
206
206
|
): Promise<SmartWalletTransactionResult> {
|
|
207
207
|
if (!this.kernelAccount || !this.aaService) {
|
|
208
208
|
throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
try {
|
|
212
|
-
// Use session account if available
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
userOpHash
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
212
|
+
// Use session account if available and requested
|
|
213
|
+
if (options?.sessionAccount) {
|
|
214
|
+
// Session keys use kernel account client, not bundler client
|
|
215
|
+
const { createSessionKeyClient } = await import('./aa-service/lib/session-keys');
|
|
216
|
+
|
|
217
|
+
const kernelClient = createSessionKeyClient({
|
|
218
|
+
account: options.sessionAccount.account,
|
|
219
|
+
chain: this.chain,
|
|
220
|
+
bundlerUrl: this.options.bundlerUrl!,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Use kernel client to send transaction
|
|
224
|
+
const userOpHash = await kernelClient.sendUserOperation({
|
|
225
|
+
callData: await options.sessionAccount.account.encodeCalls([{
|
|
226
|
+
to,
|
|
227
|
+
value,
|
|
228
|
+
data
|
|
229
|
+
}])
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Wait for receipt
|
|
233
|
+
const receipt = await kernelClient.waitForUserOperationReceipt({
|
|
234
|
+
hash: userOpHash
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
success: true,
|
|
239
|
+
userOpHash,
|
|
240
|
+
transactionHash: receipt.receipt.transactionHash
|
|
241
|
+
};
|
|
242
|
+
} else {
|
|
243
|
+
// Use regular kernel account with AA service
|
|
244
|
+
const userOpHash = await this.aaService.sendTransaction({
|
|
245
|
+
account: this.kernelAccount,
|
|
246
|
+
to,
|
|
247
|
+
value,
|
|
248
|
+
data
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Wait for receipt
|
|
252
|
+
const receipt = await this.aaService.waitForReceipt({
|
|
253
|
+
userOpHash,
|
|
254
|
+
chain: this.chain
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
userOpHash,
|
|
260
|
+
transactionHash: receipt.transactionHash
|
|
261
|
+
};
|
|
262
|
+
}
|
|
233
263
|
} catch (error) {
|
|
264
|
+
console.log('error: ', error);
|
|
234
265
|
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
235
266
|
return {
|
|
236
267
|
success: false,
|
|
@@ -254,7 +285,7 @@ export class EVMSmartWallet {
|
|
|
254
285
|
* { to: usdcAddress, value: 0n, data: transferCalldata }
|
|
255
286
|
* ]);
|
|
256
287
|
*/
|
|
257
|
-
async sendBatchTransaction(calls: Call[]): Promise<SmartWalletTransactionResult> {
|
|
288
|
+
async sendBatchTransaction(calls: Call[], options?: { sessionAccount: KernelAccountInstance }): Promise<SmartWalletTransactionResult> {
|
|
258
289
|
if (!this.kernelAccount || !this.aaService) {
|
|
259
290
|
throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
|
|
260
291
|
}
|
|
@@ -264,32 +295,65 @@ export class EVMSmartWallet {
|
|
|
264
295
|
}
|
|
265
296
|
|
|
266
297
|
try {
|
|
267
|
-
// Convert to
|
|
268
|
-
const
|
|
298
|
+
// Convert to proper Call format
|
|
299
|
+
const normalizedCalls = calls.map(call => ({
|
|
269
300
|
to: call.to,
|
|
270
|
-
value: call.value,
|
|
271
|
-
data: call.data
|
|
301
|
+
value: call.value ?? 0n,
|
|
302
|
+
data: call.data ?? '0x' as Hex
|
|
272
303
|
}));
|
|
273
304
|
|
|
274
|
-
// Use session account if available
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
305
|
+
// Use session account if available
|
|
306
|
+
if (options?.sessionAccount) {
|
|
307
|
+
// Session keys use kernel account client
|
|
308
|
+
const { createSessionKeyClient } = await import('./aa-service/lib/session-keys');
|
|
309
|
+
|
|
310
|
+
const kernelClient = createSessionKeyClient({
|
|
311
|
+
account: options.sessionAccount.account,
|
|
312
|
+
chain: this.chain,
|
|
313
|
+
bundlerUrl: this.options.bundlerUrl!,
|
|
314
|
+
entryPoint: options.sessionAccount.entryPoint
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Use kernel client to send batch transaction
|
|
318
|
+
const userOpHash = await kernelClient.sendUserOperation({
|
|
319
|
+
callData: await options.sessionAccount.account.encodeCalls(normalizedCalls)
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Wait for receipt
|
|
323
|
+
const receipt = await kernelClient.waitForUserOperationReceipt({
|
|
324
|
+
hash: userOpHash
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
success: true,
|
|
329
|
+
userOpHash,
|
|
330
|
+
transactionHash: receipt.receipt.transactionHash
|
|
331
|
+
};
|
|
332
|
+
} else {
|
|
333
|
+
// Use regular kernel account with AA service
|
|
334
|
+
const aaCalls: AACall[] = normalizedCalls.map(call => ({
|
|
335
|
+
to: call.to,
|
|
336
|
+
value: call.value,
|
|
337
|
+
data: call.data
|
|
338
|
+
}));
|
|
339
|
+
|
|
340
|
+
const userOpHash = await this.aaService.sendBatchTransaction({
|
|
341
|
+
account: this.kernelAccount,
|
|
342
|
+
calls: aaCalls
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Wait for receipt
|
|
346
|
+
const receipt = await this.aaService.waitForReceipt({
|
|
347
|
+
userOpHash,
|
|
348
|
+
chain: this.chain
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
success: true,
|
|
353
|
+
userOpHash,
|
|
354
|
+
transactionHash: receipt.transactionHash
|
|
355
|
+
};
|
|
356
|
+
}
|
|
293
357
|
} catch (error) {
|
|
294
358
|
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
295
359
|
return {
|
|
@@ -336,27 +400,7 @@ export class EVMSmartWallet {
|
|
|
336
400
|
}
|
|
337
401
|
}
|
|
338
402
|
|
|
339
|
-
|
|
340
|
-
* Recreate session key from stored private key
|
|
341
|
-
*
|
|
342
|
-
* @param privateKey - Session key private key
|
|
343
|
-
* @returns Session key info
|
|
344
|
-
*
|
|
345
|
-
* @example
|
|
346
|
-
* const sessionKey = await smartWallet.recreateSessionKey(storedPrivateKey);
|
|
347
|
-
*/
|
|
348
|
-
async recreateSessionKey(privateKey: Hex): Promise<SessionKeyInfo> {
|
|
349
|
-
if (!this.aaService) {
|
|
350
|
-
throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
|
|
351
|
-
}
|
|
352
|
-
try {
|
|
353
|
-
return await this.aaService.recreateSessionKey(privateKey);
|
|
354
|
-
} catch (error) {
|
|
355
|
-
throw new SessionKeyError(
|
|
356
|
-
`Failed to recreate session key: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
403
|
+
|
|
360
404
|
|
|
361
405
|
/**
|
|
362
406
|
* Create session key approval (Owner side)
|
|
@@ -380,6 +424,7 @@ export class EVMSmartWallet {
|
|
|
380
424
|
try {
|
|
381
425
|
return await this.aaService.createSessionKeyApproval({
|
|
382
426
|
sessionKeyAddress: options.sessionKeyAddress,
|
|
427
|
+
sessionKeyPrivateKey: options.sessionKeyPrivateKey,
|
|
383
428
|
owner: this.ownerAccount,
|
|
384
429
|
chain: this.chain,
|
|
385
430
|
entryPointVersion: this.options.entryPointVersion,
|
|
@@ -393,52 +438,6 @@ export class EVMSmartWallet {
|
|
|
393
438
|
}
|
|
394
439
|
}
|
|
395
440
|
|
|
396
|
-
/**
|
|
397
|
-
* Use session key for transactions (Agent side)
|
|
398
|
-
* Agent deserializes the approval and can send transactions with session key
|
|
399
|
-
*
|
|
400
|
-
* @param options - Session key usage options with approval and signer
|
|
401
|
-
*
|
|
402
|
-
* @example
|
|
403
|
-
* const sessionKey = await smartWallet.recreateSessionKey(privateKey);
|
|
404
|
-
* await smartWallet.useSessionKey({
|
|
405
|
-
* approval,
|
|
406
|
-
* sessionKeySigner: sessionKey.signer
|
|
407
|
-
* });
|
|
408
|
-
* // Now can send transactions with session key permissions
|
|
409
|
-
*/
|
|
410
|
-
async useSessionKey(options: SessionKeyUsageOptions): Promise<void> {
|
|
411
|
-
if (!this.aaService) {
|
|
412
|
-
throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
|
|
413
|
-
}
|
|
414
|
-
try {
|
|
415
|
-
this.sessionAccount = await this.aaService.deserializeSessionKey({
|
|
416
|
-
approval: options.approval,
|
|
417
|
-
sessionKeySigner: options.sessionKeySigner,
|
|
418
|
-
chain: this.chain,
|
|
419
|
-
entryPointVersion: this.options.entryPointVersion
|
|
420
|
-
});
|
|
421
|
-
} catch (error) {
|
|
422
|
-
throw new SessionKeyError(
|
|
423
|
-
`Failed to use session key: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Clear session key (revert to owner account)
|
|
430
|
-
*/
|
|
431
|
-
clearSessionKey(): void {
|
|
432
|
-
this.sessionAccount = null;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Check if using session key
|
|
437
|
-
*/
|
|
438
|
-
isUsingSessionKey(): boolean {
|
|
439
|
-
return this.sessionAccount !== null;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
441
|
/**
|
|
443
442
|
* Create USDC transfer permission
|
|
444
443
|
*
|
|
@@ -446,11 +445,11 @@ export class EVMSmartWallet {
|
|
|
446
445
|
* @param maxAmount - Maximum USDC amount (in USDC units, e.g., "10" for 10 USDC)
|
|
447
446
|
* @returns Permission rule
|
|
448
447
|
*/
|
|
449
|
-
createUSDCPermission(usdcAddress: Hex, maxAmount: string): SessionKeyPermissionRule {
|
|
448
|
+
createUSDCPermission(usdcAddress: Hex, maxAmount: string, destinationAddress: Hex): SessionKeyPermissionRule {
|
|
450
449
|
if (!this.aaService) {
|
|
451
450
|
throw new SmartWalletError('Smart wallet not initialized', 'NOT_INITIALIZED');
|
|
452
451
|
}
|
|
453
|
-
return this.aaService.createUSDCTransferPermission(usdcAddress, maxAmount);
|
|
452
|
+
return this.aaService.createUSDCTransferPermission(usdcAddress, maxAmount, destinationAddress);
|
|
454
453
|
}
|
|
455
454
|
|
|
456
455
|
/**
|
|
@@ -706,14 +705,5 @@ export class EVMSmartWallet {
|
|
|
706
705
|
return this.aaService.getBundlerInfo(this.chain);
|
|
707
706
|
}
|
|
708
707
|
|
|
709
|
-
|
|
710
|
-
* Clear all caches
|
|
711
|
-
*/
|
|
712
|
-
clearCache(): void {
|
|
713
|
-
if (this.aaService) {
|
|
714
|
-
this.aaService.clearCache();
|
|
715
|
-
}
|
|
716
|
-
this.kernelAccount = null;
|
|
717
|
-
this.sessionAccount = null;
|
|
718
|
-
}
|
|
708
|
+
|
|
719
709
|
}
|
package/utils/evm/utils.ts
CHANGED
|
@@ -641,7 +641,7 @@ export const safeApprove = async (
|
|
|
641
641
|
|
|
642
642
|
export const discoverTokens = async (wallet: string, chain: ChainWalletConfig): Promise<UserTokenBalance<string>[]> => {
|
|
643
643
|
const balances = await HelperAPI.getUserToken(wallet, chain.vmType ?? "EVM", chain.chainId)
|
|
644
|
-
|
|
644
|
+
|
|
645
645
|
|
|
646
646
|
|
|
647
647
|
const formatBalances: UserTokenBalance<string>[] = balances.data.map((token: any) => {
|