@effectstream/wallets 0.100.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 +1 -0
- package/package.json +30 -0
- package/src/IProvider.ts +62 -0
- package/src/algorand/algorand.ts +168 -0
- package/src/algorand/wrapper.ts +22 -0
- package/src/avail/avail.ts +81 -0
- package/src/avail/wrapper.ts +44 -0
- package/src/cardano/cardano.ts +194 -0
- package/src/cardano/wrapper.ts +34 -0
- package/src/effectstream.ts +382 -0
- package/src/evm/ethers.ts +104 -0
- package/src/evm/injected.ts +429 -0
- package/src/evm/types.ts +2 -0
- package/src/evm/wrapper-ethers.ts +49 -0
- package/src/evm/wrapper-injected.ts +103 -0
- package/src/midnight/midnight.ts +196 -0
- package/src/midnight/wrapper.ts +36 -0
- package/src/mina/mina.ts +175 -0
- package/src/mina/wrapper.ts +22 -0
- package/src/mod.ts +10 -0
- package/src/polkadot/polkadot.ts +166 -0
- package/src/polkadot/wrapper.ts +30 -0
- package/src/types.ts +61 -0
- package/src/utils.test.ts +64 -0
- package/src/utils.ts +133 -0
- package/src/wallet-modes.ts +124 -0
- package/src/wallets.ts +62 -0
- package/src/windows.ts +10 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { AddressType, type EvmAddress } from "@effectstream/utils";
|
|
2
|
+
import type { Wallet } from "./types.ts";
|
|
3
|
+
import type { IProvider } from "./IProvider.ts";
|
|
4
|
+
import { type Chain, numberToHex } from "viem";
|
|
5
|
+
import { utf8ToHex } from "web3-utils";
|
|
6
|
+
import type { EthersEvmProvider } from "./evm/ethers.ts";
|
|
7
|
+
import type { EvmInjectedProvider } from "./evm/injected.ts";
|
|
8
|
+
import type { AbiItem } from "web3-utils";
|
|
9
|
+
import { type TransactionReceipt, Web3 } from "web3";
|
|
10
|
+
import { createMessageForBatcher } from "@effectstream/concise";
|
|
11
|
+
import { BuiltinEvents, EventManager } from "@effectstream/event-client";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This is main class used for setting up the Effectstream
|
|
15
|
+
* communication. It sets up the location of the Effectstream L2 Contact.
|
|
16
|
+
*/
|
|
17
|
+
export class EffectstreamConfig {
|
|
18
|
+
public appName: string;
|
|
19
|
+
public effectstreamL2SyncProtocolName: string;
|
|
20
|
+
public effectstreamL2ContractAddress: EvmAddress;
|
|
21
|
+
public effectstreamL2Abi: AbiItem[];
|
|
22
|
+
public effectstreamL2Chain: Chain;
|
|
23
|
+
public effectstreamL2CurrentFee: bigint = 0n;
|
|
24
|
+
public web3: Web3 | undefined = undefined;
|
|
25
|
+
public batcherURL: string | undefined = undefined;
|
|
26
|
+
public preferBatchedMode: boolean = false;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
appName: string | undefined,
|
|
30
|
+
effectstreamL2SyncProtocolName: string,
|
|
31
|
+
effectstreamL2ContractAddress: EvmAddress,
|
|
32
|
+
effectstreamL2Chain: Chain,
|
|
33
|
+
effectstreamL2Abi: AbiItem[] | undefined,
|
|
34
|
+
batcherURL: string | undefined,
|
|
35
|
+
preferBatchedMode: boolean = false,
|
|
36
|
+
) {
|
|
37
|
+
this.appName = appName ?? "";
|
|
38
|
+
|
|
39
|
+
this.effectstreamL2SyncProtocolName = effectstreamL2SyncProtocolName;
|
|
40
|
+
this.effectstreamL2ContractAddress = effectstreamL2ContractAddress;
|
|
41
|
+
this.effectstreamL2Abi = effectstreamL2Abi ?? this.fallbackABI();
|
|
42
|
+
this.effectstreamL2Chain = effectstreamL2Chain;
|
|
43
|
+
|
|
44
|
+
this.batcherURL = batcherURL;
|
|
45
|
+
if (!this.batcherURL && preferBatchedMode) {
|
|
46
|
+
throw new Error("To enable batcher, you need to set the batcher URL.");
|
|
47
|
+
}
|
|
48
|
+
this.preferBatchedMode = preferBatchedMode;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Return a Web3 client for the EffectstreamL2 chain. */
|
|
52
|
+
public async getWeb3Client(): Promise<Web3> {
|
|
53
|
+
if (this.web3) {
|
|
54
|
+
return this.web3;
|
|
55
|
+
}
|
|
56
|
+
this.web3 = new Web3(this.effectstreamL2Chain.rpcUrls.default.http[0]);
|
|
57
|
+
await this.web3.eth.getNodeInfo();
|
|
58
|
+
return this.web3;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Return a Effectstream L2 Contract Instance for the EffectstreamL2. */
|
|
62
|
+
public async getEffectstreamL2Contract() {
|
|
63
|
+
const web3 = await this.getWeb3Client();
|
|
64
|
+
return new web3.eth.Contract(this.effectstreamL2Abi, this.effectstreamL2ContractAddress);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private fallbackABI(): AbiItem[] {
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
inputs: [{ name: "data", type: "bytes" }],
|
|
71
|
+
name: "effectstreamSubmitGameInput",
|
|
72
|
+
outputs: [],
|
|
73
|
+
stateMutability: "payable",
|
|
74
|
+
type: "function",
|
|
75
|
+
},
|
|
76
|
+
] as const;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Effectstream Wallet Interface - Sign a message with a wallet.
|
|
82
|
+
* @param wallet - The wallet to sign the message with.
|
|
83
|
+
* @param message - The message to sign.
|
|
84
|
+
* @returns
|
|
85
|
+
*/
|
|
86
|
+
export async function signMessage(wallet: Wallet, message: string) {
|
|
87
|
+
const signature = await wallet.provider.signMessage(message);
|
|
88
|
+
return signature;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Main function to send a transaction to a Effectstream L2 contract.
|
|
93
|
+
* It will decide whether to use the batcher or the self-sequenced transaction based on the preferBatchedMode flag.
|
|
94
|
+
*
|
|
95
|
+
* @param wallet - The wallet to send the transaction with.
|
|
96
|
+
* @param conciseData - The concise data to send.
|
|
97
|
+
* @param effectstreamConfig - The Effectstream configuration.
|
|
98
|
+
* @param waitForConfirmation - The confirmation mode to use:
|
|
99
|
+
* no-wait: Do not wait for any confirmation.
|
|
100
|
+
* wait-receipt: Wait only for the chain transaction receipt.
|
|
101
|
+
* wait-effectstream-processed: Wait for the transaction to be processed by the Effectstream.
|
|
102
|
+
* @returns
|
|
103
|
+
*/
|
|
104
|
+
export async function sendTransaction(
|
|
105
|
+
wallet: Wallet,
|
|
106
|
+
conciseData: any[],
|
|
107
|
+
effectstreamConfig: EffectstreamConfig,
|
|
108
|
+
waitForConfirmation: "wait-effectstream-processed" | "wait-receipt" | "no-wait" =
|
|
109
|
+
"wait-effectstream-processed",
|
|
110
|
+
batcherTarget: string | undefined = undefined,
|
|
111
|
+
): Promise<
|
|
112
|
+
| ReturnType<typeof sendBatcherTransaction>
|
|
113
|
+
| ReturnType<typeof sendSelfSequencedTransaction>
|
|
114
|
+
> {
|
|
115
|
+
if (effectstreamConfig.preferBatchedMode) {
|
|
116
|
+
return await sendBatcherTransaction(
|
|
117
|
+
wallet,
|
|
118
|
+
conciseData,
|
|
119
|
+
effectstreamConfig,
|
|
120
|
+
waitForConfirmation,
|
|
121
|
+
batcherTarget,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return await sendSelfSequencedTransaction(
|
|
125
|
+
wallet,
|
|
126
|
+
conciseData,
|
|
127
|
+
effectstreamConfig,
|
|
128
|
+
waitForConfirmation,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Effectstream Wallet Interface - Send a transaction to a Effectstream L2 contract with a wallet.
|
|
134
|
+
* The concise data must match the grammar; if not the input will be rejected by Effectstream.
|
|
135
|
+
* @param wallet - The wallet to send the transaction with.
|
|
136
|
+
* @param conciseData - The concise data to send.
|
|
137
|
+
* @param effectstreamConfig - The Effectstream configuration.
|
|
138
|
+
* @param waitForConfirmation - The confirmation mode to use:
|
|
139
|
+
* no-wait: Do not wait for any confirmation.
|
|
140
|
+
* wait-receipt: Wait only for the chain transaction receipt.
|
|
141
|
+
* wait-effectstream-processed: Wait for the transaction to be processed by the Effectstream.
|
|
142
|
+
** @returns
|
|
143
|
+
*/
|
|
144
|
+
export async function sendSelfSequencedTransaction(
|
|
145
|
+
wallet: Wallet,
|
|
146
|
+
// TODO this should be any type of grammar.
|
|
147
|
+
conciseData: any[],
|
|
148
|
+
effectstreamConfig: EffectstreamConfig,
|
|
149
|
+
waitForConfirmation: "wait-effectstream-processed" | "wait-receipt" | "no-wait" =
|
|
150
|
+
"wait-effectstream-processed",
|
|
151
|
+
): Promise<
|
|
152
|
+
& {
|
|
153
|
+
success: boolean;
|
|
154
|
+
type: "self-sequenced";
|
|
155
|
+
}
|
|
156
|
+
& (
|
|
157
|
+
| {
|
|
158
|
+
wait: "wait-effectstream-processed";
|
|
159
|
+
hash: string;
|
|
160
|
+
receipt: TransactionReceipt;
|
|
161
|
+
rollup: number;
|
|
162
|
+
}
|
|
163
|
+
| {
|
|
164
|
+
wait: "wait-receipt" | "no-wait";
|
|
165
|
+
hash: string;
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
> {
|
|
169
|
+
// TODO: Where to get this value from?
|
|
170
|
+
const DEFAULT_GAS_PRICE = BigInt("61000000000");
|
|
171
|
+
|
|
172
|
+
const provider: IProvider<unknown> = wallet.provider;
|
|
173
|
+
const addressAndType = provider.getAddress();
|
|
174
|
+
|
|
175
|
+
// NOTE: If the Effectstream L2 contract interface is implemented in other chains,
|
|
176
|
+
// we need to add support for them here. Effectstream L2 is EVM only for now.
|
|
177
|
+
if (addressAndType.type !== AddressType.EVM) {
|
|
178
|
+
throw new Error("Effectstream L2 is EVM contract.");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const evmProvider = wallet.provider as
|
|
182
|
+
| EthersEvmProvider
|
|
183
|
+
| EvmInjectedProvider;
|
|
184
|
+
|
|
185
|
+
const hexData = utf8ToHex(JSON.stringify(conciseData));
|
|
186
|
+
const effectstreamL2Contract = await effectstreamConfig.getEffectstreamL2Contract();
|
|
187
|
+
|
|
188
|
+
const txData = effectstreamL2Contract.methods["effectstreamSubmitGameInput"](hexData)
|
|
189
|
+
.encodeABI();
|
|
190
|
+
const tx = {
|
|
191
|
+
from: addressAndType.address,
|
|
192
|
+
data: txData,
|
|
193
|
+
to: effectstreamConfig.effectstreamL2ContractAddress,
|
|
194
|
+
gasPrice: numberToHex(DEFAULT_GAS_PRICE),
|
|
195
|
+
value: numberToHex(effectstreamConfig.effectstreamL2CurrentFee),
|
|
196
|
+
};
|
|
197
|
+
const tx_result = await evmProvider.sendTransaction(tx);
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
waitForConfirmation === "no-wait" || waitForConfirmation === "wait-receipt"
|
|
201
|
+
) {
|
|
202
|
+
return {
|
|
203
|
+
success: true,
|
|
204
|
+
type: "self-sequenced",
|
|
205
|
+
wait: waitForConfirmation,
|
|
206
|
+
hash: tx_result.txHash,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Wait for paima engine to process the transaction
|
|
211
|
+
const receipt = await getTxReceipt(tx_result.txHash, effectstreamConfig);
|
|
212
|
+
|
|
213
|
+
const response = await waitForEffectstreamBlockProcessed(
|
|
214
|
+
Number(receipt.blockNumber),
|
|
215
|
+
effectstreamConfig,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const rollup = response ? response.rollup : 0;
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
success: true,
|
|
222
|
+
type: "self-sequenced",
|
|
223
|
+
hash: tx_result.txHash,
|
|
224
|
+
wait: waitForConfirmation,
|
|
225
|
+
receipt: serializeBigInts(receipt),
|
|
226
|
+
rollup,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// We return a json version of object for the frontend.
|
|
231
|
+
function serializeBigInts<T>(value: T): T {
|
|
232
|
+
return JSON.parse(
|
|
233
|
+
JSON.stringify(
|
|
234
|
+
value,
|
|
235
|
+
(_, v) => typeof v === "bigint" ? v.toString() : v,
|
|
236
|
+
),
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Wait for the transaction receipt for a given transaction hash.
|
|
241
|
+
async function getTxReceipt(
|
|
242
|
+
txHash: string,
|
|
243
|
+
effectstreamConfig: EffectstreamConfig,
|
|
244
|
+
): Promise<TransactionReceipt> {
|
|
245
|
+
const web3 = await effectstreamConfig.getWeb3Client();
|
|
246
|
+
return await web3.eth.getTransactionReceipt(txHash);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Wait for specific block number to be processed by the Effectstream.
|
|
251
|
+
* This guarantees that the block number is processed by the Effectstream.
|
|
252
|
+
* @param blockNumber - The block number to wait for.
|
|
253
|
+
* @param effectstreamConfig - The Effectstream configuration.
|
|
254
|
+
* @param timeout (optional) - The timeout in milliseconds.
|
|
255
|
+
* @returns
|
|
256
|
+
*/
|
|
257
|
+
export function waitForEffectstreamBlockProcessed(
|
|
258
|
+
blockNumber: number,
|
|
259
|
+
effectstreamConfig: EffectstreamConfig,
|
|
260
|
+
timeout: number = 60000,
|
|
261
|
+
): Promise<{ latestBlock: number; rollup: number } | void> {
|
|
262
|
+
let subscriptionReference: symbol | undefined = undefined;
|
|
263
|
+
let latestBlock = 0;
|
|
264
|
+
let timer: any = undefined; // node & deno differ in type of timer
|
|
265
|
+
|
|
266
|
+
return Promise.race([
|
|
267
|
+
new Promise<void>((_, reject) => {
|
|
268
|
+
timer = setTimeout(() => reject(new Error("Timeout")), timeout);
|
|
269
|
+
}),
|
|
270
|
+
new Promise<{ latestBlock: number; rollup: number }>((resolve, reject) => {
|
|
271
|
+
if (!effectstreamConfig.effectstreamL2SyncProtocolName) {
|
|
272
|
+
reject(new Error("Effectstream L2 Sync Protocol Name is not set"));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
EventManager.Instance.subscribe(
|
|
277
|
+
{
|
|
278
|
+
topic: BuiltinEvents.SyncChains,
|
|
279
|
+
filter: {
|
|
280
|
+
chain: effectstreamConfig.effectstreamL2SyncProtocolName,
|
|
281
|
+
block: undefined,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
(event) => {
|
|
285
|
+
latestBlock = Math.max(event.block, latestBlock);
|
|
286
|
+
if (latestBlock > blockNumber) {
|
|
287
|
+
resolve({ latestBlock, rollup: event.rollup });
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
)
|
|
291
|
+
.then((subscription) => subscriptionReference = subscription)
|
|
292
|
+
.catch(reject);
|
|
293
|
+
}),
|
|
294
|
+
]).finally(() => {
|
|
295
|
+
if (subscriptionReference) {
|
|
296
|
+
EventManager.Instance.unsubscribe(subscriptionReference);
|
|
297
|
+
}
|
|
298
|
+
if (timer) {
|
|
299
|
+
clearTimeout(timer);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Effectstream Wallet Interface - Standard batcher communication for a Effectstream L2 contract.
|
|
306
|
+
* This is only a default implementation, your own batcher might have different requirements.
|
|
307
|
+
* @param wallet - The wallet to send the batched transaction with.
|
|
308
|
+
* @param effectstreamL2Address - The address of the Effectstream L2 contract.
|
|
309
|
+
* @param conciseData - The concise data to send.
|
|
310
|
+
* @param waitForConfirmation - The confirmation mode to use:
|
|
311
|
+
* no-wait: Do not wait for any confirmation.
|
|
312
|
+
* wait-receipt: Wait only for the chain transaction receipt.
|
|
313
|
+
* wait-effectstream-processed: Wait for the transaction to be processed by the Effectstream.
|
|
314
|
+
* @returns
|
|
315
|
+
*/
|
|
316
|
+
export async function sendBatcherTransaction(
|
|
317
|
+
wallet: Wallet,
|
|
318
|
+
// TODO we need to pass the batcher address here.
|
|
319
|
+
conciseData: any[],
|
|
320
|
+
effectstreamConfig: EffectstreamConfig,
|
|
321
|
+
waitForConfirmation: "wait-effectstream-processed" | "wait-receipt" | "no-wait" =
|
|
322
|
+
"wait-effectstream-processed",
|
|
323
|
+
batcherTarget: string | undefined = undefined,
|
|
324
|
+
): Promise<{
|
|
325
|
+
success: boolean;
|
|
326
|
+
type: "batcher";
|
|
327
|
+
message: string;
|
|
328
|
+
blockNumber: number;
|
|
329
|
+
blockHash: string;
|
|
330
|
+
rollup: number;
|
|
331
|
+
}> {
|
|
332
|
+
if (!effectstreamConfig.batcherURL) {
|
|
333
|
+
throw new Error("Batcher URL is not set");
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const conciseDataStr = JSON.stringify(conciseData);
|
|
337
|
+
// Send a batched message.
|
|
338
|
+
const timestamp = Date.now().toString();
|
|
339
|
+
const signature = await wallet.provider.signMessage(
|
|
340
|
+
createMessageForBatcher(
|
|
341
|
+
effectstreamConfig.appName,
|
|
342
|
+
timestamp,
|
|
343
|
+
wallet.provider.getAddress().address,
|
|
344
|
+
wallet.provider.getAddress().type,
|
|
345
|
+
conciseDataStr,
|
|
346
|
+
batcherTarget,
|
|
347
|
+
),
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const response = await fetch(
|
|
351
|
+
`${effectstreamConfig.batcherURL}/send-input`,
|
|
352
|
+
{
|
|
353
|
+
method: "POST",
|
|
354
|
+
headers: {
|
|
355
|
+
"Content-Type": "application/json",
|
|
356
|
+
},
|
|
357
|
+
body: JSON.stringify({
|
|
358
|
+
data: {
|
|
359
|
+
target: batcherTarget,
|
|
360
|
+
addressType: wallet.provider.getAddress().type,
|
|
361
|
+
address: wallet.provider.getAddress().address,
|
|
362
|
+
signature,
|
|
363
|
+
input: conciseDataStr,
|
|
364
|
+
timestamp,
|
|
365
|
+
},
|
|
366
|
+
confirmationLevel: waitForConfirmation,
|
|
367
|
+
}),
|
|
368
|
+
},
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
return await {
|
|
372
|
+
...(await (response.json() as Promise<{
|
|
373
|
+
success: boolean;
|
|
374
|
+
message: string;
|
|
375
|
+
blockNumber: number;
|
|
376
|
+
blockHash: string;
|
|
377
|
+
rollup: number;
|
|
378
|
+
}>)),
|
|
379
|
+
type: "batcher",
|
|
380
|
+
success: response.ok,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Signer,
|
|
3
|
+
TransactionLike,
|
|
4
|
+
TransactionRequest,
|
|
5
|
+
TransactionResponse,
|
|
6
|
+
} from "ethers";
|
|
7
|
+
|
|
8
|
+
import { Buffer } from "node:buffer";
|
|
9
|
+
import { AddressType } from "@effectstream/utils";
|
|
10
|
+
import type {
|
|
11
|
+
ActiveConnection,
|
|
12
|
+
AddressAndType,
|
|
13
|
+
IProvider,
|
|
14
|
+
UserSignature,
|
|
15
|
+
} from "../IProvider.ts";
|
|
16
|
+
import { DEFAULT_GAS_LIMIT, type EvmAddress } from "./types.ts";
|
|
17
|
+
import { utf8ToHex } from "web3-utils";
|
|
18
|
+
|
|
19
|
+
export type EthersApi = Signer;
|
|
20
|
+
|
|
21
|
+
export class EthersConnector {
|
|
22
|
+
private provider: EthersEvmProvider | undefined;
|
|
23
|
+
private static INSTANCE: undefined | EthersConnector = undefined;
|
|
24
|
+
|
|
25
|
+
static instance(): EthersConnector {
|
|
26
|
+
if (EthersConnector.INSTANCE == null) {
|
|
27
|
+
const newInstance = new EthersConnector();
|
|
28
|
+
EthersConnector.INSTANCE = newInstance;
|
|
29
|
+
}
|
|
30
|
+
return EthersConnector.INSTANCE;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
connectExternal = async (conn: EthersApi): Promise<EthersEvmProvider> => {
|
|
34
|
+
this.provider = await EthersEvmProvider.init(conn);
|
|
35
|
+
return this.provider;
|
|
36
|
+
};
|
|
37
|
+
getProvider = (): undefined | EthersEvmProvider => {
|
|
38
|
+
return this.provider;
|
|
39
|
+
};
|
|
40
|
+
getOrThrowProvider = (): EthersEvmProvider => {
|
|
41
|
+
if (this.provider == null) {
|
|
42
|
+
throw new Error(`EthersConnector not initialized yet`);
|
|
43
|
+
}
|
|
44
|
+
return this.provider;
|
|
45
|
+
};
|
|
46
|
+
isConnected = (): boolean => {
|
|
47
|
+
return this.provider != null;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export class EthersEvmProvider implements IProvider<EthersApi> {
|
|
51
|
+
constructor(
|
|
52
|
+
private readonly conn: ActiveConnection<EthersApi>,
|
|
53
|
+
readonly address: EvmAddress,
|
|
54
|
+
) {}
|
|
55
|
+
|
|
56
|
+
static init = async (api: EthersApi): Promise<EthersEvmProvider> => {
|
|
57
|
+
const address = await api.getAddress();
|
|
58
|
+
const conn = {
|
|
59
|
+
api: api,
|
|
60
|
+
metadata: {
|
|
61
|
+
name: "Ethers",
|
|
62
|
+
displayName: "Ethers",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
return new EthersEvmProvider(conn, address);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
getConnection = (): ActiveConnection<EthersApi> => {
|
|
69
|
+
return this.conn;
|
|
70
|
+
};
|
|
71
|
+
getAddress = (): AddressAndType => {
|
|
72
|
+
return {
|
|
73
|
+
type: AddressType.EVM,
|
|
74
|
+
address: this.address.toLowerCase(),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
signMessage = async (message: string): Promise<UserSignature> => {
|
|
78
|
+
const hexMessage = utf8ToHex(message);
|
|
79
|
+
const buffer = Buffer.from(hexMessage.slice(2), "hex");
|
|
80
|
+
const signature = await this.conn.api.signMessage(buffer);
|
|
81
|
+
return signature;
|
|
82
|
+
};
|
|
83
|
+
finalizeTransaction = async (
|
|
84
|
+
tx: TransactionRequest,
|
|
85
|
+
): Promise<TransactionLike<string>> => {
|
|
86
|
+
return await this.conn.api.populateTransaction({
|
|
87
|
+
gasLimit: DEFAULT_GAS_LIMIT,
|
|
88
|
+
...tx,
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
sendTransaction = async (
|
|
92
|
+
tx: TransactionRequest,
|
|
93
|
+
): Promise<{
|
|
94
|
+
txHash: string;
|
|
95
|
+
extra: TransactionResponse;
|
|
96
|
+
}> => {
|
|
97
|
+
const finalTx = await this.finalizeTransaction(tx);
|
|
98
|
+
const result = await this.conn.api.sendTransaction(finalTx);
|
|
99
|
+
return {
|
|
100
|
+
txHash: result.hash,
|
|
101
|
+
extra: result,
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}
|