/
withdraw_controller.ts
98 lines (90 loc) · 3.28 KB
/
withdraw_controller.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { EthAddress, GrumpkinAddress } from '@aztec/barretenberg/address';
import { AssetValue } from '@aztec/barretenberg/asset';
import { TxId } from '@aztec/barretenberg/tx_id';
import { CoreSdkInterface } from '../core_sdk';
import { ProofOutput } from '../proofs';
import { Signer } from '../signer';
import { createTxRefNo } from './create_tx_ref_no';
import { FeePayer } from './fee_payer';
import { filterUndefined } from './filter_undefined';
export class WithdrawController {
private readonly requireFeePayingTx: boolean;
private proofOutput!: ProofOutput;
private feeProofOutput?: ProofOutput;
private txIds: TxId[] = [];
constructor(
public readonly userId: GrumpkinAddress,
private readonly userSigner: Signer,
public readonly assetValue: AssetValue,
public readonly fee: AssetValue,
public readonly recipient: EthAddress,
public readonly feePayer: FeePayer = { userId, signer: userSigner },
private readonly core: CoreSdkInterface,
) {
if (!assetValue.value) {
throw new Error('Value must be greater than 0.');
}
this.requireFeePayingTx =
!!fee.value &&
(fee.assetId !== assetValue.assetId ||
!feePayer.userId.equals(userId) ||
!feePayer.signer.getPublicKey().equals(userSigner.getPublicKey()));
}
public async createProof() {
const { assetId, value } = this.assetValue;
const privateInput = value + (!this.requireFeePayingTx ? this.fee.value : BigInt(0));
const txRefNo = this.requireFeePayingTx ? createTxRefNo() : 0;
const spendingPublicKey = this.userSigner.getPublicKey();
const spendingKeyRequired = !spendingPublicKey.equals(this.userId);
const proofInput = await this.core.createPaymentProofInput(
this.userId,
assetId,
BigInt(0),
value,
privateInput,
BigInt(0),
BigInt(0),
this.userId,
spendingKeyRequired,
this.recipient,
spendingPublicKey,
2,
);
proofInput.signature = await this.userSigner.signMessage(proofInput.signingData);
this.proofOutput = await this.core.createPaymentProof(proofInput, txRefNo);
if (this.requireFeePayingTx) {
const { userId, signer } = this.feePayer;
const spendingPublicKey = signer.getPublicKey();
const spendingKeyRequired = !spendingPublicKey.equals(userId);
const feeProofInput = await this.core.createPaymentProofInput(
userId,
this.fee.assetId,
BigInt(0),
BigInt(0),
this.fee.value,
BigInt(0),
BigInt(0),
userId,
spendingKeyRequired,
undefined,
spendingPublicKey,
2,
);
feeProofInput.signature = await signer.signMessage(feeProofInput.signingData);
this.feeProofOutput = await this.core.createPaymentProof(feeProofInput, txRefNo);
}
}
public async send() {
if (!this.proofOutput) {
throw new Error('Call createProof() first.');
}
this.txIds = await this.core.sendProofs(filterUndefined([this.proofOutput, this.feeProofOutput]));
return this.txIds[0];
}
public async awaitSettlement(timeout?: number) {
if (!this.txIds.length) {
throw new Error(`Call ${!this.proofOutput ? 'createProof()' : 'send()'} first.`);
}
await Promise.all(this.txIds.map(txId => this.core.awaitSettlement(txId, timeout)));
}
}