@0xsequence/guard 0.43.34 → 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/dist/0xsequence-guard.cjs.dev.js +90 -13
- package/dist/0xsequence-guard.cjs.prod.js +90 -13
- package/dist/0xsequence-guard.esm.js +90 -14
- package/dist/declarations/src/guard.gen.d.ts +14 -19
- package/dist/declarations/src/index.d.ts +1 -0
- package/dist/declarations/src/signer.d.ts +21 -0
- package/package.json +6 -4
- package/src/guard.gen.ts +24 -32
- package/src/index.ts +1 -0
- package/src/signer.ts +117 -0
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var ethers = require('ethers');
|
|
6
|
+
var core = require('@0xsequence/core');
|
|
7
|
+
|
|
5
8
|
function _extends() {
|
|
6
9
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
7
10
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -18,7 +21,7 @@ function _extends() {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/* eslint-disable */
|
|
21
|
-
// sequence-guard v0.4.0
|
|
24
|
+
// sequence-guard v0.4.0 a29651d1d5f63268e8d03b51e46557e0632c144d
|
|
22
25
|
// --
|
|
23
26
|
// Code generated by webrpc-gen@v0.10.x-dev with typescript generator. DO NOT EDIT.
|
|
24
27
|
//
|
|
@@ -31,19 +34,16 @@ const WebRPCVersion = "v1";
|
|
|
31
34
|
const WebRPCSchemaVersion = "v0.4.0";
|
|
32
35
|
|
|
33
36
|
// Schema hash generated from your RIDL schema
|
|
34
|
-
const WebRPCSchemaHash = "
|
|
37
|
+
const WebRPCSchemaHash = "a29651d1d5f63268e8d03b51e46557e0632c144d";
|
|
35
38
|
|
|
36
39
|
//
|
|
37
40
|
// Types
|
|
38
41
|
//
|
|
39
|
-
|
|
40
42
|
//
|
|
41
43
|
// Client
|
|
42
44
|
//
|
|
43
45
|
class Guard {
|
|
44
46
|
constructor(hostname, fetch) {
|
|
45
|
-
this.hostname = void 0;
|
|
46
|
-
this.fetch = void 0;
|
|
47
47
|
this.path = '/rpc/Guard/';
|
|
48
48
|
this.ping = headers => {
|
|
49
49
|
return this.fetch(this.url('Ping'), createHTTPRequest({}, headers)).then(res => {
|
|
@@ -72,26 +72,26 @@ class Guard {
|
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
74
|
};
|
|
75
|
-
this.
|
|
76
|
-
return this.fetch(this.url('
|
|
75
|
+
this.getSignerConfig = (args, headers) => {
|
|
76
|
+
return this.fetch(this.url('GetSignerConfig'), createHTTPRequest(args, headers)).then(res => {
|
|
77
77
|
return buildResponse(res).then(_data => {
|
|
78
78
|
return {
|
|
79
|
-
|
|
79
|
+
signerConfig: _data.signerConfig
|
|
80
80
|
};
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
};
|
|
84
|
-
this.
|
|
85
|
-
return this.fetch(this.url('
|
|
84
|
+
this.sign = (args, headers) => {
|
|
85
|
+
return this.fetch(this.url('Sign'), createHTTPRequest(args, headers)).then(res => {
|
|
86
86
|
return buildResponse(res).then(_data => {
|
|
87
87
|
return {
|
|
88
|
-
|
|
88
|
+
sig: _data.sig
|
|
89
89
|
};
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
};
|
|
93
|
-
this.
|
|
94
|
-
return this.fetch(this.url('
|
|
93
|
+
this.signWith = (args, headers) => {
|
|
94
|
+
return this.fetch(this.url('SignWith'), createHTTPRequest(args, headers)).then(res => {
|
|
95
95
|
return buildResponse(res).then(_data => {
|
|
96
96
|
return {
|
|
97
97
|
sig: _data.sig
|
|
@@ -135,7 +135,84 @@ const buildResponse = res => {
|
|
|
135
135
|
});
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
+
class GuardSigner {
|
|
139
|
+
constructor(address, url, appendSuffix = false) {
|
|
140
|
+
this.requests = new Map();
|
|
141
|
+
this.address = address;
|
|
142
|
+
this.url = url;
|
|
143
|
+
this.appendSuffix = appendSuffix;
|
|
144
|
+
this.guard = new Guard(url, global.fetch);
|
|
145
|
+
}
|
|
146
|
+
async getAddress() {
|
|
147
|
+
return this.address;
|
|
148
|
+
}
|
|
149
|
+
async requestSignature(id, _message, metadata, callbacks) {
|
|
150
|
+
if (!core.commons.isWalletSignRequestMetadata(metadata)) {
|
|
151
|
+
callbacks.onRejection('Expected Sequence-like metadata');
|
|
152
|
+
} else {
|
|
153
|
+
// Queue the request first, this method only does that
|
|
154
|
+
// the requesting to the API is later handled on every status change
|
|
155
|
+
this.requests.set(id, callbacks);
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
notifyStatusChange(id, status, metadata) {
|
|
160
|
+
if (!this.requests.has(id)) return;
|
|
161
|
+
if (!core.commons.isWalletSignRequestMetadata(metadata)) {
|
|
162
|
+
this.requests.get(id).onRejection('Expected Sequence-like metadata (status update)');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.evaluateRequest(id, status.message, status, metadata);
|
|
166
|
+
}
|
|
167
|
+
packMsgAndSig(address, msg, sig, chainId) {
|
|
168
|
+
return ethers.ethers.utils.defaultAbiCoder.encode(['address', 'uint256', 'bytes', 'bytes'], [address, chainId, msg, sig]);
|
|
169
|
+
}
|
|
170
|
+
keyOfRequest(signer, msg, auxData, chainId) {
|
|
171
|
+
return ethers.ethers.utils.solidityKeccak256(['address', 'uint256', 'bytes', 'bytes'], [signer, chainId, msg, auxData]);
|
|
172
|
+
}
|
|
173
|
+
async evaluateRequest(id, message, _, metadata) {
|
|
174
|
+
var _metadata$parts;
|
|
175
|
+
// Building auxData, notice: this uses the old v1 format
|
|
176
|
+
// TODO: We should update the guard API so we can pass the metadata directly
|
|
177
|
+
const coder = core.universal.genericCoderFor(metadata.config.version);
|
|
178
|
+
const {
|
|
179
|
+
encoded
|
|
180
|
+
} = coder.signature.encodeSigners(metadata.config, (_metadata$parts = metadata.parts) != null ? _metadata$parts : new Map(), [], metadata.chainId);
|
|
181
|
+
try {
|
|
182
|
+
var _this$requests$get;
|
|
183
|
+
const key = this.keyOfRequest(this.address, message, encoded, metadata.chainId);
|
|
184
|
+
const lastAttempt = (_this$requests$get = this.requests.get(id)) == null ? void 0 : _this$requests$get.lastAttempt;
|
|
185
|
+
if (lastAttempt === key) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.requests.get(id).lastAttempt = key;
|
|
189
|
+
const result = await this.guard.signWith({
|
|
190
|
+
signer: this.address,
|
|
191
|
+
request: {
|
|
192
|
+
msg: ethers.ethers.utils.hexlify(message),
|
|
193
|
+
auxData: this.packMsgAndSig(metadata.address, metadata.digest, encoded, metadata.chainId),
|
|
194
|
+
chainId: ethers.ethers.BigNumber.from(metadata.chainId).toNumber() // TODO: This should be a string (in the API)
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
if (ethers.ethers.utils.arrayify(result.sig).length !== 0) {
|
|
199
|
+
this.requests.get(id).onSignature(result.sig);
|
|
200
|
+
this.requests.delete(id);
|
|
201
|
+
}
|
|
202
|
+
} catch (e) {
|
|
203
|
+
// The guard signer may reject the request for a number of reasons
|
|
204
|
+
// like for example, if it's being the first signer (it waits for other signers to sign first)
|
|
205
|
+
// for now we ignore all errors, but we should probably handle them
|
|
206
|
+
// TODO: Filter real errors from control flow errors
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
suffix() {
|
|
210
|
+
return this.appendSuffix ? [3] : [];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
138
214
|
exports.Guard = Guard;
|
|
215
|
+
exports.GuardSigner = GuardSigner;
|
|
139
216
|
exports.WebRPCSchemaHash = WebRPCSchemaHash;
|
|
140
217
|
exports.WebRPCSchemaVersion = WebRPCSchemaVersion;
|
|
141
218
|
exports.WebRPCVersion = WebRPCVersion;
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var ethers = require('ethers');
|
|
6
|
+
var core = require('@0xsequence/core');
|
|
7
|
+
|
|
5
8
|
function _extends() {
|
|
6
9
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
7
10
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -18,7 +21,7 @@ function _extends() {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/* eslint-disable */
|
|
21
|
-
// sequence-guard v0.4.0
|
|
24
|
+
// sequence-guard v0.4.0 a29651d1d5f63268e8d03b51e46557e0632c144d
|
|
22
25
|
// --
|
|
23
26
|
// Code generated by webrpc-gen@v0.10.x-dev with typescript generator. DO NOT EDIT.
|
|
24
27
|
//
|
|
@@ -31,19 +34,16 @@ const WebRPCVersion = "v1";
|
|
|
31
34
|
const WebRPCSchemaVersion = "v0.4.0";
|
|
32
35
|
|
|
33
36
|
// Schema hash generated from your RIDL schema
|
|
34
|
-
const WebRPCSchemaHash = "
|
|
37
|
+
const WebRPCSchemaHash = "a29651d1d5f63268e8d03b51e46557e0632c144d";
|
|
35
38
|
|
|
36
39
|
//
|
|
37
40
|
// Types
|
|
38
41
|
//
|
|
39
|
-
|
|
40
42
|
//
|
|
41
43
|
// Client
|
|
42
44
|
//
|
|
43
45
|
class Guard {
|
|
44
46
|
constructor(hostname, fetch) {
|
|
45
|
-
this.hostname = void 0;
|
|
46
|
-
this.fetch = void 0;
|
|
47
47
|
this.path = '/rpc/Guard/';
|
|
48
48
|
this.ping = headers => {
|
|
49
49
|
return this.fetch(this.url('Ping'), createHTTPRequest({}, headers)).then(res => {
|
|
@@ -72,26 +72,26 @@ class Guard {
|
|
|
72
72
|
});
|
|
73
73
|
});
|
|
74
74
|
};
|
|
75
|
-
this.
|
|
76
|
-
return this.fetch(this.url('
|
|
75
|
+
this.getSignerConfig = (args, headers) => {
|
|
76
|
+
return this.fetch(this.url('GetSignerConfig'), createHTTPRequest(args, headers)).then(res => {
|
|
77
77
|
return buildResponse(res).then(_data => {
|
|
78
78
|
return {
|
|
79
|
-
|
|
79
|
+
signerConfig: _data.signerConfig
|
|
80
80
|
};
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
};
|
|
84
|
-
this.
|
|
85
|
-
return this.fetch(this.url('
|
|
84
|
+
this.sign = (args, headers) => {
|
|
85
|
+
return this.fetch(this.url('Sign'), createHTTPRequest(args, headers)).then(res => {
|
|
86
86
|
return buildResponse(res).then(_data => {
|
|
87
87
|
return {
|
|
88
|
-
|
|
88
|
+
sig: _data.sig
|
|
89
89
|
};
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
};
|
|
93
|
-
this.
|
|
94
|
-
return this.fetch(this.url('
|
|
93
|
+
this.signWith = (args, headers) => {
|
|
94
|
+
return this.fetch(this.url('SignWith'), createHTTPRequest(args, headers)).then(res => {
|
|
95
95
|
return buildResponse(res).then(_data => {
|
|
96
96
|
return {
|
|
97
97
|
sig: _data.sig
|
|
@@ -135,7 +135,84 @@ const buildResponse = res => {
|
|
|
135
135
|
});
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
+
class GuardSigner {
|
|
139
|
+
constructor(address, url, appendSuffix = false) {
|
|
140
|
+
this.requests = new Map();
|
|
141
|
+
this.address = address;
|
|
142
|
+
this.url = url;
|
|
143
|
+
this.appendSuffix = appendSuffix;
|
|
144
|
+
this.guard = new Guard(url, global.fetch);
|
|
145
|
+
}
|
|
146
|
+
async getAddress() {
|
|
147
|
+
return this.address;
|
|
148
|
+
}
|
|
149
|
+
async requestSignature(id, _message, metadata, callbacks) {
|
|
150
|
+
if (!core.commons.isWalletSignRequestMetadata(metadata)) {
|
|
151
|
+
callbacks.onRejection('Expected Sequence-like metadata');
|
|
152
|
+
} else {
|
|
153
|
+
// Queue the request first, this method only does that
|
|
154
|
+
// the requesting to the API is later handled on every status change
|
|
155
|
+
this.requests.set(id, callbacks);
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
notifyStatusChange(id, status, metadata) {
|
|
160
|
+
if (!this.requests.has(id)) return;
|
|
161
|
+
if (!core.commons.isWalletSignRequestMetadata(metadata)) {
|
|
162
|
+
this.requests.get(id).onRejection('Expected Sequence-like metadata (status update)');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.evaluateRequest(id, status.message, status, metadata);
|
|
166
|
+
}
|
|
167
|
+
packMsgAndSig(address, msg, sig, chainId) {
|
|
168
|
+
return ethers.ethers.utils.defaultAbiCoder.encode(['address', 'uint256', 'bytes', 'bytes'], [address, chainId, msg, sig]);
|
|
169
|
+
}
|
|
170
|
+
keyOfRequest(signer, msg, auxData, chainId) {
|
|
171
|
+
return ethers.ethers.utils.solidityKeccak256(['address', 'uint256', 'bytes', 'bytes'], [signer, chainId, msg, auxData]);
|
|
172
|
+
}
|
|
173
|
+
async evaluateRequest(id, message, _, metadata) {
|
|
174
|
+
var _metadata$parts;
|
|
175
|
+
// Building auxData, notice: this uses the old v1 format
|
|
176
|
+
// TODO: We should update the guard API so we can pass the metadata directly
|
|
177
|
+
const coder = core.universal.genericCoderFor(metadata.config.version);
|
|
178
|
+
const {
|
|
179
|
+
encoded
|
|
180
|
+
} = coder.signature.encodeSigners(metadata.config, (_metadata$parts = metadata.parts) != null ? _metadata$parts : new Map(), [], metadata.chainId);
|
|
181
|
+
try {
|
|
182
|
+
var _this$requests$get;
|
|
183
|
+
const key = this.keyOfRequest(this.address, message, encoded, metadata.chainId);
|
|
184
|
+
const lastAttempt = (_this$requests$get = this.requests.get(id)) == null ? void 0 : _this$requests$get.lastAttempt;
|
|
185
|
+
if (lastAttempt === key) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.requests.get(id).lastAttempt = key;
|
|
189
|
+
const result = await this.guard.signWith({
|
|
190
|
+
signer: this.address,
|
|
191
|
+
request: {
|
|
192
|
+
msg: ethers.ethers.utils.hexlify(message),
|
|
193
|
+
auxData: this.packMsgAndSig(metadata.address, metadata.digest, encoded, metadata.chainId),
|
|
194
|
+
chainId: ethers.ethers.BigNumber.from(metadata.chainId).toNumber() // TODO: This should be a string (in the API)
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
if (ethers.ethers.utils.arrayify(result.sig).length !== 0) {
|
|
199
|
+
this.requests.get(id).onSignature(result.sig);
|
|
200
|
+
this.requests.delete(id);
|
|
201
|
+
}
|
|
202
|
+
} catch (e) {
|
|
203
|
+
// The guard signer may reject the request for a number of reasons
|
|
204
|
+
// like for example, if it's being the first signer (it waits for other signers to sign first)
|
|
205
|
+
// for now we ignore all errors, but we should probably handle them
|
|
206
|
+
// TODO: Filter real errors from control flow errors
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
suffix() {
|
|
210
|
+
return this.appendSuffix ? [3] : [];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
138
214
|
exports.Guard = Guard;
|
|
215
|
+
exports.GuardSigner = GuardSigner;
|
|
139
216
|
exports.WebRPCSchemaHash = WebRPCSchemaHash;
|
|
140
217
|
exports.WebRPCSchemaVersion = WebRPCSchemaVersion;
|
|
141
218
|
exports.WebRPCVersion = WebRPCVersion;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { commons, universal } from '@0xsequence/core';
|
|
3
|
+
|
|
1
4
|
function _extends() {
|
|
2
5
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
3
6
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -14,7 +17,7 @@ function _extends() {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
/* eslint-disable */
|
|
17
|
-
// sequence-guard v0.4.0
|
|
20
|
+
// sequence-guard v0.4.0 a29651d1d5f63268e8d03b51e46557e0632c144d
|
|
18
21
|
// --
|
|
19
22
|
// Code generated by webrpc-gen@v0.10.x-dev with typescript generator. DO NOT EDIT.
|
|
20
23
|
//
|
|
@@ -27,19 +30,16 @@ const WebRPCVersion = "v1";
|
|
|
27
30
|
const WebRPCSchemaVersion = "v0.4.0";
|
|
28
31
|
|
|
29
32
|
// Schema hash generated from your RIDL schema
|
|
30
|
-
const WebRPCSchemaHash = "
|
|
33
|
+
const WebRPCSchemaHash = "a29651d1d5f63268e8d03b51e46557e0632c144d";
|
|
31
34
|
|
|
32
35
|
//
|
|
33
36
|
// Types
|
|
34
37
|
//
|
|
35
|
-
|
|
36
38
|
//
|
|
37
39
|
// Client
|
|
38
40
|
//
|
|
39
41
|
class Guard {
|
|
40
42
|
constructor(hostname, fetch) {
|
|
41
|
-
this.hostname = void 0;
|
|
42
|
-
this.fetch = void 0;
|
|
43
43
|
this.path = '/rpc/Guard/';
|
|
44
44
|
this.ping = headers => {
|
|
45
45
|
return this.fetch(this.url('Ping'), createHTTPRequest({}, headers)).then(res => {
|
|
@@ -68,26 +68,26 @@ class Guard {
|
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
70
|
};
|
|
71
|
-
this.
|
|
72
|
-
return this.fetch(this.url('
|
|
71
|
+
this.getSignerConfig = (args, headers) => {
|
|
72
|
+
return this.fetch(this.url('GetSignerConfig'), createHTTPRequest(args, headers)).then(res => {
|
|
73
73
|
return buildResponse(res).then(_data => {
|
|
74
74
|
return {
|
|
75
|
-
|
|
75
|
+
signerConfig: _data.signerConfig
|
|
76
76
|
};
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
79
|
};
|
|
80
|
-
this.
|
|
81
|
-
return this.fetch(this.url('
|
|
80
|
+
this.sign = (args, headers) => {
|
|
81
|
+
return this.fetch(this.url('Sign'), createHTTPRequest(args, headers)).then(res => {
|
|
82
82
|
return buildResponse(res).then(_data => {
|
|
83
83
|
return {
|
|
84
|
-
|
|
84
|
+
sig: _data.sig
|
|
85
85
|
};
|
|
86
86
|
});
|
|
87
87
|
});
|
|
88
88
|
};
|
|
89
|
-
this.
|
|
90
|
-
return this.fetch(this.url('
|
|
89
|
+
this.signWith = (args, headers) => {
|
|
90
|
+
return this.fetch(this.url('SignWith'), createHTTPRequest(args, headers)).then(res => {
|
|
91
91
|
return buildResponse(res).then(_data => {
|
|
92
92
|
return {
|
|
93
93
|
sig: _data.sig
|
|
@@ -131,4 +131,80 @@ const buildResponse = res => {
|
|
|
131
131
|
});
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
class GuardSigner {
|
|
135
|
+
constructor(address, url, appendSuffix = false) {
|
|
136
|
+
this.requests = new Map();
|
|
137
|
+
this.address = address;
|
|
138
|
+
this.url = url;
|
|
139
|
+
this.appendSuffix = appendSuffix;
|
|
140
|
+
this.guard = new Guard(url, global.fetch);
|
|
141
|
+
}
|
|
142
|
+
async getAddress() {
|
|
143
|
+
return this.address;
|
|
144
|
+
}
|
|
145
|
+
async requestSignature(id, _message, metadata, callbacks) {
|
|
146
|
+
if (!commons.isWalletSignRequestMetadata(metadata)) {
|
|
147
|
+
callbacks.onRejection('Expected Sequence-like metadata');
|
|
148
|
+
} else {
|
|
149
|
+
// Queue the request first, this method only does that
|
|
150
|
+
// the requesting to the API is later handled on every status change
|
|
151
|
+
this.requests.set(id, callbacks);
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
notifyStatusChange(id, status, metadata) {
|
|
156
|
+
if (!this.requests.has(id)) return;
|
|
157
|
+
if (!commons.isWalletSignRequestMetadata(metadata)) {
|
|
158
|
+
this.requests.get(id).onRejection('Expected Sequence-like metadata (status update)');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.evaluateRequest(id, status.message, status, metadata);
|
|
162
|
+
}
|
|
163
|
+
packMsgAndSig(address, msg, sig, chainId) {
|
|
164
|
+
return ethers.utils.defaultAbiCoder.encode(['address', 'uint256', 'bytes', 'bytes'], [address, chainId, msg, sig]);
|
|
165
|
+
}
|
|
166
|
+
keyOfRequest(signer, msg, auxData, chainId) {
|
|
167
|
+
return ethers.utils.solidityKeccak256(['address', 'uint256', 'bytes', 'bytes'], [signer, chainId, msg, auxData]);
|
|
168
|
+
}
|
|
169
|
+
async evaluateRequest(id, message, _, metadata) {
|
|
170
|
+
var _metadata$parts;
|
|
171
|
+
// Building auxData, notice: this uses the old v1 format
|
|
172
|
+
// TODO: We should update the guard API so we can pass the metadata directly
|
|
173
|
+
const coder = universal.genericCoderFor(metadata.config.version);
|
|
174
|
+
const {
|
|
175
|
+
encoded
|
|
176
|
+
} = coder.signature.encodeSigners(metadata.config, (_metadata$parts = metadata.parts) != null ? _metadata$parts : new Map(), [], metadata.chainId);
|
|
177
|
+
try {
|
|
178
|
+
var _this$requests$get;
|
|
179
|
+
const key = this.keyOfRequest(this.address, message, encoded, metadata.chainId);
|
|
180
|
+
const lastAttempt = (_this$requests$get = this.requests.get(id)) == null ? void 0 : _this$requests$get.lastAttempt;
|
|
181
|
+
if (lastAttempt === key) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.requests.get(id).lastAttempt = key;
|
|
185
|
+
const result = await this.guard.signWith({
|
|
186
|
+
signer: this.address,
|
|
187
|
+
request: {
|
|
188
|
+
msg: ethers.utils.hexlify(message),
|
|
189
|
+
auxData: this.packMsgAndSig(metadata.address, metadata.digest, encoded, metadata.chainId),
|
|
190
|
+
chainId: ethers.BigNumber.from(metadata.chainId).toNumber() // TODO: This should be a string (in the API)
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (ethers.utils.arrayify(result.sig).length !== 0) {
|
|
195
|
+
this.requests.get(id).onSignature(result.sig);
|
|
196
|
+
this.requests.delete(id);
|
|
197
|
+
}
|
|
198
|
+
} catch (e) {
|
|
199
|
+
// The guard signer may reject the request for a number of reasons
|
|
200
|
+
// like for example, if it's being the first signer (it waits for other signers to sign first)
|
|
201
|
+
// for now we ignore all errors, but we should probably handle them
|
|
202
|
+
// TODO: Filter real errors from control flow errors
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
suffix() {
|
|
206
|
+
return this.appendSuffix ? [3] : [];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export { Guard, GuardSigner, WebRPCSchemaHash, WebRPCSchemaVersion, WebRPCVersion };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const WebRPCVersion = "v1";
|
|
2
2
|
export declare const WebRPCSchemaVersion = "v0.4.0";
|
|
3
|
-
export declare const WebRPCSchemaHash = "
|
|
3
|
+
export declare const WebRPCSchemaHash = "a29651d1d5f63268e8d03b51e46557e0632c144d";
|
|
4
4
|
export interface Version {
|
|
5
5
|
webrpcVersion: string;
|
|
6
6
|
schemaVersion: string;
|
|
@@ -15,17 +15,9 @@ export interface RuntimeStatus {
|
|
|
15
15
|
branch: string;
|
|
16
16
|
commitHash: string;
|
|
17
17
|
}
|
|
18
|
-
export interface SequenceContext {
|
|
19
|
-
factory: string;
|
|
20
|
-
mainModule: string;
|
|
21
|
-
mainModuleUpgradable: string;
|
|
22
|
-
guestModule: string;
|
|
23
|
-
utils: string;
|
|
24
|
-
}
|
|
25
18
|
export interface WalletConfig {
|
|
26
19
|
address: string;
|
|
27
|
-
|
|
28
|
-
threshold: number;
|
|
20
|
+
content: string;
|
|
29
21
|
}
|
|
30
22
|
export interface WalletSigner {
|
|
31
23
|
address: string;
|
|
@@ -40,9 +32,9 @@ export interface Guard {
|
|
|
40
32
|
ping(headers?: object): Promise<PingReturn>;
|
|
41
33
|
version(headers?: object): Promise<VersionReturn>;
|
|
42
34
|
runtimeStatus(headers?: object): Promise<RuntimeStatusReturn>;
|
|
43
|
-
|
|
44
|
-
getSignerConfig(headers?: object): Promise<GetSignerConfigReturn>;
|
|
35
|
+
getSignerConfig(args: GetSignerConfigArgs, headers?: object): Promise<GetSignerConfigReturn>;
|
|
45
36
|
sign(args: SignArgs, headers?: object): Promise<SignReturn>;
|
|
37
|
+
signWith(args: SignWithArgs, headers?: object): Promise<SignWithReturn>;
|
|
46
38
|
}
|
|
47
39
|
export interface PingArgs {
|
|
48
40
|
}
|
|
@@ -59,12 +51,8 @@ export interface RuntimeStatusArgs {
|
|
|
59
51
|
export interface RuntimeStatusReturn {
|
|
60
52
|
status: RuntimeStatus;
|
|
61
53
|
}
|
|
62
|
-
export interface GetSequenceContextArgs {
|
|
63
|
-
}
|
|
64
|
-
export interface GetSequenceContextReturn {
|
|
65
|
-
data: SequenceContext;
|
|
66
|
-
}
|
|
67
54
|
export interface GetSignerConfigArgs {
|
|
55
|
+
signer: string;
|
|
68
56
|
}
|
|
69
57
|
export interface GetSignerConfigReturn {
|
|
70
58
|
signerConfig: WalletConfig;
|
|
@@ -75,6 +63,13 @@ export interface SignArgs {
|
|
|
75
63
|
export interface SignReturn {
|
|
76
64
|
sig: string;
|
|
77
65
|
}
|
|
66
|
+
export interface SignWithArgs {
|
|
67
|
+
signer: string;
|
|
68
|
+
request: SignRequest;
|
|
69
|
+
}
|
|
70
|
+
export interface SignWithReturn {
|
|
71
|
+
sig: string;
|
|
72
|
+
}
|
|
78
73
|
export declare class Guard implements Guard {
|
|
79
74
|
protected hostname: string;
|
|
80
75
|
protected fetch: Fetch;
|
|
@@ -84,9 +79,9 @@ export declare class Guard implements Guard {
|
|
|
84
79
|
ping: (headers?: object | undefined) => Promise<PingReturn>;
|
|
85
80
|
version: (headers?: object | undefined) => Promise<VersionReturn>;
|
|
86
81
|
runtimeStatus: (headers?: object | undefined) => Promise<RuntimeStatusReturn>;
|
|
87
|
-
|
|
88
|
-
getSignerConfig: (headers?: object | undefined) => Promise<GetSignerConfigReturn>;
|
|
82
|
+
getSignerConfig: (args: GetSignerConfigArgs, headers?: object | undefined) => Promise<GetSignerConfigReturn>;
|
|
89
83
|
sign: (args: SignArgs, headers?: object | undefined) => Promise<SignReturn>;
|
|
84
|
+
signWith: (args: SignWithArgs, headers?: object | undefined) => Promise<SignWithReturn>;
|
|
90
85
|
}
|
|
91
86
|
export interface WebRPCError extends Error {
|
|
92
87
|
code: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { signers, Status } from '@0xsequence/signhub';
|
|
2
|
+
import { BytesLike } from 'ethers';
|
|
3
|
+
export declare class GuardSigner implements signers.SapientSigner {
|
|
4
|
+
readonly address: string;
|
|
5
|
+
readonly url: string;
|
|
6
|
+
readonly appendSuffix: boolean;
|
|
7
|
+
private guard;
|
|
8
|
+
private requests;
|
|
9
|
+
constructor(address: string, url: string, appendSuffix?: boolean);
|
|
10
|
+
getAddress(): Promise<string>;
|
|
11
|
+
requestSignature(id: string, _message: BytesLike, metadata: Object, callbacks: {
|
|
12
|
+
onSignature: (signature: BytesLike) => void;
|
|
13
|
+
onRejection: (error: string) => void;
|
|
14
|
+
onStatus: (situation: string) => void;
|
|
15
|
+
}): Promise<boolean>;
|
|
16
|
+
notifyStatusChange(id: string, status: Status, metadata: Object): void;
|
|
17
|
+
private packMsgAndSig;
|
|
18
|
+
private keyOfRequest;
|
|
19
|
+
private evaluateRequest;
|
|
20
|
+
suffix(): BytesLike;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "guard sub-package for Sequence",
|
|
5
5
|
"repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/guard",
|
|
6
6
|
"source": "src/index.ts",
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
"module": "dist/0xsequence-guard.esm.js",
|
|
9
9
|
"author": "Horizon Blockchain Games",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
|
-
"dependencies": {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"ethers": "^5.7.2",
|
|
13
|
+
"@0xsequence/core": "1.0.0",
|
|
14
|
+
"@0xsequence/signhub": "1.0.0"
|
|
15
|
+
},
|
|
14
16
|
"files": [
|
|
15
17
|
"src",
|
|
16
18
|
"dist"
|
package/src/guard.gen.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
-
// sequence-guard v0.4.0
|
|
2
|
+
// sequence-guard v0.4.0 a29651d1d5f63268e8d03b51e46557e0632c144d
|
|
3
3
|
// --
|
|
4
4
|
// Code generated by webrpc-gen@v0.10.x-dev with typescript generator. DO NOT EDIT.
|
|
5
5
|
//
|
|
@@ -12,7 +12,7 @@ export const WebRPCVersion = "v1"
|
|
|
12
12
|
export const WebRPCSchemaVersion = "v0.4.0"
|
|
13
13
|
|
|
14
14
|
// Schema hash generated from your RIDL schema
|
|
15
|
-
export const WebRPCSchemaHash = "
|
|
15
|
+
export const WebRPCSchemaHash = "a29651d1d5f63268e8d03b51e46557e0632c144d"
|
|
16
16
|
|
|
17
17
|
//
|
|
18
18
|
// Types
|
|
@@ -35,18 +35,9 @@ export interface RuntimeStatus {
|
|
|
35
35
|
commitHash: string
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export interface SequenceContext {
|
|
39
|
-
factory: string
|
|
40
|
-
mainModule: string
|
|
41
|
-
mainModuleUpgradable: string
|
|
42
|
-
guestModule: string
|
|
43
|
-
utils: string
|
|
44
|
-
}
|
|
45
|
-
|
|
46
38
|
export interface WalletConfig {
|
|
47
39
|
address: string
|
|
48
|
-
|
|
49
|
-
threshold: number
|
|
40
|
+
content: string
|
|
50
41
|
}
|
|
51
42
|
|
|
52
43
|
export interface WalletSigner {
|
|
@@ -64,9 +55,9 @@ export interface Guard {
|
|
|
64
55
|
ping(headers?: object): Promise<PingReturn>
|
|
65
56
|
version(headers?: object): Promise<VersionReturn>
|
|
66
57
|
runtimeStatus(headers?: object): Promise<RuntimeStatusReturn>
|
|
67
|
-
|
|
68
|
-
getSignerConfig(headers?: object): Promise<GetSignerConfigReturn>
|
|
58
|
+
getSignerConfig(args: GetSignerConfigArgs, headers?: object): Promise<GetSignerConfigReturn>
|
|
69
59
|
sign(args: SignArgs, headers?: object): Promise<SignReturn>
|
|
60
|
+
signWith(args: SignWithArgs, headers?: object): Promise<SignWithReturn>
|
|
70
61
|
}
|
|
71
62
|
|
|
72
63
|
export interface PingArgs {
|
|
@@ -87,13 +78,8 @@ export interface RuntimeStatusArgs {
|
|
|
87
78
|
export interface RuntimeStatusReturn {
|
|
88
79
|
status: RuntimeStatus
|
|
89
80
|
}
|
|
90
|
-
export interface GetSequenceContextArgs {
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface GetSequenceContextReturn {
|
|
94
|
-
data: SequenceContext
|
|
95
|
-
}
|
|
96
81
|
export interface GetSignerConfigArgs {
|
|
82
|
+
signer: string
|
|
97
83
|
}
|
|
98
84
|
|
|
99
85
|
export interface GetSignerConfigReturn {
|
|
@@ -106,6 +92,14 @@ export interface SignArgs {
|
|
|
106
92
|
export interface SignReturn {
|
|
107
93
|
sig: string
|
|
108
94
|
}
|
|
95
|
+
export interface SignWithArgs {
|
|
96
|
+
signer: string
|
|
97
|
+
request: SignRequest
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface SignWithReturn {
|
|
101
|
+
sig: string
|
|
102
|
+
}
|
|
109
103
|
|
|
110
104
|
|
|
111
105
|
|
|
@@ -165,35 +159,33 @@ export class Guard implements Guard {
|
|
|
165
159
|
})
|
|
166
160
|
}
|
|
167
161
|
|
|
168
|
-
|
|
162
|
+
getSignerConfig = (args: GetSignerConfigArgs, headers?: object): Promise<GetSignerConfigReturn> => {
|
|
169
163
|
return this.fetch(
|
|
170
|
-
this.url('
|
|
171
|
-
createHTTPRequest(
|
|
172
|
-
).then((res) => {
|
|
164
|
+
this.url('GetSignerConfig'),
|
|
165
|
+
createHTTPRequest(args, headers)).then((res) => {
|
|
173
166
|
return buildResponse(res).then(_data => {
|
|
174
167
|
return {
|
|
175
|
-
|
|
168
|
+
signerConfig: <WalletConfig>(_data.signerConfig)
|
|
176
169
|
}
|
|
177
170
|
})
|
|
178
171
|
})
|
|
179
172
|
}
|
|
180
173
|
|
|
181
|
-
|
|
174
|
+
sign = (args: SignArgs, headers?: object): Promise<SignReturn> => {
|
|
182
175
|
return this.fetch(
|
|
183
|
-
this.url('
|
|
184
|
-
createHTTPRequest(
|
|
185
|
-
).then((res) => {
|
|
176
|
+
this.url('Sign'),
|
|
177
|
+
createHTTPRequest(args, headers)).then((res) => {
|
|
186
178
|
return buildResponse(res).then(_data => {
|
|
187
179
|
return {
|
|
188
|
-
|
|
180
|
+
sig: <string>(_data.sig)
|
|
189
181
|
}
|
|
190
182
|
})
|
|
191
183
|
})
|
|
192
184
|
}
|
|
193
185
|
|
|
194
|
-
|
|
186
|
+
signWith = (args: SignWithArgs, headers?: object): Promise<SignWithReturn> => {
|
|
195
187
|
return this.fetch(
|
|
196
|
-
this.url('
|
|
188
|
+
this.url('SignWith'),
|
|
197
189
|
createHTTPRequest(args, headers)).then((res) => {
|
|
198
190
|
return buildResponse(res).then(_data => {
|
|
199
191
|
return {
|
package/src/index.ts
CHANGED
package/src/signer.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
|
|
2
|
+
import { signers, Status } from '@0xsequence/signhub'
|
|
3
|
+
import { BytesLike, ethers } from 'ethers'
|
|
4
|
+
import { Guard } from './guard.gen'
|
|
5
|
+
import { commons, universal } from '@0xsequence/core'
|
|
6
|
+
|
|
7
|
+
export class GuardSigner implements signers.SapientSigner {
|
|
8
|
+
private guard: Guard
|
|
9
|
+
private requests: Map<string, {
|
|
10
|
+
lastAttempt?: string;
|
|
11
|
+
onSignature: (signature: BytesLike) => void;
|
|
12
|
+
onRejection: (error: string) => void;
|
|
13
|
+
onStatus: (situation: string) => void;
|
|
14
|
+
}> = new Map()
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
public readonly address: string,
|
|
18
|
+
public readonly url: string,
|
|
19
|
+
public readonly appendSuffix: boolean = false
|
|
20
|
+
) {
|
|
21
|
+
this.guard = new Guard(url, global.fetch)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async getAddress(): Promise<string> {
|
|
25
|
+
return this.address
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async requestSignature(
|
|
29
|
+
id: string,
|
|
30
|
+
_message: BytesLike,
|
|
31
|
+
metadata: Object,
|
|
32
|
+
callbacks: {
|
|
33
|
+
onSignature: (signature: BytesLike) => void;
|
|
34
|
+
onRejection: (error: string) => void;
|
|
35
|
+
onStatus: (situation: string) => void;
|
|
36
|
+
}
|
|
37
|
+
): Promise<boolean> {
|
|
38
|
+
if (!commons.isWalletSignRequestMetadata(metadata)) {
|
|
39
|
+
callbacks.onRejection('Expected Sequence-like metadata')
|
|
40
|
+
} else {
|
|
41
|
+
// Queue the request first, this method only does that
|
|
42
|
+
// the requesting to the API is later handled on every status change
|
|
43
|
+
this.requests.set(id, callbacks)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
notifyStatusChange(
|
|
50
|
+
id: string,
|
|
51
|
+
status: Status,
|
|
52
|
+
metadata: Object
|
|
53
|
+
): void {
|
|
54
|
+
if (!this.requests.has(id)) return
|
|
55
|
+
|
|
56
|
+
if (!commons.isWalletSignRequestMetadata(metadata)) {
|
|
57
|
+
this.requests.get(id)!.onRejection('Expected Sequence-like metadata (status update)')
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.evaluateRequest(id, status.message, status, metadata)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private packMsgAndSig(address: string, msg: BytesLike, sig: BytesLike, chainId: ethers.BigNumberish): string {
|
|
65
|
+
return ethers.utils.defaultAbiCoder.encode(
|
|
66
|
+
['address', 'uint256', 'bytes', 'bytes'],
|
|
67
|
+
[address, chainId, msg, sig]
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private keyOfRequest(signer: string, msg: BytesLike, auxData: BytesLike, chainId: ethers.BigNumberish): string {
|
|
72
|
+
return ethers.utils.solidityKeccak256(
|
|
73
|
+
['address', 'uint256', 'bytes', 'bytes'],
|
|
74
|
+
[signer, chainId, msg, auxData]
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private async evaluateRequest(id: string, message: BytesLike, _: Status, metadata: commons.WalletSignRequestMetadata): Promise<void> {
|
|
79
|
+
// Building auxData, notice: this uses the old v1 format
|
|
80
|
+
// TODO: We should update the guard API so we can pass the metadata directly
|
|
81
|
+
const coder = universal.genericCoderFor(metadata.config.version)
|
|
82
|
+
const { encoded } = coder.signature.encodeSigners(metadata.config, metadata.parts ?? new Map(), [], metadata.chainId)
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const key = this.keyOfRequest(this.address, message, encoded, metadata.chainId)
|
|
86
|
+
const lastAttempt = this.requests.get(id)?.lastAttempt
|
|
87
|
+
if (lastAttempt === key) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.requests.get(id)!.lastAttempt = key
|
|
92
|
+
|
|
93
|
+
const result = await this.guard.signWith({
|
|
94
|
+
signer: this.address,
|
|
95
|
+
request: {
|
|
96
|
+
msg: ethers.utils.hexlify(message),
|
|
97
|
+
auxData: this.packMsgAndSig(metadata.address, metadata.digest, encoded, metadata.chainId),
|
|
98
|
+
chainId: ethers.BigNumber.from(metadata.chainId).toNumber() // TODO: This should be a string (in the API)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (ethers.utils.arrayify(result.sig).length !== 0) {
|
|
103
|
+
this.requests.get(id)!.onSignature(result.sig)
|
|
104
|
+
this.requests.delete(id)
|
|
105
|
+
}
|
|
106
|
+
} catch (e) {
|
|
107
|
+
// The guard signer may reject the request for a number of reasons
|
|
108
|
+
// like for example, if it's being the first signer (it waits for other signers to sign first)
|
|
109
|
+
// for now we ignore all errors, but we should probably handle them
|
|
110
|
+
// TODO: Filter real errors from control flow errors
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
suffix(): BytesLike {
|
|
115
|
+
return this.appendSuffix ? [ 3 ] : []
|
|
116
|
+
}
|
|
117
|
+
}
|