@dfns/lib-ethersjs5 0.1.2-rc.5 → 0.1.3-rc.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/index.d.ts +8 -2
- package/index.js +130 -63
- package/package.json +4 -2
package/index.d.ts
CHANGED
|
@@ -4,16 +4,22 @@ import { Signer, TypedDataDomain, TypedDataField, TypedDataSigner } from '@ether
|
|
|
4
4
|
export type DfnsWalletOptions = {
|
|
5
5
|
walletId: string;
|
|
6
6
|
dfnsClient: DfnsApiClient;
|
|
7
|
+
/** @deprecated transaction signing is now synchronous. polling is deprecated. */
|
|
7
8
|
maxRetries?: number;
|
|
9
|
+
/** @deprecated transaction signing is now synchronous. polling is deprecated. */
|
|
8
10
|
retryInterval?: number;
|
|
9
11
|
};
|
|
10
12
|
export declare class DfnsWallet extends Signer implements TypedDataSigner {
|
|
11
|
-
private address?;
|
|
12
13
|
private options;
|
|
14
|
+
private address?;
|
|
15
|
+
private metadata?;
|
|
16
|
+
/** @deprecated use DfnsWallet.init(options) instead */
|
|
13
17
|
constructor(options: DfnsWalletOptions, provider?: Provider | null);
|
|
18
|
+
static init(options: DfnsWalletOptions): Promise<DfnsWallet>;
|
|
14
19
|
connect(provider: Provider | null): Signer;
|
|
20
|
+
private getCachedMetadata;
|
|
15
21
|
getAddress(): Promise<string>;
|
|
16
|
-
|
|
22
|
+
private signHash;
|
|
17
23
|
signTransaction(transaction: TransactionRequest): Promise<string>;
|
|
18
24
|
signMessage(message: string | Uint8Array): Promise<string>;
|
|
19
25
|
_signTypedData(domain: TypedDataDomain, types: Record<string, TypedDataField[]>, value: Record<string, any>): Promise<string>;
|
package/index.js
CHANGED
|
@@ -1,66 +1,100 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DfnsWallet = void 0;
|
|
4
|
-
const
|
|
4
|
+
const sdk_1 = require("@dfns/sdk");
|
|
5
5
|
const address_1 = require("@ethersproject/address");
|
|
6
6
|
const abstract_signer_1 = require("@ethersproject/abstract-signer");
|
|
7
|
+
const bignumber_1 = require("@ethersproject/bignumber");
|
|
7
8
|
const bytes_1 = require("@ethersproject/bytes");
|
|
8
9
|
const hash_1 = require("@ethersproject/hash");
|
|
9
10
|
const keccak256_1 = require("@ethersproject/keccak256");
|
|
10
11
|
const properties_1 = require("@ethersproject/properties");
|
|
12
|
+
const strings_1 = require("@ethersproject/strings");
|
|
11
13
|
const transactions_1 = require("@ethersproject/transactions");
|
|
12
|
-
const
|
|
14
|
+
const assertSigned = (res) => {
|
|
15
|
+
if (res.status === 'Failed') {
|
|
16
|
+
throw new sdk_1.DfnsError(-1, 'signing failed', res);
|
|
17
|
+
}
|
|
18
|
+
else if (res.status !== 'Signed') {
|
|
19
|
+
throw new sdk_1.DfnsError(-1, 'cannot complete signing synchronously because this wallet action requires policy approval', res);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const combineSignature = (res) => {
|
|
23
|
+
if (!res.signature) {
|
|
24
|
+
throw new sdk_1.DfnsError(-1, 'signature missing', res);
|
|
25
|
+
}
|
|
26
|
+
const { r, s, recid } = res.signature;
|
|
27
|
+
return (0, bytes_1.joinSignature)({
|
|
28
|
+
r,
|
|
29
|
+
s,
|
|
30
|
+
recoveryParam: recid,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
const boundToEvmNetwork = (wallet) => {
|
|
34
|
+
// if the address is evm format, it's a wallet bound to evm network. prefer to
|
|
35
|
+
// sign the full transaction instead of the hash of the transaction
|
|
36
|
+
return wallet.address ? !!wallet.address.match(/^0x[0-9a-fA-F]{40}$/) : false;
|
|
37
|
+
};
|
|
38
|
+
const fetchWalletMetadata = async (options) => {
|
|
39
|
+
const { walletId, dfnsClient } = options;
|
|
40
|
+
const wallet = await dfnsClient.wallets.getWallet({ walletId });
|
|
41
|
+
if (wallet.status !== 'Active') {
|
|
42
|
+
throw new sdk_1.DfnsError(-1, 'wallet not active', { walletId, status: wallet.status });
|
|
43
|
+
}
|
|
44
|
+
const { scheme, curve } = wallet.signingKey;
|
|
45
|
+
if (scheme !== 'ECDSA') {
|
|
46
|
+
throw new sdk_1.DfnsError(-1, 'key scheme is not ECDSA', { walletId, scheme });
|
|
47
|
+
}
|
|
48
|
+
if (curve !== 'secp256k1') {
|
|
49
|
+
throw new sdk_1.DfnsError(-1, 'key curve is not secp256k1', { walletId, curve });
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
boundToEvmNetwork: boundToEvmNetwork(wallet),
|
|
53
|
+
...wallet,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
13
56
|
class DfnsWallet extends abstract_signer_1.Signer {
|
|
57
|
+
/** @deprecated use DfnsWallet.init(options) instead */
|
|
14
58
|
constructor(options, provider) {
|
|
15
59
|
super();
|
|
16
|
-
this.options =
|
|
17
|
-
...options,
|
|
18
|
-
maxRetries: options.maxRetries ?? 3,
|
|
19
|
-
retryInterval: options.retryInterval ?? 1000,
|
|
20
|
-
};
|
|
60
|
+
this.options = options;
|
|
21
61
|
(0, properties_1.defineReadOnly)(this, 'provider', provider || undefined);
|
|
22
62
|
}
|
|
63
|
+
static async init(options) {
|
|
64
|
+
const metadata = await fetchWalletMetadata(options);
|
|
65
|
+
const wallet = new DfnsWallet(options);
|
|
66
|
+
wallet.metadata = metadata;
|
|
67
|
+
return wallet;
|
|
68
|
+
}
|
|
23
69
|
connect(provider) {
|
|
24
|
-
|
|
70
|
+
const copy = new DfnsWallet(this.options, provider);
|
|
71
|
+
copy.address = this.address;
|
|
72
|
+
copy.metadata = this.metadata;
|
|
73
|
+
return copy;
|
|
74
|
+
}
|
|
75
|
+
async getCachedMetadata() {
|
|
76
|
+
if (!this.metadata) {
|
|
77
|
+
this.metadata = await fetchWalletMetadata(this.options);
|
|
78
|
+
}
|
|
79
|
+
return this.metadata;
|
|
25
80
|
}
|
|
26
81
|
async getAddress() {
|
|
27
82
|
if (!this.address) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
if (res.address) {
|
|
34
|
-
this.address = (0, address_1.getAddress)(res.address);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
this.address = (0, transactions_1.computeAddress)('0x' + res.signingKey.publicKey);
|
|
38
|
-
}
|
|
83
|
+
const metadata = await this.getCachedMetadata();
|
|
84
|
+
this.address = metadata.boundToEvmNetwork
|
|
85
|
+
? (0, address_1.getAddress)(metadata.address)
|
|
86
|
+
: (0, transactions_1.computeAddress)('0x' + metadata.signingKey.publicKey);
|
|
39
87
|
}
|
|
40
88
|
return this.address;
|
|
41
89
|
}
|
|
42
|
-
async
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
break;
|
|
51
|
-
return (0, bytes_1.joinSignature)({
|
|
52
|
-
r: res.signature.r,
|
|
53
|
-
s: res.signature.s,
|
|
54
|
-
recoveryParam: res.signature.recid,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
else if (res.status === Wallets_1.SignatureStatus.Failed) {
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
maxRetries -= 1;
|
|
61
|
-
}
|
|
62
|
-
const waitedSeconds = Math.floor((this.options.maxRetries * retryInterval) / 1000);
|
|
63
|
-
throw new Error(`Signature request ${signatureId} took more than ${waitedSeconds}s to complete, stopping polling. Please update options "maxRetries" or "retryIntervals" to wait longer.`);
|
|
90
|
+
async signHash(hash) {
|
|
91
|
+
const metadata = await this.getCachedMetadata();
|
|
92
|
+
const res = await this.options.dfnsClient.wallets.generateSignature({
|
|
93
|
+
walletId: metadata.id,
|
|
94
|
+
body: { kind: 'Hash', hash },
|
|
95
|
+
});
|
|
96
|
+
assertSigned(res);
|
|
97
|
+
return combineSignature(res);
|
|
64
98
|
}
|
|
65
99
|
async signTransaction(transaction) {
|
|
66
100
|
return (0, properties_1.resolveProperties)(transaction).then(async (tx) => {
|
|
@@ -70,22 +104,41 @@ class DfnsWallet extends abstract_signer_1.Signer {
|
|
|
70
104
|
}
|
|
71
105
|
delete tx.from;
|
|
72
106
|
}
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
107
|
+
const unsigned = (0, transactions_1.serialize)(tx);
|
|
108
|
+
const metadata = await this.getCachedMetadata();
|
|
109
|
+
if (metadata.boundToEvmNetwork) {
|
|
110
|
+
const res = await this.options.dfnsClient.wallets.generateSignature({
|
|
111
|
+
walletId: metadata.id,
|
|
112
|
+
body: { kind: 'Transaction', transaction: unsigned },
|
|
113
|
+
});
|
|
114
|
+
assertSigned(res);
|
|
115
|
+
if (!res.signedData) {
|
|
116
|
+
throw new sdk_1.DfnsError(-1, 'signedData missing', res);
|
|
117
|
+
}
|
|
118
|
+
return res.signedData;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const signature = await this.signHash((0, keccak256_1.keccak256)(unsigned));
|
|
122
|
+
return (0, transactions_1.serialize)(tx, signature);
|
|
123
|
+
}
|
|
80
124
|
});
|
|
81
125
|
}
|
|
82
126
|
async signMessage(message) {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
127
|
+
const metadata = await this.getCachedMetadata();
|
|
128
|
+
if (metadata.boundToEvmNetwork) {
|
|
129
|
+
if (typeof message === 'string') {
|
|
130
|
+
message = (0, strings_1.toUtf8Bytes)(message);
|
|
131
|
+
}
|
|
132
|
+
const res = await this.options.dfnsClient.wallets.generateSignature({
|
|
133
|
+
walletId: metadata.id,
|
|
134
|
+
body: { kind: 'Message', message: (0, bytes_1.hexlify)(message) },
|
|
135
|
+
});
|
|
136
|
+
assertSigned(res);
|
|
137
|
+
return combineSignature(res);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return this.signHash((0, hash_1.hashMessage)(message));
|
|
141
|
+
}
|
|
89
142
|
}
|
|
90
143
|
async _signTypedData(domain, types, value) {
|
|
91
144
|
// Populate any ENS names
|
|
@@ -98,15 +151,29 @@ class DfnsWallet extends abstract_signer_1.Signer {
|
|
|
98
151
|
throw new Error(`unconfigured ENS name ${name}`);
|
|
99
152
|
return resolved;
|
|
100
153
|
});
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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 ? bignumber_1.BigNumber.from(populated.domain.chainId).toNumber() : undefined,
|
|
165
|
+
verifyingContract: populated.domain.verifyingContract ?? undefined,
|
|
166
|
+
salt: populated.domain.salt ? (0, bytes_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(hash_1._TypedDataEncoder.hash(populated.domain, types, populated.value));
|
|
176
|
+
}
|
|
110
177
|
}
|
|
111
178
|
}
|
|
112
179
|
exports.DfnsWallet = DfnsWallet;
|
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dfns/lib-ethersjs5",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3-rc.1",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@ethersproject/abstract-provider": "5.7.0",
|
|
6
6
|
"@ethersproject/abstract-signer": "5.7.0",
|
|
7
7
|
"@ethersproject/address": "5.7.0",
|
|
8
|
+
"@ethersproject/bignumber": "5.7.0",
|
|
8
9
|
"@ethersproject/bytes": "5.7.0",
|
|
9
10
|
"@ethersproject/hash": "5.7.0",
|
|
10
11
|
"@ethersproject/keccak256": "5.7.0",
|
|
11
12
|
"@ethersproject/properties": "5.7.0",
|
|
13
|
+
"@ethersproject/strings": "5.7.0",
|
|
12
14
|
"@ethersproject/transactions": "5.7.0",
|
|
13
15
|
"buffer": "6.0.3",
|
|
14
16
|
"cross-fetch": "3.1.6",
|
|
15
17
|
"uuid": "9.0.0"
|
|
16
18
|
},
|
|
17
19
|
"peerDependencies": {
|
|
18
|
-
"@dfns/sdk": "0.1.
|
|
20
|
+
"@dfns/sdk": "0.1.3-rc.1"
|
|
19
21
|
},
|
|
20
22
|
"main": "./index.js",
|
|
21
23
|
"type": "commonjs"
|