rain-sdk-v2 1.0.0
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 +1074 -0
- package/dist/Rain.d.ts +212 -0
- package/dist/Rain.js +401 -0
- package/dist/RainAA.d.ts +62 -0
- package/dist/RainAA.js +304 -0
- package/dist/abi/CreateMarketAbi.d.ts +1125 -0
- package/dist/abi/CreateMarketAbi.js +1 -0
- package/dist/abi/ERC20Abi.d.ts +89 -0
- package/dist/abi/ERC20Abi.js +119 -0
- package/dist/abi/MarketsAbi.d.ts +2810 -0
- package/dist/abi/MarketsAbi.js +1 -0
- package/dist/abi/OracleAbi.d.ts +11 -0
- package/dist/abi/OracleAbi.js +15 -0
- package/dist/api/comments.d.ts +14 -0
- package/dist/api/comments.js +48 -0
- package/dist/api/dispute.d.ts +3 -0
- package/dist/api/dispute.js +30 -0
- package/dist/api/follow.d.ts +6 -0
- package/dist/api/follow.js +38 -0
- package/dist/api/helpers.d.ts +4 -0
- package/dist/api/helpers.js +26 -0
- package/dist/api/index.d.ts +14 -0
- package/dist/api/index.js +14 -0
- package/dist/api/investments.d.ts +21 -0
- package/dist/api/investments.js +135 -0
- package/dist/api/notifications.d.ts +4 -0
- package/dist/api/notifications.js +24 -0
- package/dist/api/orders.d.ts +8 -0
- package/dist/api/orders.js +40 -0
- package/dist/api/points.d.ts +5 -0
- package/dist/api/points.js +32 -0
- package/dist/api/poolReviews.d.ts +4 -0
- package/dist/api/poolReviews.js +23 -0
- package/dist/api/pools.d.ts +41 -0
- package/dist/api/pools.js +149 -0
- package/dist/api/priceData.d.ts +2 -0
- package/dist/api/priceData.js +9 -0
- package/dist/api/rainBurn.d.ts +3 -0
- package/dist/api/rainBurn.js +15 -0
- package/dist/api/types.d.ts +292 -0
- package/dist/api/types.js +2 -0
- package/dist/api/users.d.ts +15 -0
- package/dist/api/users.js +60 -0
- package/dist/auth/login.d.ts +4 -0
- package/dist/auth/login.js +27 -0
- package/dist/auth/types.d.ts +16 -0
- package/dist/auth/types.js +1 -0
- package/dist/config/environments.d.ts +15 -0
- package/dist/config/environments.js +41 -0
- package/dist/constants/contractmethods.d.ts +15 -0
- package/dist/constants/contractmethods.js +15 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/markets/getDisputeFee.d.ts +5 -0
- package/dist/markets/getDisputeFee.js +19 -0
- package/dist/markets/getOrderInfo.d.ts +53 -0
- package/dist/markets/getOrderInfo.js +80 -0
- package/dist/markets/getResolverBondAmount.d.ts +9 -0
- package/dist/markets/getResolverBondAmount.js +35 -0
- package/dist/markets/getUserOptionLPShares.d.ts +7 -0
- package/dist/markets/getUserOptionLPShares.js +17 -0
- package/dist/markets/getUserOptionShares.d.ts +8 -0
- package/dist/markets/getUserOptionShares.js +17 -0
- package/dist/socket/RainSocket.d.ts +175 -0
- package/dist/socket/RainSocket.js +186 -0
- package/dist/tx/CreateMarket/buildCreateMarketRawTx.d.ts +2 -0
- package/dist/tx/CreateMarket/buildCreateMarketRawTx.js +55 -0
- package/dist/tx/CreateMarket/createMarketValidation.d.ts +2 -0
- package/dist/tx/CreateMarket/createMarketValidation.js +48 -0
- package/dist/tx/CreateMarket/helpers.d.ts +3 -0
- package/dist/tx/CreateMarket/helpers.js +42 -0
- package/dist/tx/buildAddLiquidityRawTx.d.ts +2 -0
- package/dist/tx/buildAddLiquidityRawTx.js +23 -0
- package/dist/tx/buildApprovalRawTx.d.ts +2 -0
- package/dist/tx/buildApprovalRawTx.js +24 -0
- package/dist/tx/buildCalculateWinnerRawTx.d.ts +13 -0
- package/dist/tx/buildCalculateWinnerRawTx.js +37 -0
- package/dist/tx/buildCancelOrdersRawTx.d.ts +3 -0
- package/dist/tx/buildCancelOrdersRawTx.js +43 -0
- package/dist/tx/buildClaimRawTx.d.ts +2 -0
- package/dist/tx/buildClaimRawTx.js +19 -0
- package/dist/tx/buildClosePoolRawTx.d.ts +20 -0
- package/dist/tx/buildClosePoolRawTx.js +95 -0
- package/dist/tx/buildEnterOptionRawTx.d.ts +2 -0
- package/dist/tx/buildEnterOptionRawTx.js +25 -0
- package/dist/tx/buildMergeRawTx.d.ts +2 -0
- package/dist/tx/buildMergeRawTx.js +21 -0
- package/dist/tx/buildOpenDisputeRawTx.d.ts +8 -0
- package/dist/tx/buildOpenDisputeRawTx.js +39 -0
- package/dist/tx/buildPlaceOrderRawTx.d.ts +3 -0
- package/dist/tx/buildPlaceOrderRawTx.js +47 -0
- package/dist/tx/buildRemoveLiquidityRawTx.d.ts +2 -0
- package/dist/tx/buildRemoveLiquidityRawTx.js +23 -0
- package/dist/tx/buildSplitRawTx.d.ts +2 -0
- package/dist/tx/buildSplitRawTx.js +21 -0
- package/dist/tx/types.d.ts +117 -0
- package/dist/tx/types.js +10 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.js +1 -0
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +28 -0
- package/package.json +66 -0
package/dist/RainAA.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RainConfig } from './types.js';
|
|
2
|
+
import { RawTransaction } from './tx/types.js';
|
|
3
|
+
export declare class RainAA {
|
|
4
|
+
private config;
|
|
5
|
+
private _client;
|
|
6
|
+
private _sessionClient;
|
|
7
|
+
private _account;
|
|
8
|
+
private _address;
|
|
9
|
+
private _sessionContext;
|
|
10
|
+
private _sessionKeyAddress;
|
|
11
|
+
private _sessionPrivateKey;
|
|
12
|
+
private _sessionExpirySec;
|
|
13
|
+
private _alchemyChain;
|
|
14
|
+
private _aaSdk;
|
|
15
|
+
private _walletClientLib;
|
|
16
|
+
private _viemAccounts;
|
|
17
|
+
private _alchemyTransportFactory;
|
|
18
|
+
constructor(config: RainConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Initializes the smart account. Does NOT trigger MetaMask. If a still-valid
|
|
21
|
+
* session is persisted in IndexedDB for this account, it is rehydrated
|
|
22
|
+
* silently and `hasActiveSession` will be true — sends work immediately.
|
|
23
|
+
* Otherwise the caller must invoke `grantSession()` (which prompts MetaMask)
|
|
24
|
+
* before sending transactions.
|
|
25
|
+
*/
|
|
26
|
+
connect(): Promise<`0x${string}`>;
|
|
27
|
+
/**
|
|
28
|
+
* Triggers MetaMask `wallet_createSession` to grant a generated session key
|
|
29
|
+
* permission to act on behalf of the smart account for SESSION_DURATION_SEC.
|
|
30
|
+
* Persists `{privateKey, context, expirySec}` in IndexedDB so that
|
|
31
|
+
* subsequent `connect()` calls within the expiry skip the popup.
|
|
32
|
+
*
|
|
33
|
+
* Returns the new session details. Safe to call when a session is already
|
|
34
|
+
* active — in that case it returns the existing session without prompting.
|
|
35
|
+
*/
|
|
36
|
+
grantSession(): Promise<{
|
|
37
|
+
privateKey: `0x${string}`;
|
|
38
|
+
sessionKeyAddress: `0x${string}`;
|
|
39
|
+
context: `0x${string}`;
|
|
40
|
+
expirySec: number;
|
|
41
|
+
}>;
|
|
42
|
+
get address(): `0x${string}`;
|
|
43
|
+
get client(): any;
|
|
44
|
+
/** Public address of the active session key (signs userOps locally — no popup). */
|
|
45
|
+
get sessionKeyAddress(): `0x${string}` | null;
|
|
46
|
+
/** Unix seconds when the current session permission expires. */
|
|
47
|
+
get sessionExpirySec(): number | null;
|
|
48
|
+
/** Whether a fresh `connect()` would reuse the existing session (no MetaMask popup). */
|
|
49
|
+
get hasActiveSession(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Sends a raw transaction from the smart account using the granted session
|
|
52
|
+
* key — no MetaMask popup per call. Returns the on-chain transaction hash.
|
|
53
|
+
*/
|
|
54
|
+
sendTransaction(rawTx: RawTransaction): Promise<`0x${string}`>;
|
|
55
|
+
/**
|
|
56
|
+
* Clear in-memory state. The persisted session in IndexedDB is preserved
|
|
57
|
+
* so reconnecting within the expiry window won't trigger a fresh
|
|
58
|
+
* grantPermissions popup. Call `forgetSession()` to wipe it explicitly.
|
|
59
|
+
*/
|
|
60
|
+
disconnect(): void;
|
|
61
|
+
forgetSession(): Promise<void>;
|
|
62
|
+
}
|
package/dist/RainAA.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { custom, createWalletClient, toHex } from 'viem';
|
|
2
|
+
const SESSION_DURATION_SEC = 60 * 60 * 24; // 24 hours
|
|
3
|
+
const DB_NAME = 'RainSDKV2';
|
|
4
|
+
const STORE_NAME = 'sessions';
|
|
5
|
+
function openSessionDB() {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const req = indexedDB.open(DB_NAME, 1);
|
|
8
|
+
req.onupgradeneeded = () => {
|
|
9
|
+
const db = req.result;
|
|
10
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
11
|
+
db.createObjectStore(STORE_NAME);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
req.onsuccess = () => resolve(req.result);
|
|
15
|
+
req.onerror = () => reject(req.error);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function loadSession(key) {
|
|
19
|
+
const db = await openSessionDB();
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
22
|
+
const req = tx.objectStore(STORE_NAME).get(key);
|
|
23
|
+
req.onsuccess = () => resolve((req.result ?? null));
|
|
24
|
+
req.onerror = () => reject(req.error);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function saveSession(key, data) {
|
|
28
|
+
const db = await openSessionDB();
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
31
|
+
tx.objectStore(STORE_NAME).put(data, key);
|
|
32
|
+
tx.oncomplete = () => resolve();
|
|
33
|
+
tx.onerror = () => reject(tx.error);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function deleteSession(key) {
|
|
37
|
+
const db = await openSessionDB();
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
40
|
+
tx.objectStore(STORE_NAME).delete(key);
|
|
41
|
+
tx.oncomplete = () => resolve();
|
|
42
|
+
tx.onerror = () => reject(tx.error);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export class RainAA {
|
|
46
|
+
config;
|
|
47
|
+
_client = null; // EOA-signed client (for grantPermissions)
|
|
48
|
+
_sessionClient = null; // session-key client (for sendCalls)
|
|
49
|
+
_account = null;
|
|
50
|
+
_address = null;
|
|
51
|
+
_sessionContext = null;
|
|
52
|
+
_sessionKeyAddress = null;
|
|
53
|
+
_sessionPrivateKey = null;
|
|
54
|
+
_sessionExpirySec = null;
|
|
55
|
+
_alchemyChain = null;
|
|
56
|
+
_aaSdk = null;
|
|
57
|
+
_walletClientLib = null;
|
|
58
|
+
_viemAccounts = null;
|
|
59
|
+
_alchemyTransportFactory = null;
|
|
60
|
+
constructor(config) {
|
|
61
|
+
if (!config.walletClient)
|
|
62
|
+
throw new Error('walletClient is required');
|
|
63
|
+
if (!config.alchemyApiKey)
|
|
64
|
+
throw new Error('alchemyApiKey is required');
|
|
65
|
+
if (!config.paymasterPolicyId)
|
|
66
|
+
throw new Error('paymasterPolicyId is required');
|
|
67
|
+
if (!config.chain)
|
|
68
|
+
throw new Error('chain is required');
|
|
69
|
+
this.config = config;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Initializes the smart account. Does NOT trigger MetaMask. If a still-valid
|
|
73
|
+
* session is persisted in IndexedDB for this account, it is rehydrated
|
|
74
|
+
* silently and `hasActiveSession` will be true — sends work immediately.
|
|
75
|
+
* Otherwise the caller must invoke `grantSession()` (which prompts MetaMask)
|
|
76
|
+
* before sending transactions.
|
|
77
|
+
*/
|
|
78
|
+
async connect() {
|
|
79
|
+
if (this._address && this._client) {
|
|
80
|
+
return this._address;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const [{ WalletClientSigner, LocalAccountSigner }, infraMod, walletClientLib, viemAccounts,] = await Promise.all([
|
|
84
|
+
// @ts-ignore - peer dep
|
|
85
|
+
import('@aa-sdk/core'),
|
|
86
|
+
// @ts-ignore - peer dep
|
|
87
|
+
import('@account-kit/infra'),
|
|
88
|
+
// @ts-ignore - peer dep
|
|
89
|
+
import('@account-kit/wallet-client'),
|
|
90
|
+
// @ts-ignore - viem subpath
|
|
91
|
+
import('viem/accounts'),
|
|
92
|
+
]);
|
|
93
|
+
const { createSmartWalletClient } = walletClientLib;
|
|
94
|
+
const { alchemy, defineAlchemyChain } = infraMod;
|
|
95
|
+
const { privateKeyToAccount } = viemAccounts;
|
|
96
|
+
const alchemyChain = defineAlchemyChain({
|
|
97
|
+
chain: this.config.chain,
|
|
98
|
+
rpcBaseUrl: `https://${this.config.chain.id === 42161 ? 'arb-mainnet' : 'arb-sepolia'}.g.alchemy.com/v2`,
|
|
99
|
+
});
|
|
100
|
+
const eoaSigner = new WalletClientSigner(createWalletClient({
|
|
101
|
+
transport: custom(this.config.walletClient),
|
|
102
|
+
}), 'wallet');
|
|
103
|
+
const eoaClient = createSmartWalletClient({
|
|
104
|
+
chain: alchemyChain,
|
|
105
|
+
signer: eoaSigner,
|
|
106
|
+
policyId: this.config.paymasterPolicyId,
|
|
107
|
+
transport: alchemy({
|
|
108
|
+
apiKey: this.config.alchemyApiKey,
|
|
109
|
+
nodeRpcUrl: this.config.rpcUrl,
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
const account = await eoaClient.requestAccount();
|
|
113
|
+
if (!account?.address)
|
|
114
|
+
throw new Error('Failed to create smart account');
|
|
115
|
+
this._client = eoaClient;
|
|
116
|
+
this._account = account;
|
|
117
|
+
this._address = account.address;
|
|
118
|
+
// Cache modules for later use in grantSession()
|
|
119
|
+
this._aaSdk = { LocalAccountSigner };
|
|
120
|
+
this._walletClientLib = walletClientLib;
|
|
121
|
+
this._viemAccounts = viemAccounts;
|
|
122
|
+
this._alchemyChain = alchemyChain;
|
|
123
|
+
this._alchemyTransportFactory = alchemy;
|
|
124
|
+
// Try to rehydrate an existing valid session WITHOUT prompting MetaMask.
|
|
125
|
+
const storageKey = `sessionKeyData:${account.address.toLowerCase()}`;
|
|
126
|
+
const now = Math.floor(Date.now() / 1000);
|
|
127
|
+
const stored = await loadSession(storageKey).catch(() => null);
|
|
128
|
+
const sessionStillValid = stored &&
|
|
129
|
+
stored.expirySec > now &&
|
|
130
|
+
stored.smartAccountAddress?.toLowerCase() === account.address.toLowerCase();
|
|
131
|
+
if (sessionStillValid && stored) {
|
|
132
|
+
const sessionAccount = privateKeyToAccount(stored.privateKey);
|
|
133
|
+
const sessionSigner = new LocalAccountSigner(sessionAccount);
|
|
134
|
+
this._sessionPrivateKey = stored.privateKey;
|
|
135
|
+
this._sessionKeyAddress = sessionAccount.address;
|
|
136
|
+
this._sessionExpirySec = stored.expirySec;
|
|
137
|
+
this._sessionContext = stored.context;
|
|
138
|
+
this._sessionClient = createSmartWalletClient({
|
|
139
|
+
chain: alchemyChain,
|
|
140
|
+
signer: sessionSigner,
|
|
141
|
+
policyId: this.config.paymasterPolicyId,
|
|
142
|
+
transport: alchemy({
|
|
143
|
+
apiKey: this.config.alchemyApiKey,
|
|
144
|
+
nodeRpcUrl: this.config.rpcUrl,
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return account.address;
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error('[Rain SDK V2] connect failed:', err);
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Triggers MetaMask `wallet_createSession` to grant a generated session key
|
|
157
|
+
* permission to act on behalf of the smart account for SESSION_DURATION_SEC.
|
|
158
|
+
* Persists `{privateKey, context, expirySec}` in IndexedDB so that
|
|
159
|
+
* subsequent `connect()` calls within the expiry skip the popup.
|
|
160
|
+
*
|
|
161
|
+
* Returns the new session details. Safe to call when a session is already
|
|
162
|
+
* active — in that case it returns the existing session without prompting.
|
|
163
|
+
*/
|
|
164
|
+
async grantSession() {
|
|
165
|
+
if (!this._client || !this._account || !this._address) {
|
|
166
|
+
throw new Error('Rain not connected. Call rain.connect() first.');
|
|
167
|
+
}
|
|
168
|
+
// Already have a valid session — no popup needed.
|
|
169
|
+
if (this.hasActiveSession && this._sessionPrivateKey && this._sessionKeyAddress && this._sessionContext && this._sessionExpirySec) {
|
|
170
|
+
return {
|
|
171
|
+
privateKey: this._sessionPrivateKey,
|
|
172
|
+
sessionKeyAddress: this._sessionKeyAddress,
|
|
173
|
+
context: this._sessionContext,
|
|
174
|
+
expirySec: this._sessionExpirySec,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (!this._aaSdk || !this._walletClientLib || !this._viemAccounts || !this._alchemyChain || !this._alchemyTransportFactory) {
|
|
178
|
+
throw new Error('Rain not connected. Call rain.connect() first.');
|
|
179
|
+
}
|
|
180
|
+
const { LocalAccountSigner } = this._aaSdk;
|
|
181
|
+
const { createSmartWalletClient } = this._walletClientLib;
|
|
182
|
+
const { generatePrivateKey, privateKeyToAccount } = this._viemAccounts;
|
|
183
|
+
const alchemy = this._alchemyTransportFactory;
|
|
184
|
+
const alchemyChain = this._alchemyChain;
|
|
185
|
+
const privateKey = generatePrivateKey();
|
|
186
|
+
const sessionAccount = privateKeyToAccount(privateKey);
|
|
187
|
+
const expirySec = Math.floor(Date.now() / 1000) + SESSION_DURATION_SEC;
|
|
188
|
+
const result = await this._client.grantPermissions({
|
|
189
|
+
account: this._address,
|
|
190
|
+
expirySec,
|
|
191
|
+
key: {
|
|
192
|
+
publicKey: sessionAccount.address,
|
|
193
|
+
type: 'secp256k1',
|
|
194
|
+
},
|
|
195
|
+
permissions: [{ type: 'root' }],
|
|
196
|
+
});
|
|
197
|
+
const context = result.context;
|
|
198
|
+
await saveSession(`sessionKeyData:${this._address.toLowerCase()}`, {
|
|
199
|
+
privateKey,
|
|
200
|
+
context,
|
|
201
|
+
expirySec,
|
|
202
|
+
smartAccountAddress: this._address,
|
|
203
|
+
});
|
|
204
|
+
const sessionSigner = new LocalAccountSigner(sessionAccount);
|
|
205
|
+
this._sessionPrivateKey = privateKey;
|
|
206
|
+
this._sessionKeyAddress = sessionAccount.address;
|
|
207
|
+
this._sessionExpirySec = expirySec;
|
|
208
|
+
this._sessionContext = context;
|
|
209
|
+
this._sessionClient = createSmartWalletClient({
|
|
210
|
+
chain: alchemyChain,
|
|
211
|
+
signer: sessionSigner,
|
|
212
|
+
policyId: this.config.paymasterPolicyId,
|
|
213
|
+
transport: alchemy({
|
|
214
|
+
apiKey: this.config.alchemyApiKey,
|
|
215
|
+
nodeRpcUrl: this.config.rpcUrl,
|
|
216
|
+
}),
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
privateKey,
|
|
220
|
+
sessionKeyAddress: sessionAccount.address,
|
|
221
|
+
context,
|
|
222
|
+
expirySec,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
get address() {
|
|
226
|
+
if (!this._address)
|
|
227
|
+
throw new Error('Rain not connected. Call rain.connect() first.');
|
|
228
|
+
return this._address;
|
|
229
|
+
}
|
|
230
|
+
get client() {
|
|
231
|
+
if (!this._client)
|
|
232
|
+
throw new Error('Rain not connected. Call rain.connect() first.');
|
|
233
|
+
return this._client;
|
|
234
|
+
}
|
|
235
|
+
/** Public address of the active session key (signs userOps locally — no popup). */
|
|
236
|
+
get sessionKeyAddress() {
|
|
237
|
+
return this._sessionKeyAddress;
|
|
238
|
+
}
|
|
239
|
+
/** Unix seconds when the current session permission expires. */
|
|
240
|
+
get sessionExpirySec() {
|
|
241
|
+
return this._sessionExpirySec;
|
|
242
|
+
}
|
|
243
|
+
/** Whether a fresh `connect()` would reuse the existing session (no MetaMask popup). */
|
|
244
|
+
get hasActiveSession() {
|
|
245
|
+
if (!this._sessionExpirySec)
|
|
246
|
+
return false;
|
|
247
|
+
return this._sessionExpirySec > Math.floor(Date.now() / 1000);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Sends a raw transaction from the smart account using the granted session
|
|
251
|
+
* key — no MetaMask popup per call. Returns the on-chain transaction hash.
|
|
252
|
+
*/
|
|
253
|
+
async sendTransaction(rawTx) {
|
|
254
|
+
if (!this._client || !this._account) {
|
|
255
|
+
throw new Error('Rain not connected. Call rain.connect() first.');
|
|
256
|
+
}
|
|
257
|
+
if (!this._sessionClient || !this._sessionContext) {
|
|
258
|
+
throw new Error('No active session. Call rain.grantSession() first to grant permission.');
|
|
259
|
+
}
|
|
260
|
+
const { id } = await this._sessionClient.sendCalls({
|
|
261
|
+
from: this._account.address,
|
|
262
|
+
calls: [{
|
|
263
|
+
to: rawTx.to,
|
|
264
|
+
data: rawTx.data,
|
|
265
|
+
value: toHex(rawTx.value ?? 0n),
|
|
266
|
+
}],
|
|
267
|
+
capabilities: {
|
|
268
|
+
permissions: { context: this._sessionContext },
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
const status = await this._sessionClient.waitForCallsStatus({ id });
|
|
272
|
+
const txHash = status.receipts?.[0]?.transactionHash;
|
|
273
|
+
if (!txHash) {
|
|
274
|
+
throw new Error(`Smart account call ${id} returned no transaction hash`);
|
|
275
|
+
}
|
|
276
|
+
return txHash;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Clear in-memory state. The persisted session in IndexedDB is preserved
|
|
280
|
+
* so reconnecting within the expiry window won't trigger a fresh
|
|
281
|
+
* grantPermissions popup. Call `forgetSession()` to wipe it explicitly.
|
|
282
|
+
*/
|
|
283
|
+
disconnect() {
|
|
284
|
+
this._client = null;
|
|
285
|
+
this._sessionClient = null;
|
|
286
|
+
this._account = null;
|
|
287
|
+
this._address = null;
|
|
288
|
+
this._sessionContext = null;
|
|
289
|
+
this._sessionKeyAddress = null;
|
|
290
|
+
this._sessionPrivateKey = null;
|
|
291
|
+
this._sessionExpirySec = null;
|
|
292
|
+
this._aaSdk = null;
|
|
293
|
+
this._walletClientLib = null;
|
|
294
|
+
this._viemAccounts = null;
|
|
295
|
+
this._alchemyChain = null;
|
|
296
|
+
this._alchemyTransportFactory = null;
|
|
297
|
+
}
|
|
298
|
+
async forgetSession() {
|
|
299
|
+
if (this._address) {
|
|
300
|
+
await deleteSession(`sessionKeyData:${this._address.toLowerCase()}`).catch(() => { });
|
|
301
|
+
}
|
|
302
|
+
this.disconnect();
|
|
303
|
+
}
|
|
304
|
+
}
|