algosdk 2.1.0 → 2.2.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/README.md +4 -4
- package/dist/browser/algosdk.min.js +1 -1
- package/dist/browser/algosdk.min.js.map +1 -1
- package/dist/cjs/client/v2/algod/algod.js +16 -0
- package/dist/cjs/client/v2/algod/algod.js.map +1 -1
- package/dist/cjs/client/v2/algod/models/types.js +120 -1
- package/dist/cjs/client/v2/algod/models/types.js.map +1 -1
- package/dist/cjs/client/v2/algod/simulateTransaction.js +88 -0
- package/dist/cjs/client/v2/algod/simulateTransaction.js.map +1 -0
- package/dist/cjs/composer.js +69 -18
- package/dist/cjs/composer.js.map +1 -1
- package/dist/cjs/encoding/encoding.js +14 -3
- package/dist/cjs/encoding/encoding.js.map +1 -1
- package/dist/cjs/signer.js +17 -1
- package/dist/cjs/signer.js.map +1 -1
- package/dist/cjs/transaction.js +17 -1
- package/dist/cjs/transaction.js.map +1 -1
- package/dist/esm/client/v2/algod/algod.js +16 -0
- package/dist/esm/client/v2/algod/algod.js.map +1 -1
- package/dist/esm/client/v2/algod/models/types.js +116 -0
- package/dist/esm/client/v2/algod/models/types.js.map +1 -1
- package/dist/esm/client/v2/algod/simulateTransaction.js +57 -0
- package/dist/esm/client/v2/algod/simulateTransaction.js.map +1 -0
- package/dist/esm/composer.js +70 -19
- package/dist/esm/composer.js.map +1 -1
- package/dist/esm/encoding/encoding.js +12 -2
- package/dist/esm/encoding/encoding.js.map +1 -1
- package/dist/esm/signer.js +15 -0
- package/dist/esm/signer.js.map +1 -1
- package/dist/esm/transaction.js +15 -0
- package/dist/esm/transaction.js.map +1 -1
- package/dist/types/client/v2/algod/algod.d.ts +14 -0
- package/dist/types/client/v2/algod/models/types.d.ts +103 -0
- package/dist/types/client/v2/algod/simulateTransaction.d.ts +19 -0
- package/dist/types/composer.d.ts +28 -1
- package/dist/types/encoding/encoding.d.ts +7 -0
- package/dist/types/signer.d.ts +5 -0
- package/dist/types/transaction.d.ts +9 -0
- package/dist/types/types/transactions/builder.d.ts +1 -1
- package/dist/types/types/utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/client/v2/algod/algod.ts +17 -0
- package/src/client/v2/algod/models/types.ts +222 -0
- package/src/client/v2/algod/simulateTransaction.ts +74 -0
- package/src/composer.ts +114 -31
- package/src/encoding/encoding.ts +13 -2
- package/src/signer.ts +18 -1
- package/src/transaction.ts +18 -0
- package/src/types/transactions/builder.ts +4 -4
- package/src/types/utils.ts +1 -1
|
@@ -3084,6 +3084,228 @@ export class PostTransactionsResponse extends BaseModel {
|
|
|
3084
3084
|
}
|
|
3085
3085
|
}
|
|
3086
3086
|
|
|
3087
|
+
/**
|
|
3088
|
+
* Result of a transaction group simulation.
|
|
3089
|
+
*/
|
|
3090
|
+
export class SimulateResponse extends BaseModel {
|
|
3091
|
+
/**
|
|
3092
|
+
* The round immediately preceding this simulation. State changes through this
|
|
3093
|
+
* round were used to run this simulation.
|
|
3094
|
+
*/
|
|
3095
|
+
public lastRound: number | bigint;
|
|
3096
|
+
|
|
3097
|
+
/**
|
|
3098
|
+
* A result object for each transaction group that was simulated.
|
|
3099
|
+
*/
|
|
3100
|
+
public txnGroups: SimulateTransactionGroupResult[];
|
|
3101
|
+
|
|
3102
|
+
/**
|
|
3103
|
+
* The version of this response object.
|
|
3104
|
+
*/
|
|
3105
|
+
public version: number | bigint;
|
|
3106
|
+
|
|
3107
|
+
/**
|
|
3108
|
+
* Indicates whether the simulated transactions would have succeeded during an
|
|
3109
|
+
* actual submission. If any transaction fails or is missing a signature, this will
|
|
3110
|
+
* be false.
|
|
3111
|
+
*/
|
|
3112
|
+
public wouldSucceed: boolean;
|
|
3113
|
+
|
|
3114
|
+
/**
|
|
3115
|
+
* Creates a new `SimulateResponse` object.
|
|
3116
|
+
* @param lastRound - The round immediately preceding this simulation. State changes through this
|
|
3117
|
+
* round were used to run this simulation.
|
|
3118
|
+
* @param txnGroups - A result object for each transaction group that was simulated.
|
|
3119
|
+
* @param version - The version of this response object.
|
|
3120
|
+
* @param wouldSucceed - Indicates whether the simulated transactions would have succeeded during an
|
|
3121
|
+
* actual submission. If any transaction fails or is missing a signature, this will
|
|
3122
|
+
* be false.
|
|
3123
|
+
*/
|
|
3124
|
+
constructor({
|
|
3125
|
+
lastRound,
|
|
3126
|
+
txnGroups,
|
|
3127
|
+
version,
|
|
3128
|
+
wouldSucceed,
|
|
3129
|
+
}: {
|
|
3130
|
+
lastRound: number | bigint;
|
|
3131
|
+
txnGroups: SimulateTransactionGroupResult[];
|
|
3132
|
+
version: number | bigint;
|
|
3133
|
+
wouldSucceed: boolean;
|
|
3134
|
+
}) {
|
|
3135
|
+
super();
|
|
3136
|
+
this.lastRound = lastRound;
|
|
3137
|
+
this.txnGroups = txnGroups;
|
|
3138
|
+
this.version = version;
|
|
3139
|
+
this.wouldSucceed = wouldSucceed;
|
|
3140
|
+
|
|
3141
|
+
this.attribute_map = {
|
|
3142
|
+
lastRound: 'last-round',
|
|
3143
|
+
txnGroups: 'txn-groups',
|
|
3144
|
+
version: 'version',
|
|
3145
|
+
wouldSucceed: 'would-succeed',
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
// eslint-disable-next-line camelcase
|
|
3150
|
+
static from_obj_for_encoding(data: Record<string, any>): SimulateResponse {
|
|
3151
|
+
/* eslint-disable dot-notation */
|
|
3152
|
+
if (typeof data['last-round'] === 'undefined')
|
|
3153
|
+
throw new Error(
|
|
3154
|
+
`Response is missing required field 'last-round': ${data}`
|
|
3155
|
+
);
|
|
3156
|
+
if (!Array.isArray(data['txn-groups']))
|
|
3157
|
+
throw new Error(
|
|
3158
|
+
`Response is missing required array field 'txn-groups': ${data}`
|
|
3159
|
+
);
|
|
3160
|
+
if (typeof data['version'] === 'undefined')
|
|
3161
|
+
throw new Error(`Response is missing required field 'version': ${data}`);
|
|
3162
|
+
if (typeof data['would-succeed'] === 'undefined')
|
|
3163
|
+
throw new Error(
|
|
3164
|
+
`Response is missing required field 'would-succeed': ${data}`
|
|
3165
|
+
);
|
|
3166
|
+
return new SimulateResponse({
|
|
3167
|
+
lastRound: data['last-round'],
|
|
3168
|
+
txnGroups: data['txn-groups'].map(
|
|
3169
|
+
SimulateTransactionGroupResult.from_obj_for_encoding
|
|
3170
|
+
),
|
|
3171
|
+
version: data['version'],
|
|
3172
|
+
wouldSucceed: data['would-succeed'],
|
|
3173
|
+
});
|
|
3174
|
+
/* eslint-enable dot-notation */
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
/**
|
|
3179
|
+
* Simulation result for an atomic transaction group
|
|
3180
|
+
*/
|
|
3181
|
+
export class SimulateTransactionGroupResult extends BaseModel {
|
|
3182
|
+
/**
|
|
3183
|
+
* Simulation result for individual transactions
|
|
3184
|
+
*/
|
|
3185
|
+
public txnResults: SimulateTransactionResult[];
|
|
3186
|
+
|
|
3187
|
+
/**
|
|
3188
|
+
* If present, indicates which transaction in this group caused the failure. This
|
|
3189
|
+
* array represents the path to the failing transaction. Indexes are zero based,
|
|
3190
|
+
* the first element indicates the top-level transaction, and successive elements
|
|
3191
|
+
* indicate deeper inner transactions.
|
|
3192
|
+
*/
|
|
3193
|
+
public failedAt?: (number | bigint)[];
|
|
3194
|
+
|
|
3195
|
+
/**
|
|
3196
|
+
* If present, indicates that the transaction group failed and specifies why that
|
|
3197
|
+
* happened
|
|
3198
|
+
*/
|
|
3199
|
+
public failureMessage?: string;
|
|
3200
|
+
|
|
3201
|
+
/**
|
|
3202
|
+
* Creates a new `SimulateTransactionGroupResult` object.
|
|
3203
|
+
* @param txnResults - Simulation result for individual transactions
|
|
3204
|
+
* @param failedAt - If present, indicates which transaction in this group caused the failure. This
|
|
3205
|
+
* array represents the path to the failing transaction. Indexes are zero based,
|
|
3206
|
+
* the first element indicates the top-level transaction, and successive elements
|
|
3207
|
+
* indicate deeper inner transactions.
|
|
3208
|
+
* @param failureMessage - If present, indicates that the transaction group failed and specifies why that
|
|
3209
|
+
* happened
|
|
3210
|
+
*/
|
|
3211
|
+
constructor({
|
|
3212
|
+
txnResults,
|
|
3213
|
+
failedAt,
|
|
3214
|
+
failureMessage,
|
|
3215
|
+
}: {
|
|
3216
|
+
txnResults: SimulateTransactionResult[];
|
|
3217
|
+
failedAt?: (number | bigint)[];
|
|
3218
|
+
failureMessage?: string;
|
|
3219
|
+
}) {
|
|
3220
|
+
super();
|
|
3221
|
+
this.txnResults = txnResults;
|
|
3222
|
+
this.failedAt = failedAt;
|
|
3223
|
+
this.failureMessage = failureMessage;
|
|
3224
|
+
|
|
3225
|
+
this.attribute_map = {
|
|
3226
|
+
txnResults: 'txn-results',
|
|
3227
|
+
failedAt: 'failed-at',
|
|
3228
|
+
failureMessage: 'failure-message',
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
// eslint-disable-next-line camelcase
|
|
3233
|
+
static from_obj_for_encoding(
|
|
3234
|
+
data: Record<string, any>
|
|
3235
|
+
): SimulateTransactionGroupResult {
|
|
3236
|
+
/* eslint-disable dot-notation */
|
|
3237
|
+
if (!Array.isArray(data['txn-results']))
|
|
3238
|
+
throw new Error(
|
|
3239
|
+
`Response is missing required array field 'txn-results': ${data}`
|
|
3240
|
+
);
|
|
3241
|
+
return new SimulateTransactionGroupResult({
|
|
3242
|
+
txnResults: data['txn-results'].map(
|
|
3243
|
+
SimulateTransactionResult.from_obj_for_encoding
|
|
3244
|
+
),
|
|
3245
|
+
failedAt: data['failed-at'],
|
|
3246
|
+
failureMessage: data['failure-message'],
|
|
3247
|
+
});
|
|
3248
|
+
/* eslint-enable dot-notation */
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3252
|
+
/**
|
|
3253
|
+
* Simulation result for an individual transaction
|
|
3254
|
+
*/
|
|
3255
|
+
export class SimulateTransactionResult extends BaseModel {
|
|
3256
|
+
/**
|
|
3257
|
+
* Details about a pending transaction. If the transaction was recently confirmed,
|
|
3258
|
+
* includes confirmation details like the round and reward details.
|
|
3259
|
+
*/
|
|
3260
|
+
public txnResult: PendingTransactionResponse;
|
|
3261
|
+
|
|
3262
|
+
/**
|
|
3263
|
+
* A boolean indicating whether this transaction is missing signatures
|
|
3264
|
+
*/
|
|
3265
|
+
public missingSignature?: boolean;
|
|
3266
|
+
|
|
3267
|
+
/**
|
|
3268
|
+
* Creates a new `SimulateTransactionResult` object.
|
|
3269
|
+
* @param txnResult - Details about a pending transaction. If the transaction was recently confirmed,
|
|
3270
|
+
* includes confirmation details like the round and reward details.
|
|
3271
|
+
* @param missingSignature - A boolean indicating whether this transaction is missing signatures
|
|
3272
|
+
*/
|
|
3273
|
+
constructor({
|
|
3274
|
+
txnResult,
|
|
3275
|
+
missingSignature,
|
|
3276
|
+
}: {
|
|
3277
|
+
txnResult: PendingTransactionResponse;
|
|
3278
|
+
missingSignature?: boolean;
|
|
3279
|
+
}) {
|
|
3280
|
+
super();
|
|
3281
|
+
this.txnResult = txnResult;
|
|
3282
|
+
this.missingSignature = missingSignature;
|
|
3283
|
+
|
|
3284
|
+
this.attribute_map = {
|
|
3285
|
+
txnResult: 'txn-result',
|
|
3286
|
+
missingSignature: 'missing-signature',
|
|
3287
|
+
};
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
// eslint-disable-next-line camelcase
|
|
3291
|
+
static from_obj_for_encoding(
|
|
3292
|
+
data: Record<string, any>
|
|
3293
|
+
): SimulateTransactionResult {
|
|
3294
|
+
/* eslint-disable dot-notation */
|
|
3295
|
+
if (typeof data['txn-result'] === 'undefined')
|
|
3296
|
+
throw new Error(
|
|
3297
|
+
`Response is missing required field 'txn-result': ${data}`
|
|
3298
|
+
);
|
|
3299
|
+
return new SimulateTransactionResult({
|
|
3300
|
+
txnResult: PendingTransactionResponse.from_obj_for_encoding(
|
|
3301
|
+
data['txn-result']
|
|
3302
|
+
),
|
|
3303
|
+
missingSignature: data['missing-signature'],
|
|
3304
|
+
});
|
|
3305
|
+
/* eslint-enable dot-notation */
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3087
3309
|
/**
|
|
3088
3310
|
* Represents a state proof and its corresponding message
|
|
3089
3311
|
*/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import * as encoding from '../../../encoding/encoding';
|
|
3
|
+
import { concatArrays } from '../../../utils/utils';
|
|
4
|
+
import HTTPClient from '../../client';
|
|
5
|
+
import JSONRequest from '../jsonrequest';
|
|
6
|
+
import { SimulateResponse } from './models/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sets the default header (if not previously set) for simulating a raw
|
|
10
|
+
* transaction.
|
|
11
|
+
* @param headers - A headers object
|
|
12
|
+
*/
|
|
13
|
+
export function setSimulateTransactionsHeaders(headers = {}) {
|
|
14
|
+
let hdrs = headers;
|
|
15
|
+
if (Object.keys(hdrs).every((key) => key.toLowerCase() !== 'content-type')) {
|
|
16
|
+
hdrs = { ...headers };
|
|
17
|
+
hdrs['Content-Type'] = 'application/x-binary';
|
|
18
|
+
}
|
|
19
|
+
return hdrs;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isByteArray(array: any): array is Uint8Array {
|
|
23
|
+
return array && array.byteLength !== undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Simulates signed txns.
|
|
28
|
+
*/
|
|
29
|
+
export default class SimulateRawTransactions extends JSONRequest<
|
|
30
|
+
SimulateResponse,
|
|
31
|
+
Uint8Array
|
|
32
|
+
> {
|
|
33
|
+
private txnBytesToPost: Uint8Array;
|
|
34
|
+
|
|
35
|
+
constructor(c: HTTPClient, stxOrStxs: Uint8Array | Uint8Array[]) {
|
|
36
|
+
super(c);
|
|
37
|
+
this.query.format = 'msgpack';
|
|
38
|
+
|
|
39
|
+
let forPosting = stxOrStxs;
|
|
40
|
+
if (Array.isArray(stxOrStxs)) {
|
|
41
|
+
if (!stxOrStxs.every(isByteArray)) {
|
|
42
|
+
throw new TypeError('Array elements must be byte arrays');
|
|
43
|
+
}
|
|
44
|
+
// Flatten into a single Uint8Array
|
|
45
|
+
forPosting = concatArrays(...stxOrStxs);
|
|
46
|
+
} else if (!isByteArray(forPosting)) {
|
|
47
|
+
throw new TypeError('Argument must be byte array');
|
|
48
|
+
}
|
|
49
|
+
this.txnBytesToPost = forPosting;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// eslint-disable-next-line class-methods-use-this
|
|
53
|
+
path() {
|
|
54
|
+
return '/v2/transactions/simulate';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async do(headers = {}) {
|
|
58
|
+
const txHeaders = setSimulateTransactionsHeaders(headers);
|
|
59
|
+
const res = await this.c.post(
|
|
60
|
+
this.path(),
|
|
61
|
+
Buffer.from(this.txnBytesToPost),
|
|
62
|
+
txHeaders,
|
|
63
|
+
this.query,
|
|
64
|
+
false
|
|
65
|
+
);
|
|
66
|
+
return this.prepare(res.body);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// eslint-disable-next-line class-methods-use-this
|
|
70
|
+
prepare(body: Uint8Array): SimulateResponse {
|
|
71
|
+
const decoded = encoding.decode(body);
|
|
72
|
+
return SimulateResponse.from_obj_for_encoding(decoded);
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/composer.ts
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import {
|
|
3
|
-
ABIType,
|
|
4
|
-
ABITupleType,
|
|
5
|
-
ABIUintType,
|
|
6
3
|
ABIAddressType,
|
|
7
|
-
|
|
4
|
+
abiCheckTransactionType,
|
|
8
5
|
ABIMethod,
|
|
9
6
|
ABIReferenceType,
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
ABITupleType,
|
|
8
|
+
ABIType,
|
|
12
9
|
abiTypeIsReference,
|
|
10
|
+
abiTypeIsTransaction,
|
|
11
|
+
ABIUintType,
|
|
12
|
+
ABIValue,
|
|
13
13
|
} from './abi';
|
|
14
|
-
import { Transaction, decodeSignedTransaction } from './transaction';
|
|
15
|
-
import { makeApplicationCallTxnFromObject } from './makeTxn';
|
|
16
|
-
import { assignGroupID } from './group';
|
|
17
|
-
import { waitForConfirmation } from './wait';
|
|
18
14
|
import Algodv2 from './client/v2/algod/algod';
|
|
15
|
+
import { SimulateResponse } from './client/v2/algod/models/types';
|
|
16
|
+
import { assignGroupID } from './group';
|
|
17
|
+
import { makeApplicationCallTxnFromObject } from './makeTxn';
|
|
19
18
|
import {
|
|
19
|
+
isTransactionWithSigner,
|
|
20
20
|
TransactionSigner,
|
|
21
21
|
TransactionWithSigner,
|
|
22
|
-
isTransactionWithSigner,
|
|
23
22
|
} from './signer';
|
|
23
|
+
import { decodeSignedTransaction, Transaction } from './transaction';
|
|
24
24
|
import {
|
|
25
25
|
BoxReference,
|
|
26
26
|
OnApplicationComplete,
|
|
27
27
|
SuggestedParams,
|
|
28
28
|
} from './types/transactions/base';
|
|
29
|
+
import { waitForConfirmation } from './wait';
|
|
29
30
|
|
|
30
31
|
// First 4 bytes of SHA-512/256 hash of "return"
|
|
31
32
|
const RETURN_PREFIX = Buffer.from([21, 31, 124, 117]);
|
|
@@ -600,6 +601,60 @@ export class AtomicTransactionComposer {
|
|
|
600
601
|
return this.txIDs;
|
|
601
602
|
}
|
|
602
603
|
|
|
604
|
+
/**
|
|
605
|
+
* Simulates the transaction group in the network.
|
|
606
|
+
*
|
|
607
|
+
* The composer will try to sign any transactions in the group, then simulate
|
|
608
|
+
* the results.
|
|
609
|
+
* Simulating the group will not change the composer's status.
|
|
610
|
+
*
|
|
611
|
+
* @param client - An Algodv2 client
|
|
612
|
+
*
|
|
613
|
+
* @returns A promise that, upon success, resolves to an object containing an
|
|
614
|
+
* array of results containing one element for each method call transaction
|
|
615
|
+
* in this group (ABIResult[]) and the SimulateResponse object.
|
|
616
|
+
*/
|
|
617
|
+
async simulate(
|
|
618
|
+
client: Algodv2
|
|
619
|
+
): Promise<{
|
|
620
|
+
methodResults: ABIResult[];
|
|
621
|
+
simulateResponse: SimulateResponse;
|
|
622
|
+
}> {
|
|
623
|
+
if (this.status > AtomicTransactionComposerStatus.SUBMITTED) {
|
|
624
|
+
throw new Error(
|
|
625
|
+
'Simulated Transaction group has already been submitted to the network'
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
const stxns = await this.gatherSignatures();
|
|
630
|
+
|
|
631
|
+
const simulateResponse = await client.simulateRawTransactions(stxns).do();
|
|
632
|
+
|
|
633
|
+
// Parse method response
|
|
634
|
+
const methodResults: ABIResult[] = [];
|
|
635
|
+
for (const [txnIndex, method] of this.methodCalls) {
|
|
636
|
+
const txID = this.txIDs[txnIndex];
|
|
637
|
+
const pendingInfo =
|
|
638
|
+
simulateResponse.txnGroups[0].txnResults[txnIndex].txnResult;
|
|
639
|
+
|
|
640
|
+
const methodResult: ABIResult = {
|
|
641
|
+
txID,
|
|
642
|
+
rawReturnValue: new Uint8Array(),
|
|
643
|
+
method,
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
methodResults.push(
|
|
647
|
+
AtomicTransactionComposer.parseMethodResponse(
|
|
648
|
+
method,
|
|
649
|
+
methodResult,
|
|
650
|
+
pendingInfo.get_obj_for_encoding()
|
|
651
|
+
)
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return { methodResults, simulateResponse };
|
|
656
|
+
}
|
|
657
|
+
|
|
603
658
|
/**
|
|
604
659
|
* Send the transaction group to the network and wait until it's committed to a block. An error
|
|
605
660
|
* will be thrown if submission or execution fails.
|
|
@@ -653,7 +708,7 @@ export class AtomicTransactionComposer {
|
|
|
653
708
|
for (const [txnIndex, method] of this.methodCalls) {
|
|
654
709
|
const txID = txIDs[txnIndex];
|
|
655
710
|
|
|
656
|
-
|
|
711
|
+
let methodResult: ABIResult = {
|
|
657
712
|
txID,
|
|
658
713
|
rawReturnValue: new Uint8Array(),
|
|
659
714
|
method,
|
|
@@ -665,26 +720,12 @@ export class AtomicTransactionComposer {
|
|
|
665
720
|
? confirmedTxnInfo
|
|
666
721
|
: // eslint-disable-next-line no-await-in-loop
|
|
667
722
|
await client.pendingTransactionInformation(txID).do();
|
|
668
|
-
methodResult.txInfo = pendingInfo;
|
|
669
|
-
if (method.returns.type !== 'void') {
|
|
670
|
-
const logs: string[] = pendingInfo.logs || [];
|
|
671
|
-
if (logs.length === 0) {
|
|
672
|
-
throw new Error('App call transaction did not log a return value');
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
const lastLog = Buffer.from(logs[logs.length - 1], 'base64');
|
|
676
|
-
if (
|
|
677
|
-
lastLog.byteLength < 4 ||
|
|
678
|
-
!lastLog.slice(0, 4).equals(RETURN_PREFIX)
|
|
679
|
-
) {
|
|
680
|
-
throw new Error('App call transaction did not log a return value');
|
|
681
|
-
}
|
|
682
723
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
724
|
+
methodResult = AtomicTransactionComposer.parseMethodResponse(
|
|
725
|
+
method,
|
|
726
|
+
methodResult,
|
|
727
|
+
pendingInfo
|
|
728
|
+
);
|
|
688
729
|
} catch (err) {
|
|
689
730
|
methodResult.decodeError = err;
|
|
690
731
|
}
|
|
@@ -698,4 +739,46 @@ export class AtomicTransactionComposer {
|
|
|
698
739
|
methodResults,
|
|
699
740
|
};
|
|
700
741
|
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Parses a single ABI Method transaction log into a ABI result object.
|
|
745
|
+
*
|
|
746
|
+
* @param method
|
|
747
|
+
* @param methodResult
|
|
748
|
+
* @param pendingInfo
|
|
749
|
+
* @returns An ABIResult object
|
|
750
|
+
*/
|
|
751
|
+
static parseMethodResponse(
|
|
752
|
+
method: ABIMethod,
|
|
753
|
+
methodResult: ABIResult,
|
|
754
|
+
pendingInfo: Record<string, any>
|
|
755
|
+
): ABIResult {
|
|
756
|
+
const returnedResult: ABIResult = methodResult;
|
|
757
|
+
try {
|
|
758
|
+
returnedResult.txInfo = pendingInfo;
|
|
759
|
+
if (method.returns.type !== 'void') {
|
|
760
|
+
const logs: string[] = pendingInfo.logs || [];
|
|
761
|
+
if (logs.length === 0) {
|
|
762
|
+
throw new Error('App call transaction did not log a return value');
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const lastLog = Buffer.from(logs[logs.length - 1], 'base64');
|
|
766
|
+
if (
|
|
767
|
+
lastLog.byteLength < 4 ||
|
|
768
|
+
!lastLog.slice(0, 4).equals(RETURN_PREFIX)
|
|
769
|
+
) {
|
|
770
|
+
throw new Error('App call transaction did not log a return value');
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
returnedResult.rawReturnValue = new Uint8Array(lastLog.slice(4));
|
|
774
|
+
returnedResult.returnValue = method.returns.type.decode(
|
|
775
|
+
methodResult.rawReturnValue
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
} catch (err) {
|
|
779
|
+
returnedResult.decodeError = err;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return returnedResult;
|
|
783
|
+
}
|
|
701
784
|
}
|
package/src/encoding/encoding.ts
CHANGED
|
@@ -33,6 +33,18 @@ function containsEmpty(obj: Record<string | number | symbol, any>) {
|
|
|
33
33
|
return { containsEmpty: false, firstEmptyKey: undefined };
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* rawEncode encodes objects using msgpack, regardless of whether there are
|
|
38
|
+
* empty or 0 value fields.
|
|
39
|
+
* @param obj - a dictionary to be encoded. May or may not contain empty or 0 values.
|
|
40
|
+
* @returns msgpack representation of the object
|
|
41
|
+
*/
|
|
42
|
+
export function rawEncode(obj: Record<string | number | symbol, any>) {
|
|
43
|
+
// enable the canonical option
|
|
44
|
+
const options = { sortKeys: true };
|
|
45
|
+
return msgpack.encode(obj, options);
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
/**
|
|
37
49
|
* encode encodes objects using msgpack
|
|
38
50
|
* @param obj - a dictionary to be encoded. Must not contain empty or 0 values.
|
|
@@ -47,8 +59,7 @@ export function encode(obj: Record<string | number | symbol, any>) {
|
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
// enable the canonical option
|
|
50
|
-
|
|
51
|
-
return msgpack.encode(obj, options);
|
|
62
|
+
return rawEncode(obj);
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
export function decode(buffer: ArrayLike<number>) {
|
package/src/signer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Transaction } from './transaction';
|
|
1
|
+
import { encodeUnsignedSimulateTransaction, Transaction } from './transaction';
|
|
2
2
|
import Account from './types/account';
|
|
3
3
|
import { LogicSigAccount, signLogicSigTransactionObject } from './logicsig';
|
|
4
4
|
import { MultisigMetadata } from './types/multisig';
|
|
@@ -80,6 +80,23 @@ export function makeMultiSigAccountTransactionSigner(
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Create a makeEmptyTransactionSigner that does not specify any signer or
|
|
85
|
+
* signing capabilities. This should only be used to simulate transactions.
|
|
86
|
+
*/
|
|
87
|
+
export function makeEmptyTransactionSigner(): TransactionSigner {
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
89
|
+
return (txnGroup: Transaction[], indexesToSign: number[]) => {
|
|
90
|
+
const unsigned: Uint8Array[] = [];
|
|
91
|
+
|
|
92
|
+
for (const index of indexesToSign) {
|
|
93
|
+
unsigned.push(encodeUnsignedSimulateTransaction(txnGroup[index]));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Promise.resolve(unsigned);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
/** Represents an unsigned transactions and a signer that can authorize that transaction. */
|
|
84
101
|
export interface TransactionWithSigner {
|
|
85
102
|
/** An unsigned transaction */
|
package/src/transaction.ts
CHANGED
|
@@ -1278,6 +1278,24 @@ export class Transaction implements TransactionStorageStructure {
|
|
|
1278
1278
|
}
|
|
1279
1279
|
}
|
|
1280
1280
|
|
|
1281
|
+
/**
|
|
1282
|
+
* encodeUnsignedSimulateTransaction takes a txnBuilder.Transaction object,
|
|
1283
|
+
* converts it into a SignedTransaction-like object, and converts it to a Buffer.
|
|
1284
|
+
*
|
|
1285
|
+
* Note: this function should only be used to simulate unsigned transactions.
|
|
1286
|
+
*
|
|
1287
|
+
* @param transactionObject - Transaction object to simulate.
|
|
1288
|
+
*/
|
|
1289
|
+
export function encodeUnsignedSimulateTransaction(
|
|
1290
|
+
transactionObject: Transaction
|
|
1291
|
+
) {
|
|
1292
|
+
const objToEncode: EncodedSignedTransaction = {
|
|
1293
|
+
sig: null,
|
|
1294
|
+
txn: transactionObject.get_obj_for_encoding(),
|
|
1295
|
+
};
|
|
1296
|
+
return encoding.rawEncode(objToEncode);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1281
1299
|
/**
|
|
1282
1300
|
* encodeUnsignedTransaction takes a completed txnBuilder.Transaction object, such as from the makeFoo
|
|
1283
1301
|
* family of transactions, and converts it to a Buffer
|
|
@@ -45,10 +45,10 @@ export type TransactionBase =
|
|
|
45
45
|
* - A: Additional parameters on top of the base transaction parameters
|
|
46
46
|
* - O: A set of overwrites for transaction parameters
|
|
47
47
|
*/
|
|
48
|
-
export type ConstructTransaction<
|
|
49
|
-
|
|
50
|
-
O
|
|
51
|
-
>;
|
|
48
|
+
export type ConstructTransaction<
|
|
49
|
+
A = {},
|
|
50
|
+
O extends Partial<TransactionBase & A> = {}
|
|
51
|
+
> = DistributiveOverwrite<TransactionBase & A, O>;
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
* Only accept transaction objects that include suggestedParams as an object
|
package/src/types/utils.ts
CHANGED
|
@@ -27,7 +27,7 @@ export type Overwrite<T, U extends Partial<T>> = Pick<
|
|
|
27
27
|
/**
|
|
28
28
|
* Same as Overwrite, but will distribute the Overwrite over unions
|
|
29
29
|
*/
|
|
30
|
-
export type DistributiveOverwrite<T, K
|
|
30
|
+
export type DistributiveOverwrite<T, K extends Partial<T>> = T extends unknown
|
|
31
31
|
? Overwrite<T, K>
|
|
32
32
|
: never;
|
|
33
33
|
|