@0xsequence/relayer 3.0.0-beta.8 → 3.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/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +134 -0
- package/dist/preconditions/codec.d.ts.map +1 -1
- package/dist/preconditions/codec.js +55 -45
- package/dist/relayer/relayer.d.ts +2 -2
- package/dist/relayer/relayer.d.ts.map +1 -1
- package/dist/relayer/relayer.js +3 -1
- package/dist/relayer/rpc-relayer/index.d.ts +3 -3
- package/dist/relayer/rpc-relayer/index.d.ts.map +1 -1
- package/dist/relayer/rpc-relayer/index.js +26 -25
- package/dist/relayer/standard/eip6963.d.ts +2 -2
- package/dist/relayer/standard/eip6963.d.ts.map +1 -1
- package/dist/relayer/standard/eip6963.js +3 -3
- package/dist/relayer/standard/local.d.ts +2 -3
- package/dist/relayer/standard/local.d.ts.map +1 -1
- package/dist/relayer/standard/local.js +14 -30
- package/dist/relayer/standard/pk-relayer.d.ts +3 -3
- package/dist/relayer/standard/pk-relayer.d.ts.map +1 -1
- package/dist/relayer/standard/pk-relayer.js +3 -3
- package/dist/relayer/standard/sequence.d.ts +3 -3
- package/dist/relayer/standard/sequence.d.ts.map +1 -1
- package/dist/relayer/standard/sequence.js +2 -3
- package/eslint.config.js +4 -0
- package/package.json +9 -7
- package/src/preconditions/codec.ts +63 -39
- package/src/relayer/relayer.ts +4 -1
- package/src/relayer/rpc-relayer/index.ts +50 -33
- package/src/relayer/standard/eip6963.ts +4 -3
- package/src/relayer/standard/local.ts +37 -44
- package/src/relayer/standard/pk-relayer.ts +4 -3
- package/src/relayer/standard/sequence.ts +3 -3
- package/test/preconditions/codec.test.ts +11 -11
- package/test/preconditions/preconditions.test.ts +97 -138
- package/test/preconditions/selectors.test.ts +76 -254
- package/test/preconditions/types.test.ts +6 -6
- package/test/relayer/relayer.test.ts +4 -4
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { decodePrecondition } from '../../preconditions/index.js';
|
|
1
|
+
import { AbiFunction, TransactionReceipt } from 'ox';
|
|
2
|
+
import { decodePrecondition, } from '../../preconditions/index.js';
|
|
4
3
|
import { erc20BalanceOf, erc20Allowance, erc721OwnerOf, erc721GetApproved, erc1155BalanceOf, erc1155IsApprovedForAll, } from './abi.js';
|
|
5
4
|
export class LocalRelayer {
|
|
6
5
|
provider;
|
|
@@ -29,21 +28,9 @@ export class LocalRelayer {
|
|
|
29
28
|
isFeeRequired: false,
|
|
30
29
|
});
|
|
31
30
|
}
|
|
32
|
-
feeOptions(
|
|
31
|
+
feeOptions(_wallet, _chainId, _to, _calls) {
|
|
33
32
|
return Promise.resolve({ options: [] });
|
|
34
33
|
}
|
|
35
|
-
decodeCalls(data) {
|
|
36
|
-
const executeSelector = AbiFunction.getSelector(Constants.EXECUTE);
|
|
37
|
-
let packedPayload;
|
|
38
|
-
if (data.startsWith(executeSelector)) {
|
|
39
|
-
const decode = AbiFunction.decodeData(Constants.EXECUTE, data);
|
|
40
|
-
packedPayload = decode[0];
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
packedPayload = data;
|
|
44
|
-
}
|
|
45
|
-
return Payload.decode(Bytes.fromHex(packedPayload));
|
|
46
|
-
}
|
|
47
34
|
async relay(to, data, chainId, quote, preconditions, checkInterval = 5000) {
|
|
48
35
|
// Helper function to check all preconditions
|
|
49
36
|
const checkAllPreconditions = async () => {
|
|
@@ -125,7 +112,7 @@ export class LocalRelayer {
|
|
|
125
112
|
switch (decoded.type()) {
|
|
126
113
|
case 'native-balance': {
|
|
127
114
|
const native = decoded;
|
|
128
|
-
const balance = await this.provider.getBalance(native.address
|
|
115
|
+
const balance = await this.provider.getBalance(native.address);
|
|
129
116
|
if (native.min !== undefined && balance < native.min) {
|
|
130
117
|
return false;
|
|
131
118
|
}
|
|
@@ -136,9 +123,9 @@ export class LocalRelayer {
|
|
|
136
123
|
}
|
|
137
124
|
case 'erc20-balance': {
|
|
138
125
|
const erc20 = decoded;
|
|
139
|
-
const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address
|
|
126
|
+
const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address]);
|
|
140
127
|
const result = await this.provider.call({
|
|
141
|
-
to: erc20.token
|
|
128
|
+
to: erc20.token,
|
|
142
129
|
data,
|
|
143
130
|
});
|
|
144
131
|
const balance = BigInt(result);
|
|
@@ -152,9 +139,9 @@ export class LocalRelayer {
|
|
|
152
139
|
}
|
|
153
140
|
case 'erc20-approval': {
|
|
154
141
|
const erc20 = decoded;
|
|
155
|
-
const data = AbiFunction.encodeData(erc20Allowance, [erc20.address
|
|
142
|
+
const data = AbiFunction.encodeData(erc20Allowance, [erc20.address, erc20.operator]);
|
|
156
143
|
const result = await this.provider.call({
|
|
157
|
-
to: erc20.token
|
|
144
|
+
to: erc20.token,
|
|
158
145
|
data,
|
|
159
146
|
});
|
|
160
147
|
const allowance = BigInt(result);
|
|
@@ -164,7 +151,7 @@ export class LocalRelayer {
|
|
|
164
151
|
const erc721 = decoded;
|
|
165
152
|
const data = AbiFunction.encodeData(erc721OwnerOf, [erc721.tokenId]);
|
|
166
153
|
const result = await this.provider.call({
|
|
167
|
-
to: erc721.token
|
|
154
|
+
to: erc721.token,
|
|
168
155
|
data,
|
|
169
156
|
});
|
|
170
157
|
const owner = '0x' + result.slice(26);
|
|
@@ -175,7 +162,7 @@ export class LocalRelayer {
|
|
|
175
162
|
const erc721 = decoded;
|
|
176
163
|
const data = AbiFunction.encodeData(erc721GetApproved, [erc721.tokenId]);
|
|
177
164
|
const result = await this.provider.call({
|
|
178
|
-
to: erc721.token
|
|
165
|
+
to: erc721.token,
|
|
179
166
|
data,
|
|
180
167
|
});
|
|
181
168
|
const approved = '0x' + result.slice(26);
|
|
@@ -183,9 +170,9 @@ export class LocalRelayer {
|
|
|
183
170
|
}
|
|
184
171
|
case 'erc1155-balance': {
|
|
185
172
|
const erc1155 = decoded;
|
|
186
|
-
const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address
|
|
173
|
+
const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address, erc1155.tokenId]);
|
|
187
174
|
const result = await this.provider.call({
|
|
188
|
-
to: erc1155.token
|
|
175
|
+
to: erc1155.token,
|
|
189
176
|
data,
|
|
190
177
|
});
|
|
191
178
|
const balance = BigInt(result);
|
|
@@ -199,12 +186,9 @@ export class LocalRelayer {
|
|
|
199
186
|
}
|
|
200
187
|
case 'erc1155-approval': {
|
|
201
188
|
const erc1155 = decoded;
|
|
202
|
-
const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [
|
|
203
|
-
erc1155.address.toString(),
|
|
204
|
-
erc1155.operator.toString(),
|
|
205
|
-
]);
|
|
189
|
+
const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [erc1155.address, erc1155.operator]);
|
|
206
190
|
const result = await this.provider.call({
|
|
207
|
-
to: erc1155.token
|
|
191
|
+
to: erc1155.token,
|
|
208
192
|
data,
|
|
209
193
|
});
|
|
210
194
|
return BigInt(result) === 1n;
|
|
@@ -4,7 +4,7 @@ import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js';
|
|
|
4
4
|
import { FeeToken } from '../rpc-relayer/relayer.gen.js';
|
|
5
5
|
export declare class PkRelayer implements Relayer {
|
|
6
6
|
private readonly provider;
|
|
7
|
-
readonly kind
|
|
7
|
+
readonly kind = "relayer";
|
|
8
8
|
readonly type = "pk";
|
|
9
9
|
readonly id = "pk";
|
|
10
10
|
private readonly relayer;
|
|
@@ -15,7 +15,7 @@ export declare class PkRelayer implements Relayer {
|
|
|
15
15
|
tokens?: FeeToken[];
|
|
16
16
|
paymentAddress?: Address.Address;
|
|
17
17
|
}>;
|
|
18
|
-
feeOptions(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<{
|
|
18
|
+
feeOptions(wallet: Address.Address, chainId: number, to: Address.Address, calls: Payload.Call[]): Promise<{
|
|
19
19
|
options: FeeOption[];
|
|
20
20
|
quote?: FeeQuote;
|
|
21
21
|
}>;
|
|
@@ -23,6 +23,6 @@ export declare class PkRelayer implements Relayer {
|
|
|
23
23
|
opHash: Hex.Hex;
|
|
24
24
|
}>;
|
|
25
25
|
status(opHash: Hex.Hex, chainId: number): Promise<OperationStatus>;
|
|
26
|
-
checkPrecondition(
|
|
26
|
+
checkPrecondition(_precondition: Precondition.Precondition): Promise<boolean>;
|
|
27
27
|
}
|
|
28
28
|
//# sourceMappingURL=pk-relayer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pk-relayer.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/pk-relayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAA6D,MAAM,IAAI,CAAA;AAEtG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAExD,qBAAa,SAAU,YAAW,OAAO;IAQrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,SAAgB,IAAI,
|
|
1
|
+
{"version":3,"file":"pk-relayer.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/pk-relayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAA6D,MAAM,IAAI,CAAA;AAEtG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAExD,qBAAa,SAAU,YAAW,OAAO;IAQrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,SAAgB,IAAI,aAAY;IAChC,SAAgB,IAAI,QAAO;IAC3B,SAAgB,EAAE,QAAO;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAGpC,UAAU,EAAE,GAAG,CAAC,GAAG,EACF,QAAQ,EAAE,QAAQ,CAAC,QAAQ;IA0FxC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9E,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAIvG,UAAU,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,OAAO,CAAC,OAAO,EACnB,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAIhD,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAQ5G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAI5D,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAIpF"}
|
|
@@ -92,8 +92,8 @@ export class PkRelayer {
|
|
|
92
92
|
feeTokens() {
|
|
93
93
|
return this.relayer.feeTokens();
|
|
94
94
|
}
|
|
95
|
-
feeOptions(wallet, chainId, calls) {
|
|
96
|
-
return this.relayer.feeOptions(wallet, chainId, calls);
|
|
95
|
+
feeOptions(wallet, chainId, to, calls) {
|
|
96
|
+
return this.relayer.feeOptions(wallet, chainId, to, calls);
|
|
97
97
|
}
|
|
98
98
|
async relay(to, data, chainId, _) {
|
|
99
99
|
const providerChainId = Number(await this.provider.request({ method: 'eth_chainId' }));
|
|
@@ -105,7 +105,7 @@ export class PkRelayer {
|
|
|
105
105
|
status(opHash, chainId) {
|
|
106
106
|
return this.relayer.status(opHash, chainId);
|
|
107
107
|
}
|
|
108
|
-
async checkPrecondition(
|
|
108
|
+
async checkPrecondition(_precondition) {
|
|
109
109
|
// TODO: Implement precondition check
|
|
110
110
|
return true;
|
|
111
111
|
}
|
|
@@ -3,7 +3,7 @@ import { Payload } from '@0xsequence/wallet-primitives';
|
|
|
3
3
|
import { Address, Hex } from 'ox';
|
|
4
4
|
import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js';
|
|
5
5
|
export declare class SequenceRelayer implements Relayer {
|
|
6
|
-
readonly kind
|
|
6
|
+
readonly kind = "relayer";
|
|
7
7
|
readonly type = "sequence";
|
|
8
8
|
readonly id = "sequence";
|
|
9
9
|
private readonly service;
|
|
@@ -14,11 +14,11 @@ export declare class SequenceRelayer implements Relayer {
|
|
|
14
14
|
tokens?: FeeToken[];
|
|
15
15
|
paymentAddress?: Address.Address;
|
|
16
16
|
}>;
|
|
17
|
-
feeOptions(wallet: Address.Address, _chainId: number, calls: Payload.Call[]): Promise<{
|
|
17
|
+
feeOptions(wallet: Address.Address, _chainId: number, to: Address.Address, calls: Payload.Call[]): Promise<{
|
|
18
18
|
options: FeeOption[];
|
|
19
19
|
quote?: FeeQuote;
|
|
20
20
|
}>;
|
|
21
|
-
checkPrecondition(
|
|
21
|
+
checkPrecondition(_precondition: TransactionPrecondition): Promise<boolean>;
|
|
22
22
|
relay(to: Address.Address, data: Hex.Hex, _chainId: number, quote?: FeeQuote): Promise<{
|
|
23
23
|
opHash: Hex.Hex;
|
|
24
24
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,uBAAuB,EAAsB,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,MAAM,IAAI,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,qBAAa,eAAgB,YAAW,OAAO;IAC7C,SAAgB,IAAI,
|
|
1
|
+
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,uBAAuB,EAAsB,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,MAAM,IAAI,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,qBAAa,eAAgB,YAAW,OAAO;IAC7C,SAAgB,IAAI,aAAY;IAChC,SAAgB,IAAI,cAAa;IACjC,QAAQ,CAAC,EAAE,cAAa;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,MAAM;IAIlB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzE,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAgBvG,UAAU,CACd,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,OAAO,CAAC,OAAO,EACnB,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAchD,iBAAiB,CAAC,aAAa,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3E,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAW3G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAuC1E"}
|
|
@@ -27,8 +27,7 @@ export class SequenceRelayer {
|
|
|
27
27
|
isFeeRequired,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
async feeOptions(wallet, _chainId, calls) {
|
|
31
|
-
const to = wallet; // TODO: this might be the guest module
|
|
30
|
+
async feeOptions(wallet, _chainId, to, calls) {
|
|
32
31
|
const execute = AbiFunction.from('function execute(bytes calldata _payload, bytes calldata _signature)');
|
|
33
32
|
const payload = Payload.encode({ type: 'call', space: 0n, nonce: 0n, calls }, to);
|
|
34
33
|
const signature = '0x0001'; // TODO: use a stub signature
|
|
@@ -39,7 +38,7 @@ export class SequenceRelayer {
|
|
|
39
38
|
quote: quote ? { _tag: 'FeeQuote', _quote: quote } : undefined,
|
|
40
39
|
};
|
|
41
40
|
}
|
|
42
|
-
async checkPrecondition(
|
|
41
|
+
async checkPrecondition(_precondition) {
|
|
43
42
|
// TODO: implement
|
|
44
43
|
return false;
|
|
45
44
|
}
|
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/relayer",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"description": "relayer sub-package for Sequence",
|
|
9
9
|
"repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/services/relayer",
|
|
10
|
-
"author": "Sequence Platforms
|
|
10
|
+
"author": "Sequence Platforms ULC",
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
@@ -16,16 +16,17 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@types/node": "^25.0
|
|
19
|
+
"@types/node": "^25.3.0",
|
|
20
20
|
"typescript": "^5.9.3",
|
|
21
|
-
"vitest": "^4.0.
|
|
22
|
-
"@repo/typescript-config": "^0.0.1
|
|
21
|
+
"vitest": "^4.0.18",
|
|
22
|
+
"@repo/typescript-config": "^0.0.1",
|
|
23
|
+
"@repo/eslint-config": "^0.0.1"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"mipd": "^0.0.7",
|
|
26
27
|
"ox": "^0.9.17",
|
|
27
28
|
"viem": "^2.40.3",
|
|
28
|
-
"@0xsequence/wallet-primitives": "^3.0.0
|
|
29
|
+
"@0xsequence/wallet-primitives": "^3.0.0"
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"build": "tsc",
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"old-test:file": "NODE_OPTIONS='--import tsx' mocha --timeout 60000",
|
|
36
37
|
"old-test:concurrently": "concurrently -k --success first 'pnpm start:hardhat > /dev/null' ",
|
|
37
38
|
"start:hardhat": "pnpm hardhat node --port 9547",
|
|
38
|
-
"typecheck": "tsc --noEmit"
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"lint": "eslint . --max-warnings 0"
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -36,6 +36,11 @@ export function decodePrecondition(p: TransactionPrecondition): Precondition | u
|
|
|
36
36
|
return undefined
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
if (typeof p.minAmount !== 'bigint') {
|
|
40
|
+
console.warn(`Failed to decode precondition: minAmount must be a bigint`)
|
|
41
|
+
return undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
let precondition: Precondition | undefined
|
|
40
45
|
|
|
41
46
|
try {
|
|
@@ -118,73 +123,92 @@ export function decodePrecondition(p: TransactionPrecondition): Precondition | u
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
export function encodePrecondition(p: Precondition): string {
|
|
121
|
-
const data: any = {}
|
|
122
|
-
|
|
123
126
|
switch (p.type()) {
|
|
124
127
|
case 'native-balance': {
|
|
125
128
|
const native = p as NativeBalancePrecondition
|
|
126
|
-
data
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
const data = {
|
|
130
|
+
address: native.address.toString(),
|
|
131
|
+
...(native.min !== undefined && { min: native.min.toString() }),
|
|
132
|
+
...(native.max !== undefined && { max: native.max.toString() }),
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return JSON.stringify(data)
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
case 'erc20-balance': {
|
|
133
139
|
const erc20 = p as Erc20BalancePrecondition
|
|
134
|
-
data
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
const data = {
|
|
141
|
+
address: erc20.address.toString(),
|
|
142
|
+
token: erc20.token.toString(),
|
|
143
|
+
...(erc20.min !== undefined && { min: erc20.min.toString() }),
|
|
144
|
+
...(erc20.max !== undefined && { max: erc20.max.toString() }),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return JSON.stringify(data)
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
case 'erc20-approval': {
|
|
142
151
|
const erc20 = p as Erc20ApprovalPrecondition
|
|
143
|
-
data
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
const data = {
|
|
153
|
+
address: erc20.address.toString(),
|
|
154
|
+
token: erc20.token.toString(),
|
|
155
|
+
operator: erc20.operator.toString(),
|
|
156
|
+
min: erc20.min.toString(),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return JSON.stringify(data)
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
case 'erc721-ownership': {
|
|
151
163
|
const erc721 = p as Erc721OwnershipPrecondition
|
|
152
|
-
data
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
const data = {
|
|
165
|
+
address: erc721.address.toString(),
|
|
166
|
+
token: erc721.token.toString(),
|
|
167
|
+
tokenId: erc721.tokenId.toString(),
|
|
168
|
+
...(erc721.owned !== undefined && { owned: erc721.owned }),
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return JSON.stringify(data)
|
|
157
172
|
}
|
|
158
173
|
|
|
159
174
|
case 'erc721-approval': {
|
|
160
175
|
const erc721 = p as Erc721ApprovalPrecondition
|
|
161
|
-
data
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
176
|
+
const data = {
|
|
177
|
+
address: erc721.address.toString(),
|
|
178
|
+
token: erc721.token.toString(),
|
|
179
|
+
tokenId: erc721.tokenId.toString(),
|
|
180
|
+
operator: erc721.operator.toString(),
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return JSON.stringify(data)
|
|
166
184
|
}
|
|
167
185
|
|
|
168
186
|
case 'erc1155-balance': {
|
|
169
187
|
const erc1155 = p as Erc1155BalancePrecondition
|
|
170
|
-
data
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
const data = {
|
|
189
|
+
address: erc1155.address.toString(),
|
|
190
|
+
token: erc1155.token.toString(),
|
|
191
|
+
tokenId: erc1155.tokenId.toString(),
|
|
192
|
+
...(erc1155.min !== undefined && { min: erc1155.min.toString() }),
|
|
193
|
+
...(erc1155.max !== undefined && { max: erc1155.max.toString() }),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return JSON.stringify(data)
|
|
176
197
|
}
|
|
177
198
|
|
|
178
199
|
case 'erc1155-approval': {
|
|
179
200
|
const erc1155 = p as Erc1155ApprovalPrecondition
|
|
180
|
-
data
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
201
|
+
const data = {
|
|
202
|
+
address: erc1155.address.toString(),
|
|
203
|
+
token: erc1155.token.toString(),
|
|
204
|
+
tokenId: erc1155.tokenId.toString(),
|
|
205
|
+
operator: erc1155.operator.toString(),
|
|
206
|
+
min: erc1155.min.toString(),
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return JSON.stringify(data)
|
|
186
210
|
}
|
|
187
211
|
}
|
|
188
212
|
|
|
189
|
-
return JSON.stringify(
|
|
213
|
+
return JSON.stringify({})
|
|
190
214
|
}
|
package/src/relayer/relayer.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface Relayer {
|
|
|
16
16
|
feeOptions(
|
|
17
17
|
wallet: Address.Address,
|
|
18
18
|
chainId: number,
|
|
19
|
+
to: Address.Address,
|
|
19
20
|
calls: Payload.Call[],
|
|
20
21
|
): Promise<{ options: FeeOption[]; quote?: FeeQuote }>
|
|
21
22
|
|
|
@@ -26,8 +27,10 @@ export interface Relayer {
|
|
|
26
27
|
checkPrecondition(precondition: Precondition.Precondition): Promise<boolean>
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
export function isRelayer(relayer:
|
|
30
|
+
export function isRelayer(relayer: unknown): relayer is Relayer {
|
|
30
31
|
return (
|
|
32
|
+
typeof relayer === 'object' &&
|
|
33
|
+
relayer !== null &&
|
|
31
34
|
'isAvailable' in relayer &&
|
|
32
35
|
'feeOptions' in relayer &&
|
|
33
36
|
'relay' in relayer &&
|
|
@@ -7,10 +7,19 @@ import {
|
|
|
7
7
|
TransactionPrecondition,
|
|
8
8
|
ETHTxnStatus,
|
|
9
9
|
} from './relayer.gen.js'
|
|
10
|
-
import { Address, Hex,
|
|
10
|
+
import { Address, Hex, AbiFunction } from 'ox'
|
|
11
11
|
import { Constants, Payload, Network } from '@0xsequence/wallet-primitives'
|
|
12
12
|
import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js'
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
decodePrecondition,
|
|
15
|
+
Erc1155ApprovalPrecondition,
|
|
16
|
+
Erc1155BalancePrecondition,
|
|
17
|
+
Erc20ApprovalPrecondition,
|
|
18
|
+
Erc20BalancePrecondition,
|
|
19
|
+
Erc721ApprovalPrecondition,
|
|
20
|
+
Erc721OwnershipPrecondition,
|
|
21
|
+
NativeBalancePrecondition,
|
|
22
|
+
} from '../../preconditions/index.js'
|
|
14
23
|
import {
|
|
15
24
|
erc20BalanceOf,
|
|
16
25
|
erc20Allowance,
|
|
@@ -49,12 +58,14 @@ const networkToChain = (network: Network.Network): Chain => {
|
|
|
49
58
|
},
|
|
50
59
|
}
|
|
51
60
|
: undefined,
|
|
52
|
-
contracts: network.
|
|
53
|
-
?
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
contracts: network.contracts
|
|
62
|
+
? Object.entries(network.contracts).reduce(
|
|
63
|
+
(acc, [name, address]) => {
|
|
64
|
+
acc[name] = { address }
|
|
65
|
+
return acc
|
|
56
66
|
},
|
|
57
|
-
|
|
67
|
+
{} as Record<string, { address: Address.Address }>,
|
|
68
|
+
)
|
|
58
69
|
: undefined,
|
|
59
70
|
} as Chain
|
|
60
71
|
}
|
|
@@ -67,7 +78,9 @@ export const getChain = (chainId: number): Chain => {
|
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
// Fall back to viem's built-in chains
|
|
70
|
-
const viemChain = Object.values(chains).find(
|
|
81
|
+
const viemChain = Object.values(chains).find(
|
|
82
|
+
(c: unknown) => typeof c === 'object' && c !== null && 'id' in c && c.id === chainId,
|
|
83
|
+
)
|
|
71
84
|
if (viemChain) {
|
|
72
85
|
return viemChain as Chain
|
|
73
86
|
}
|
|
@@ -76,7 +89,7 @@ export const getChain = (chainId: number): Chain => {
|
|
|
76
89
|
}
|
|
77
90
|
|
|
78
91
|
export class RpcRelayer implements Relayer {
|
|
79
|
-
public readonly kind
|
|
92
|
+
public readonly kind = 'relayer'
|
|
80
93
|
public readonly type = 'rpc'
|
|
81
94
|
public readonly id: string
|
|
82
95
|
public readonly chainId: number
|
|
@@ -134,17 +147,24 @@ export class RpcRelayer implements Relayer {
|
|
|
134
147
|
async feeOptions(
|
|
135
148
|
wallet: Address.Address,
|
|
136
149
|
chainId: number,
|
|
150
|
+
to: Address.Address,
|
|
137
151
|
calls: Payload.Call[],
|
|
138
152
|
): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
|
|
153
|
+
// IMPORTANT:
|
|
154
|
+
// The relayer FeeOptions endpoint simulates `eth_call(to, data)`.
|
|
155
|
+
// wallet-webapp-v3 requests FeeOptions with `to = wallet` and `data = Payload.encode(calls, self=wallet)`.
|
|
156
|
+
// This works for undeployed wallets and avoids guest-module simulation pitfalls.
|
|
139
157
|
const callsStruct: Payload.Calls = { type: 'call', space: 0n, nonce: 0n, calls: calls }
|
|
140
|
-
|
|
158
|
+
|
|
159
|
+
const feeOptionsTo = wallet
|
|
160
|
+
const data = Payload.encode(callsStruct, wallet)
|
|
141
161
|
|
|
142
162
|
try {
|
|
143
163
|
const result = await this.client.feeOptions(
|
|
144
164
|
{
|
|
145
|
-
wallet
|
|
146
|
-
to:
|
|
147
|
-
data:
|
|
165
|
+
wallet,
|
|
166
|
+
to: feeOptionsTo,
|
|
167
|
+
data: Hex.fromBytes(data),
|
|
148
168
|
},
|
|
149
169
|
{ ...(this.projectAccessKey ? { 'X-Access-Key': this.projectAccessKey } : undefined) },
|
|
150
170
|
)
|
|
@@ -230,7 +250,7 @@ export class RpcRelayer implements Relayer {
|
|
|
230
250
|
return { opHash: `0x${result.txnHash}` }
|
|
231
251
|
}
|
|
232
252
|
|
|
233
|
-
async status(opHash: Hex.Hex,
|
|
253
|
+
async status(opHash: Hex.Hex, _chainId: number): Promise<OperationStatus> {
|
|
234
254
|
try {
|
|
235
255
|
const cleanedOpHash = opHash.startsWith('0x') ? opHash.substring(2) : opHash
|
|
236
256
|
const result = await this.client.getMetaTxnReceipt({ metaTxID: cleanedOpHash })
|
|
@@ -282,9 +302,9 @@ export class RpcRelayer implements Relayer {
|
|
|
282
302
|
|
|
283
303
|
switch (decoded.type()) {
|
|
284
304
|
case 'native-balance': {
|
|
285
|
-
const native = decoded as
|
|
305
|
+
const native = decoded as NativeBalancePrecondition
|
|
286
306
|
try {
|
|
287
|
-
const balance = await this.provider.getBalance({ address: native.address
|
|
307
|
+
const balance = await this.provider.getBalance({ address: native.address })
|
|
288
308
|
const minWei = native.min !== undefined ? BigInt(native.min) : undefined
|
|
289
309
|
const maxWei = native.max !== undefined ? BigInt(native.max) : undefined
|
|
290
310
|
|
|
@@ -307,9 +327,9 @@ export class RpcRelayer implements Relayer {
|
|
|
307
327
|
}
|
|
308
328
|
|
|
309
329
|
case 'erc20-balance': {
|
|
310
|
-
const erc20 = decoded as
|
|
330
|
+
const erc20 = decoded as Erc20BalancePrecondition
|
|
311
331
|
try {
|
|
312
|
-
const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address
|
|
332
|
+
const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address])
|
|
313
333
|
const result = await this.provider.call({
|
|
314
334
|
to: erc20.token.toString() as `0x${string}`,
|
|
315
335
|
data: data as `0x${string}`,
|
|
@@ -336,9 +356,9 @@ export class RpcRelayer implements Relayer {
|
|
|
336
356
|
}
|
|
337
357
|
|
|
338
358
|
case 'erc20-approval': {
|
|
339
|
-
const erc20 = decoded as
|
|
359
|
+
const erc20 = decoded as Erc20ApprovalPrecondition
|
|
340
360
|
try {
|
|
341
|
-
const data = AbiFunction.encodeData(erc20Allowance, [erc20.address
|
|
361
|
+
const data = AbiFunction.encodeData(erc20Allowance, [erc20.address, erc20.operator])
|
|
342
362
|
const result = await this.provider.call({
|
|
343
363
|
to: erc20.token.toString() as `0x${string}`,
|
|
344
364
|
data: data as `0x${string}`,
|
|
@@ -353,12 +373,12 @@ export class RpcRelayer implements Relayer {
|
|
|
353
373
|
}
|
|
354
374
|
|
|
355
375
|
case 'erc721-ownership': {
|
|
356
|
-
const erc721 = decoded as
|
|
376
|
+
const erc721 = decoded as Erc721OwnershipPrecondition
|
|
357
377
|
try {
|
|
358
378
|
const data = AbiFunction.encodeData(erc721OwnerOf, [erc721.tokenId])
|
|
359
379
|
const result = await this.provider.call({
|
|
360
|
-
to: erc721.token
|
|
361
|
-
data: data
|
|
380
|
+
to: erc721.token,
|
|
381
|
+
data: data,
|
|
362
382
|
})
|
|
363
383
|
const resultHex = result.toString() as `0x${string}`
|
|
364
384
|
const owner = resultHex.slice(-40)
|
|
@@ -372,7 +392,7 @@ export class RpcRelayer implements Relayer {
|
|
|
372
392
|
}
|
|
373
393
|
|
|
374
394
|
case 'erc721-approval': {
|
|
375
|
-
const erc721 = decoded as
|
|
395
|
+
const erc721 = decoded as Erc721ApprovalPrecondition
|
|
376
396
|
try {
|
|
377
397
|
const data = AbiFunction.encodeData(erc721GetApproved, [erc721.tokenId])
|
|
378
398
|
const result = await this.provider.call({
|
|
@@ -389,9 +409,9 @@ export class RpcRelayer implements Relayer {
|
|
|
389
409
|
}
|
|
390
410
|
|
|
391
411
|
case 'erc1155-balance': {
|
|
392
|
-
const erc1155 = decoded as
|
|
412
|
+
const erc1155 = decoded as Erc1155BalancePrecondition
|
|
393
413
|
try {
|
|
394
|
-
const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address
|
|
414
|
+
const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address, erc1155.tokenId])
|
|
395
415
|
const result = await this.provider.call({
|
|
396
416
|
to: erc1155.token.toString() as `0x${string}`,
|
|
397
417
|
data: data as `0x${string}`,
|
|
@@ -418,15 +438,12 @@ export class RpcRelayer implements Relayer {
|
|
|
418
438
|
}
|
|
419
439
|
|
|
420
440
|
case 'erc1155-approval': {
|
|
421
|
-
const erc1155 = decoded as
|
|
441
|
+
const erc1155 = decoded as Erc1155ApprovalPrecondition
|
|
422
442
|
try {
|
|
423
|
-
const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [
|
|
424
|
-
erc1155.address.toString(),
|
|
425
|
-
erc1155.operator.toString(),
|
|
426
|
-
])
|
|
443
|
+
const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [erc1155.address, erc1155.operator])
|
|
427
444
|
const result = await this.provider.call({
|
|
428
|
-
to: erc1155.token
|
|
429
|
-
data: data
|
|
445
|
+
to: erc1155.token,
|
|
446
|
+
data: data,
|
|
430
447
|
})
|
|
431
448
|
return BigInt(result.toString()) === 1n
|
|
432
449
|
} catch (error) {
|
|
@@ -6,7 +6,7 @@ import { Payload } from '@0xsequence/wallet-primitives'
|
|
|
6
6
|
import { FeeToken, TransactionPrecondition } from '../rpc-relayer/relayer.gen.js'
|
|
7
7
|
|
|
8
8
|
export class EIP6963Relayer implements Relayer {
|
|
9
|
-
public readonly kind
|
|
9
|
+
public readonly kind = 'relayer'
|
|
10
10
|
public readonly type = 'eip6963'
|
|
11
11
|
public readonly id: string
|
|
12
12
|
public readonly info: EIP6963ProviderInfo
|
|
@@ -30,9 +30,10 @@ export class EIP6963Relayer implements Relayer {
|
|
|
30
30
|
feeOptions(
|
|
31
31
|
wallet: Address.Address,
|
|
32
32
|
chainId: number,
|
|
33
|
+
to: Address.Address,
|
|
33
34
|
calls: Payload.Call[],
|
|
34
35
|
): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
|
|
35
|
-
return this.relayer.feeOptions(wallet, chainId, calls)
|
|
36
|
+
return this.relayer.feeOptions(wallet, chainId, to, calls)
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
async relay(to: Address.Address, data: Hex.Hex, chainId: number, _?: FeeQuote): Promise<{ opHash: Hex.Hex }> {
|
|
@@ -58,7 +59,7 @@ export function getEIP6963Store() {
|
|
|
58
59
|
return store
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
const relayers: Map<string, EIP6963Relayer> = new Map()
|
|
62
63
|
|
|
63
64
|
export function getRelayers(): EIP6963Relayer[] {
|
|
64
65
|
const store = getEIP6963Store()
|