-
Notifications
You must be signed in to change notification settings - Fork 307
Expand file tree
/
Copy pathresourceManagementTxBuilder.ts
More file actions
185 lines (156 loc) · 5.46 KB
/
Copy pathresourceManagementTxBuilder.ts
File metadata and controls
185 lines (156 loc) · 5.46 KB
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import { BaseKey, ExtendTransactionError, BuildTransactionError, SigningError } from '@bitgo/sdk-core';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import BigNumber from 'bignumber.js';
import { TransactionBuilder } from './transactionBuilder';
import { Transaction } from './transaction';
import { ResourceManagementContract } from './iface';
import { Address } from './address';
import { getBase58AddressFromHex, TRANSACTION_MAX_EXPIRATION, getHexAddressFromBase58Address } from './utils';
/**
* Abstract base class for resource management transaction builders (delegate/undelegate)
*/
export abstract class ResourceManagementTxBuilder extends TransactionBuilder {
protected _signingKeys: BaseKey[];
protected _balance: string;
protected _resource: string;
protected _receiverAddress: string;
constructor(_coinConfig: Readonly<CoinConfig>) {
super(_coinConfig);
this._signingKeys = [];
this.transaction = new Transaction(_coinConfig);
}
/**
* Set the balance amount
*
* @param amount amount in TRX to delegate/undelegate
* @returns the builder with the new parameter set
*/
setBalance(amount: string): this {
this.validateValue(new BigNumber(amount));
this._balance = amount;
return this;
}
/**
* Set the receiver address
*
* @param address receiver address for the delegate/undelegate operation
* @returns the builder with the new parameter set
*/
setReceiverAddress(address: Address): this {
this.validateAddress(address);
this._receiverAddress = getHexAddressFromBase58Address(address.address);
return this;
}
/**
* Set the resource type
*
* @param resource resource type to delegate/undelegate
* @returns the builder with the new parameter set
*/
setResource(resource: string): this {
this.validateResource(resource);
this._resource = resource;
return this;
}
/** @inheritdoc */
extendValidTo(extensionMs: number): void {
if (this.transaction.signature && this.transaction.signature.length > 0) {
throw new ExtendTransactionError('Cannot extend a signed transaction');
}
if (extensionMs <= 0) {
throw new Error('Value cannot be below zero');
}
if (extensionMs > TRANSACTION_MAX_EXPIRATION) {
throw new ExtendTransactionError('The expiration cannot be extended more than one day');
}
if (this._expiration) {
this._expiration = this._expiration + extensionMs;
} else {
throw new Error('There is not expiration to extend');
}
}
/**
* Validates the transaction
*
* @param {Transaction} transaction - The transaction to validate
* @throws {void}
*/
validateTransaction(transaction: Transaction): void {
this.validateResourceManagementTransactionFields();
}
/** @inheritdoc */
protected async buildImplementation(): Promise<Transaction> {
this.createResourceManagementTransaction();
if (this._signingKeys.length > 0) {
this.applySignatures();
}
if (!this.transaction.id) {
throw new BuildTransactionError('A valid transaction must have an id');
}
return Promise.resolve(this.transaction);
}
/** @inheritdoc */
protected signImplementation(key: BaseKey): Transaction {
if (this._signingKeys.some((signingKey) => signingKey.key === key.key)) {
throw new SigningError('Duplicated key');
}
this._signingKeys.push(key);
return this.transaction;
}
protected applySignatures(): void {
if (!this.transaction.inputs) {
throw new SigningError('Transaction has no inputs');
}
this._signingKeys.forEach((key) => this.applySignature(key));
}
/**
* Validates if the transaction is a valid delegate/undelegate transaction
*
* @throws {BuildTransactionError} when the transaction is invalid
*/
protected validateResourceManagementTransactionFields(): void {
if (!this._balance) {
throw new BuildTransactionError('Missing parameter: balance');
}
if (!this._ownerAddress) {
throw new BuildTransactionError('Missing parameter: source');
}
if (!this._resource) {
throw new BuildTransactionError('Missing parameter: resource');
}
if (!this._receiverAddress) {
throw new BuildTransactionError('Missing parameter: receiver address');
}
if (!this._refBlockBytes || !this._refBlockHash) {
throw new BuildTransactionError('Missing block reference information');
}
}
/**
* Initialize the delegate/undelegate contract call specific data
*
* @param {ResourceManagementContract} resourceManagementContractCall object with delegate txn data
*/
protected initResourceManagementContractCall(resourceManagementContractCall: ResourceManagementContract): void {
const { resource, owner_address, balance, receiver_address } = resourceManagementContractCall.parameter.value;
if (owner_address) {
this.source({ address: getBase58AddressFromHex(owner_address) });
}
if (resource) {
this.setResource(resource);
}
if (balance !== undefined) {
this.setBalance(balance.toString());
}
if (receiver_address) {
this.setReceiverAddress({ address: getBase58AddressFromHex(receiver_address) });
}
}
/**
* Helper method to create the delegate/undelegate resource transaction
*/
protected abstract createResourceManagementTransaction(): void;
/**
* Helper method to get the resource delegate/undelegate transaction raw data hex
*/
protected abstract getResourceManagementTxRawDataHex(): string;
}