@dfns/lib-ethersjs6 0.1.2 → 0.1.3-rc.2

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.
Files changed (3) hide show
  1. package/index.d.ts +8 -2
  2. package/index.js +127 -63
  3. package/package.json +3 -3
package/index.d.ts CHANGED
@@ -3,16 +3,22 @@ import { AbstractSigner, Provider, Signer, TransactionRequest, TypedDataDomain,
3
3
  export type DfnsWalletOptions = {
4
4
  walletId: string;
5
5
  dfnsClient: DfnsApiClient;
6
+ /** @deprecated transaction signing is now synchronous. polling is deprecated. */
6
7
  maxRetries?: number;
8
+ /** @deprecated transaction signing is now synchronous. polling is deprecated. */
7
9
  retryInterval?: number;
8
10
  };
9
11
  export declare class DfnsWallet extends AbstractSigner {
10
- private address?;
11
12
  private options;
13
+ private address?;
14
+ private metadata?;
15
+ /** @deprecated use DfnsWallet.init(options) instead */
12
16
  constructor(options: DfnsWalletOptions, provider?: Provider | null);
17
+ static init(options: DfnsWalletOptions): Promise<DfnsWallet>;
13
18
  connect(provider: Provider | null): Signer;
19
+ private getCachedMetadata;
14
20
  getAddress(): Promise<string>;
15
- waitForSignature(signatureId: string): Promise<string>;
21
+ private signHash;
16
22
  signTransaction(tx: TransactionRequest): Promise<string>;
17
23
  signMessage(message: string | Uint8Array): Promise<string>;
18
24
  signTypedData(domain: TypedDataDomain, types: Record<string, TypedDataField[]>, value: Record<string, any>): Promise<string>;
package/index.js CHANGED
@@ -1,59 +1,91 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DfnsWallet = void 0;
4
- const Wallets_1 = require("@dfns/sdk/codegen/datamodel/Wallets");
4
+ const sdk_1 = require("@dfns/sdk");
5
5
  const ethers_1 = require("ethers");
6
- const sleep = (interval = 0) => new Promise((resolve) => setTimeout(resolve, interval));
6
+ const assertSigned = (res) => {
7
+ if (res.status === 'Failed') {
8
+ throw new sdk_1.DfnsError(-1, 'signing failed', res);
9
+ }
10
+ else if (res.status !== 'Signed') {
11
+ throw new sdk_1.DfnsError(-1, 'cannot complete signing synchronously because this wallet action requires policy approval', res);
12
+ }
13
+ };
14
+ const combineSignature = (res) => {
15
+ if (!res.signature) {
16
+ throw new sdk_1.DfnsError(-1, 'signature missing', res);
17
+ }
18
+ const { r, s, recid } = res.signature;
19
+ return ethers_1.Signature.from({
20
+ r,
21
+ s,
22
+ v: recid ? 0x1c : 0x1b,
23
+ }).serialized;
24
+ };
25
+ const boundToEvmNetwork = (wallet) => {
26
+ // if the address is evm format, it's a wallet bound to evm network. prefer to
27
+ // sign the full transaction instead of the hash of the transaction
28
+ return wallet.address ? !!wallet.address.match(/^0x[0-9a-fA-F]{40}$/) : false;
29
+ };
30
+ const fetchWalletMetadata = async (options) => {
31
+ const { walletId, dfnsClient } = options;
32
+ const wallet = await dfnsClient.wallets.getWallet({ walletId });
33
+ if (wallet.status !== 'Active') {
34
+ throw new sdk_1.DfnsError(-1, 'wallet not active', { walletId, status: wallet.status });
35
+ }
36
+ const { scheme, curve } = wallet.signingKey;
37
+ if (scheme !== 'ECDSA') {
38
+ throw new sdk_1.DfnsError(-1, 'key scheme is not ECDSA', { walletId, scheme });
39
+ }
40
+ if (curve !== 'secp256k1') {
41
+ throw new sdk_1.DfnsError(-1, 'key curve is not secp256k1', { walletId, curve });
42
+ }
43
+ return {
44
+ boundToEvmNetwork: boundToEvmNetwork(wallet),
45
+ ...wallet,
46
+ };
47
+ };
7
48
  class DfnsWallet extends ethers_1.AbstractSigner {
49
+ /** @deprecated use DfnsWallet.init(options) instead */
8
50
  constructor(options, provider) {
9
51
  super(provider);
10
- this.options = {
11
- ...options,
12
- maxRetries: options.maxRetries ?? 3,
13
- retryInterval: options.retryInterval ?? 1000,
14
- };
52
+ this.options = options;
53
+ }
54
+ static async init(options) {
55
+ const metadata = await fetchWalletMetadata(options);
56
+ const wallet = new DfnsWallet(options);
57
+ wallet.metadata = metadata;
58
+ return wallet;
15
59
  }
16
60
  connect(provider) {
17
- return new DfnsWallet(this.options, provider);
61
+ const copy = new DfnsWallet(this.options, provider);
62
+ copy.address = this.address;
63
+ copy.metadata = this.metadata;
64
+ return copy;
65
+ }
66
+ async getCachedMetadata() {
67
+ if (!this.metadata) {
68
+ this.metadata = await fetchWalletMetadata(this.options);
69
+ }
70
+ return this.metadata;
18
71
  }
19
72
  async getAddress() {
20
73
  if (!this.address) {
21
- const { walletId, dfnsClient } = this.options;
22
- const res = await dfnsClient.wallets.getWallet({ walletId });
23
- if (!res.signingKey || res.signingKey.scheme !== Wallets_1.KeyScheme.ECDSA || res.signingKey.curve !== Wallets_1.KeyCurve.secp256k1) {
24
- throw new Error(`wallet ${walletId} has incompatible scheme (${res.signingKey?.scheme}) or curve (${res.signingKey?.curve})`);
25
- }
26
- if (res.address) {
27
- this.address = (0, ethers_1.getAddress)(res.address);
28
- }
29
- else {
30
- this.address = (0, ethers_1.computeAddress)('0x' + res.signingKey.publicKey);
31
- }
74
+ const metadata = await this.getCachedMetadata();
75
+ this.address = metadata.boundToEvmNetwork
76
+ ? (0, ethers_1.getAddress)(metadata.address)
77
+ : (0, ethers_1.computeAddress)('0x' + metadata.signingKey.publicKey);
32
78
  }
33
79
  return this.address;
34
80
  }
35
- async waitForSignature(signatureId) {
36
- const { walletId, dfnsClient, retryInterval } = this.options;
37
- let maxRetries = this.options.maxRetries;
38
- while (maxRetries > 0) {
39
- await sleep(retryInterval);
40
- const res = await dfnsClient.wallets.getSignature({ walletId, signatureId });
41
- if (res.status === Wallets_1.SignatureStatus.Signed) {
42
- if (!res.signature)
43
- break;
44
- return ethers_1.Signature.from({
45
- r: res.signature.r,
46
- s: res.signature.s,
47
- v: res.signature.recid ? 0x1c : 0x1b,
48
- }).serialized;
49
- }
50
- else if (res.status === Wallets_1.SignatureStatus.Failed) {
51
- break;
52
- }
53
- maxRetries -= 1;
54
- }
55
- const waitedSeconds = Math.floor((this.options.maxRetries * retryInterval) / 1000);
56
- throw new Error(`Signature request ${signatureId} took more than ${waitedSeconds}s to complete, stopping polling. Please update options "maxRetries" or "retryIntervals" to wait longer.`);
81
+ async signHash(hash) {
82
+ const { walletId, dfnsClient } = this.options;
83
+ const res = await dfnsClient.wallets.generateSignature({
84
+ walletId,
85
+ body: { kind: 'Hash', hash },
86
+ });
87
+ assertSigned(res);
88
+ return combineSignature(res);
57
89
  }
58
90
  async signTransaction(tx) {
59
91
  // replace any Addressable or ENS name with an address
@@ -74,21 +106,39 @@ class DfnsWallet extends ethers_1.AbstractSigner {
74
106
  delete tx.from;
75
107
  }
76
108
  const btx = ethers_1.Transaction.from(tx);
77
- const { walletId, dfnsClient } = this.options;
78
- const res = await dfnsClient.wallets.generateSignature({
79
- walletId,
80
- body: { kind: Wallets_1.SignatureKind.Hash, hash: btx.unsignedHash },
81
- });
82
- btx.signature = await this.waitForSignature(res.id);
83
- return btx.serialized;
109
+ const metadata = await this.getCachedMetadata();
110
+ if (metadata.boundToEvmNetwork) {
111
+ const res = await this.options.dfnsClient.wallets.generateSignature({
112
+ walletId: metadata.id,
113
+ body: { kind: 'Transaction', transaction: btx.unsignedSerialized },
114
+ });
115
+ assertSigned(res);
116
+ if (!res.signedData) {
117
+ throw new sdk_1.DfnsError(-1, 'signedData missing', res);
118
+ }
119
+ return res.signedData;
120
+ }
121
+ else {
122
+ btx.signature = await this.signHash(btx.unsignedHash);
123
+ return btx.serialized;
124
+ }
84
125
  }
85
126
  async signMessage(message) {
86
- const { walletId, dfnsClient } = this.options;
87
- const res = await dfnsClient.wallets.generateSignature({
88
- walletId,
89
- body: { kind: Wallets_1.SignatureKind.Hash, hash: (0, ethers_1.hashMessage)(message) },
90
- });
91
- return this.waitForSignature(res.id);
127
+ const metadata = await this.getCachedMetadata();
128
+ if (metadata.boundToEvmNetwork) {
129
+ if (typeof message === 'string') {
130
+ message = (0, ethers_1.toUtf8Bytes)(message);
131
+ }
132
+ const res = await this.options.dfnsClient.wallets.generateSignature({
133
+ walletId: metadata.id,
134
+ body: { kind: 'Message', message: (0, ethers_1.hexlify)(message) },
135
+ });
136
+ assertSigned(res);
137
+ return combineSignature(res);
138
+ }
139
+ else {
140
+ return this.signHash((0, ethers_1.hashMessage)(message));
141
+ }
92
142
  }
93
143
  async signTypedData(domain, types, value) {
94
144
  // Populate any ENS names
@@ -101,15 +151,29 @@ class DfnsWallet extends ethers_1.AbstractSigner {
101
151
  throw new Error(`unconfigured ENS name ${name}`);
102
152
  return address;
103
153
  });
104
- const { walletId, dfnsClient } = this.options;
105
- const res = await dfnsClient.wallets.generateSignature({
106
- walletId,
107
- body: {
108
- kind: Wallets_1.SignatureKind.Hash,
109
- hash: ethers_1.TypedDataEncoder.hash(populated.domain, types, populated.value),
110
- },
111
- });
112
- return this.waitForSignature(res.id);
154
+ const metadata = await this.getCachedMetadata();
155
+ if (metadata.boundToEvmNetwork) {
156
+ const res = await this.options.dfnsClient.wallets.generateSignature({
157
+ walletId: metadata.id,
158
+ body: {
159
+ kind: 'Eip712',
160
+ types,
161
+ domain: {
162
+ name: populated.domain.name ?? undefined,
163
+ version: populated.domain.version ?? undefined,
164
+ chainId: populated.domain.chainId ? (0, ethers_1.getNumber)(populated.domain.chainId) : undefined,
165
+ verifyingContract: populated.domain.verifyingContract ?? undefined,
166
+ salt: populated.domain.salt ? (0, ethers_1.hexlify)(populated.domain.salt) : undefined,
167
+ },
168
+ message: populated.value,
169
+ },
170
+ });
171
+ assertSigned(res);
172
+ return combineSignature(res);
173
+ }
174
+ else {
175
+ return this.signHash(ethers_1.TypedDataEncoder.hash(populated.domain, types, populated.value));
176
+ }
113
177
  }
114
178
  }
115
179
  exports.DfnsWallet = DfnsWallet;
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@dfns/lib-ethersjs6",
3
- "version": "0.1.2",
3
+ "version": "0.1.3-rc.2",
4
4
  "dependencies": {
5
5
  "buffer": "6.0.3",
6
6
  "cross-fetch": "3.1.6",
7
- "ethers": "6.6.1",
7
+ "ethers": "6.9.0",
8
8
  "uuid": "9.0.0"
9
9
  },
10
10
  "peerDependencies": {
11
- "@dfns/sdk": "0.1.2"
11
+ "@dfns/sdk": "0.1.3-rc.2"
12
12
  },
13
13
  "main": "./index.js",
14
14
  "type": "commonjs"