@@ -5,12 +5,13 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
5
5
import 'common.dart' ;
6
6
import 'src/exceptions.dart' ;
7
7
import 'src/generated/api/receive.dart' ;
8
- import 'src/generated/api/bitcoin_ffi.dart' ;
9
8
import 'src/generated/utils/error.dart' as error;
10
9
import 'uri.dart' ;
10
+ import 'bitcoin_ffi.dart' ;
11
11
12
- class Receiver extends FfiReceiver {
13
- Receiver ._({required super .field0});
12
+ class Receiver {
13
+ final FfiReceiver _ffiReceiver;
14
+ Receiver ._({required ffiReceiver}) : _ffiReceiver = ffiReceiver;
14
15
15
16
static Future <Receiver > create (
16
17
{required String address,
@@ -27,16 +28,15 @@ class Receiver extends FfiReceiver {
27
28
address: address,
28
29
expireAfter: expireAfter,
29
30
network: network);
30
- return Receiver ._(field0 : res.field0 );
31
+ return Receiver ._(ffiReceiver : res);
31
32
} on error.PayjoinError catch (e) {
32
33
throw mapPayjoinError (e);
33
34
}
34
35
}
35
36
36
- @override
37
37
Future <(Request , ClientResponse )> extractReq () async {
38
38
try {
39
- final res = await super .extractReq ();
39
+ final res = await _ffiReceiver .extractReq ();
40
40
final request = Request (
41
41
url: await Url .fromStr (res.$1.url.asString ()),
42
42
contentType: res.$1.contentType,
@@ -48,13 +48,12 @@ class Receiver extends FfiReceiver {
48
48
}
49
49
}
50
50
51
- @override
52
51
Future <UncheckedProposal ?> processRes (
53
52
{required List <int > body, required ClientResponse ctx}) async {
54
53
try {
55
- final res = await super .processRes (body: body, ctx: ctx);
54
+ final res = await _ffiReceiver .processRes (body: body, ctx: ctx);
56
55
if (res != null ) {
57
- return UncheckedProposal ._(field0 : res.field0 );
56
+ return UncheckedProposal ._(ffiUncheckedProposal : res);
58
57
} else {
59
58
return null ;
60
59
}
@@ -65,27 +64,26 @@ class Receiver extends FfiReceiver {
65
64
66
65
/// The contents of the `&pj=` query parameter including the base64url-encoded public key receiver subdirectory.
67
66
/// This identifies a session at the payjoin directory server.
68
- @override
69
67
Future <Url > pjUrl () async {
70
- final res = await super .pjUrl ();
68
+ final res = await _ffiReceiver .pjUrl ();
71
69
return Url .fromStr (res.asString ());
72
70
}
73
71
74
- @override
75
72
PjUriBuilder pjUriBuilder () {
76
- final res = super .pjUriBuilder ();
73
+ final res = _ffiReceiver .pjUriBuilder ();
77
74
return PjUriBuilder (internal: res.internal);
78
75
}
79
76
}
80
77
81
- class UncheckedProposal extends FfiUncheckedProposal {
82
- UncheckedProposal ._({required super .field0});
78
+ class UncheckedProposal {
79
+ final FfiUncheckedProposal _ffiUncheckedProposal;
80
+ UncheckedProposal ._({required ffiUncheckedProposal})
81
+ : _ffiUncheckedProposal = ffiUncheckedProposal;
83
82
84
83
///The Sender’s Original PSBT
85
- @override
86
84
Future <Uint8List > extractTxToScheduleBroadcast ({hint}) async {
87
85
try {
88
- return super .extractTxToScheduleBroadcast ();
86
+ return _ffiUncheckedProposal .extractTxToScheduleBroadcast ();
89
87
} on error.PayjoinError catch (e) {
90
88
throw mapPayjoinError (e);
91
89
}
@@ -95,15 +93,14 @@ class UncheckedProposal extends FfiUncheckedProposal {
95
93
/// Receiver MUST check that the Original PSBT from the sender can be broadcast, i.e. testmempoolaccept bitcoind rpc returns { “allowed”: true,.. } for gettransactiontocheckbroadcast() before calling this method.
96
94
/// Do this check if you generate bitcoin uri to receive Payjoin on sender request without manual human approval, like a payment processor. Such so called “non-interactive” receivers are otherwise vulnerable to probing attacks. If a sender can make requests at will, they can learn which bitcoin the receiver owns at no cost. Broadcasting the Original PSBT after some time in the failure case makes incurs sender cost and prevents probing.
97
95
/// Call this after checking downstream.
98
- @override
99
96
Future <MaybeInputsOwned > checkBroadcastSuitability (
100
97
{BigInt ? minFeeRate,
101
98
required FutureOr <bool > Function (Uint8List p1) canBroadcast,
102
99
hint}) async {
103
100
try {
104
- final res = await super .checkBroadcastSuitability (
101
+ final res = await _ffiUncheckedProposal .checkBroadcastSuitability (
105
102
minFeeRate: minFeeRate, canBroadcast: canBroadcast);
106
- return MaybeInputsOwned ._(field0 : res.field0 );
103
+ return MaybeInputsOwned ._(ffiMaybeInputsOwned : res);
107
104
} on error.PayjoinError catch (e) {
108
105
throw mapPayjoinError (e);
109
106
}
@@ -112,120 +109,123 @@ class UncheckedProposal extends FfiUncheckedProposal {
112
109
///Call this method if the only way to initiate a Payjoin with this receiver requires manual intervention, as in most consumer wallets.
113
110
/// So-called “non-interactive” receivers, like payment processors,
114
111
/// that allow arbitrary requests are otherwise vulnerable to probing attacks. Those receivers call gettransactiontocheckbroadcast() and attesttestedandscheduledbroadcast() after making those checks downstream
115
- @override
116
112
Future <MaybeInputsOwned > assumeInteractiveReceiver ({hint}) async {
117
113
try {
118
- final res = await super .assumeInteractiveReceiver ();
119
- return MaybeInputsOwned ._(field0 : res.field0 );
114
+ final res = await _ffiUncheckedProposal .assumeInteractiveReceiver ();
115
+ return MaybeInputsOwned ._(ffiMaybeInputsOwned : res);
120
116
} on error.PayjoinError catch (e) {
121
117
throw mapPayjoinError (e);
122
118
}
123
119
}
124
120
}
125
121
126
- class MaybeInputsOwned extends FfiMaybeInputsOwned {
127
- MaybeInputsOwned ._({required super .field0});
122
+ class MaybeInputsOwned {
123
+ final FfiMaybeInputsOwned _ffiMaybeInputsOwned;
124
+ MaybeInputsOwned ._({required ffiMaybeInputsOwned})
125
+ : _ffiMaybeInputsOwned = ffiMaybeInputsOwned;
128
126
129
127
///Check that the Original PSBT has no receiver-owned inputs. Return original-psbt-rejected error or otherwise refuse to sign undesirable inputs.
130
128
/// An attacker could try to spend receiver's own inputs. This check prevents that.
131
- @override
132
129
Future <MaybeInputsSeen > checkInputsNotOwned (
133
130
{required FutureOr <bool > Function (Uint8List p1) isOwned, hint}) async {
134
131
try {
135
- final res = await super .checkInputsNotOwned (isOwned: isOwned);
136
- return MaybeInputsSeen ._(field0: res.field0);
132
+ final res =
133
+ await _ffiMaybeInputsOwned.checkInputsNotOwned (isOwned: isOwned);
134
+ return MaybeInputsSeen ._(ffiMaybeInputsSeen: res);
137
135
} on error.PayjoinError catch (e) {
138
136
throw mapPayjoinError (e);
139
137
}
140
138
}
141
139
}
142
140
143
- class MaybeInputsSeen extends FfiMaybeInputsSeen {
144
- MaybeInputsSeen ._({required super .field0});
141
+ class MaybeInputsSeen {
142
+ final FfiMaybeInputsSeen _ffiMaybeInputsSeen;
143
+ MaybeInputsSeen ._({required ffiMaybeInputsSeen})
144
+ : _ffiMaybeInputsSeen = ffiMaybeInputsSeen;
145
145
146
146
/// Make sure that the original transaction inputs have never been seen before.
147
147
/// This prevents probing attacks. This prevents reentrant Payjoin, where a sender
148
148
/// proposes a Payjoin PSBT as a new Original PSBT for a new Payjoin.
149
- @override
150
149
Future <OutputsUnknown > checkNoInputsSeenBefore (
151
150
{required FutureOr <bool > Function (OutPoint p1) isKnown, hint}) async {
152
151
try {
153
- final res = await super .checkNoInputsSeenBefore (isKnown: isKnown);
154
- return OutputsUnknown ._(field0: res.field0);
152
+ final res =
153
+ await _ffiMaybeInputsSeen.checkNoInputsSeenBefore (isKnown: isKnown);
154
+ return OutputsUnknown ._(ffiOutputsUnknown: res);
155
155
} on error.PayjoinError catch (e) {
156
156
throw mapPayjoinError (e);
157
157
}
158
158
}
159
159
}
160
160
161
- class OutputsUnknown extends FfiOutputsUnknown {
162
- OutputsUnknown ._({required super .field0});
161
+ class OutputsUnknown {
162
+ final FfiOutputsUnknown _ffiOutputsUnknown;
163
+ OutputsUnknown ._({required ffiOutputsUnknown})
164
+ : _ffiOutputsUnknown = ffiOutputsUnknown;
163
165
164
166
/// Find which outputs belong to the receiver
165
- @override
166
167
Future <WantsOutputs > identifyReceiverOutputs (
167
168
{required FutureOr <bool > Function (Uint8List p1) isReceiverOutput,
168
169
hint}) async {
169
170
try {
170
- final res = await super
171
- . identifyReceiverOutputs ( isReceiverOutput: isReceiverOutput);
172
- return WantsOutputs ._(field0 : res.field0 );
171
+ final res = await _ffiOutputsUnknown. identifyReceiverOutputs (
172
+ isReceiverOutput: isReceiverOutput);
173
+ return WantsOutputs ._(ffiWantsOutputs : res);
173
174
} on error.PayjoinError catch (e) {
174
175
throw mapPayjoinError (e);
175
176
}
176
177
}
177
178
}
178
179
179
- class WantsOutputs extends FfiWantsOutputs {
180
- WantsOutputs ._({required super .field0});
180
+ class WantsOutputs {
181
+ final FfiWantsOutputs _ffiWantsOutputs;
182
+ WantsOutputs ._({required ffiWantsOutputs})
183
+ : _ffiWantsOutputs = ffiWantsOutputs;
181
184
182
- @override
183
185
Future <bool > isOutputSubstitutionDisabled ({hint}) {
184
186
try {
185
- return super .isOutputSubstitutionDisabled ();
187
+ return _ffiWantsOutputs .isOutputSubstitutionDisabled ();
186
188
} on error.PayjoinError catch (e) {
187
189
throw mapPayjoinError (e);
188
190
}
189
191
}
190
192
191
- @override
192
193
Future <WantsOutputs > replaceReceiverOutputs (
193
194
{required List <TxOut > replacementOutputs,
194
- required FfiScript drainScript}) async {
195
+ required Script drainScript}) async {
195
196
try {
196
- final res = await super .replaceReceiverOutputs (
197
+ final res = await _ffiWantsOutputs .replaceReceiverOutputs (
197
198
replacementOutputs: replacementOutputs, drainScript: drainScript);
198
- return WantsOutputs ._(field0 : res.field0 );
199
+ return WantsOutputs ._(ffiWantsOutputs : res);
199
200
} on error.PayjoinError catch (e) {
200
201
throw mapPayjoinError (e);
201
202
}
202
203
}
203
204
204
- @override
205
205
Future <WantsOutputs > substituteReceiverScript (
206
- {required FfiScript outputScript}) async {
206
+ {required Script outputScript}) async {
207
207
try {
208
- final res =
209
- await super . substituteReceiverScript ( outputScript: outputScript);
210
- return WantsOutputs ._(field0 : res.field0 );
208
+ final res = await _ffiWantsOutputs. substituteReceiverScript (
209
+ outputScript: outputScript);
210
+ return WantsOutputs ._(ffiWantsOutputs : res);
211
211
} on error.PayjoinError catch (e) {
212
212
throw mapPayjoinError (e);
213
213
}
214
214
}
215
215
216
- @override
217
216
Future <WantsInputs > commitOutputs () async {
218
217
try {
219
- final res = await super .commitOutputs ();
220
- return WantsInputs ._(field0 : res.field0 );
218
+ final res = await _ffiWantsOutputs .commitOutputs ();
219
+ return WantsInputs ._(ffiWantsInputs : res);
221
220
} on error.PayjoinError catch (e) {
222
221
throw mapPayjoinError (e);
223
222
}
224
223
}
225
224
}
226
225
227
- class WantsInputs extends FfiWantsInputs {
228
- WantsInputs ._({required super .field0});
226
+ class WantsInputs {
227
+ final FfiWantsInputs _ffiWantsInputs;
228
+ WantsInputs ._({required ffiWantsInputs}) : _ffiWantsInputs = ffiWantsInputs;
229
229
230
230
/// Select receiver input such that the payjoin avoids surveillance.
231
231
/// Return the input chosen that has been applied to the Proposal.
@@ -238,34 +238,31 @@ class WantsInputs extends FfiWantsInputs {
238
238
/// BlockSci UIH1 and UIH2:
239
239
/// if min(out) < min(in) then UIH1 else UIH2
240
240
/// https://eprint.iacr.org/2022/589.pdf
241
- @override
242
241
Future <InputPair > tryPreservingPrivacy (
243
- {required List <FfiInputPair > candidateInputs}) async {
242
+ {required List <InputPair > candidateInputs}) async {
244
243
try {
245
- final res =
246
- await super . tryPreservingPrivacy ( candidateInputs: candidateInputs);
244
+ final res = await _ffiWantsInputs. tryPreservingPrivacy (
245
+ candidateInputs: candidateInputs);
247
246
return InputPair ._(field0: res.field0);
248
247
} on error.PayjoinError catch (e) {
249
248
throw mapPayjoinError (e);
250
249
}
251
250
}
252
251
253
- @override
254
252
Future <WantsInputs > contributeInputs (
255
- {required List <FfiInputPair > replacementInputs}) async {
253
+ {required List <InputPair > replacementInputs}) async {
256
254
try {
257
- final res =
258
- await super . contributeInputs ( replacementInputs: replacementInputs);
259
- return WantsInputs ._(field0 : res.field0 );
255
+ final res = await _ffiWantsInputs. contributeInputs (
256
+ replacementInputs: replacementInputs);
257
+ return WantsInputs ._(ffiWantsInputs : res);
260
258
} on error.PayjoinError catch (e) {
261
259
throw mapPayjoinError (e);
262
260
}
263
261
}
264
262
265
- @override
266
263
Future <ProvisionalProposal > commitInputs () async {
267
264
try {
268
- final res = await super .commitInputs ();
265
+ final res = await _ffiWantsInputs .commitInputs ();
269
266
return ProvisionalProposal ._(field0: res.field0);
270
267
} on error.PayjoinError catch (e) {
271
268
throw mapPayjoinError (e);
0 commit comments