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.
Files changed (50) hide show
  1. package/README.md +4 -4
  2. package/dist/browser/algosdk.min.js +1 -1
  3. package/dist/browser/algosdk.min.js.map +1 -1
  4. package/dist/cjs/client/v2/algod/algod.js +16 -0
  5. package/dist/cjs/client/v2/algod/algod.js.map +1 -1
  6. package/dist/cjs/client/v2/algod/models/types.js +120 -1
  7. package/dist/cjs/client/v2/algod/models/types.js.map +1 -1
  8. package/dist/cjs/client/v2/algod/simulateTransaction.js +88 -0
  9. package/dist/cjs/client/v2/algod/simulateTransaction.js.map +1 -0
  10. package/dist/cjs/composer.js +69 -18
  11. package/dist/cjs/composer.js.map +1 -1
  12. package/dist/cjs/encoding/encoding.js +14 -3
  13. package/dist/cjs/encoding/encoding.js.map +1 -1
  14. package/dist/cjs/signer.js +17 -1
  15. package/dist/cjs/signer.js.map +1 -1
  16. package/dist/cjs/transaction.js +17 -1
  17. package/dist/cjs/transaction.js.map +1 -1
  18. package/dist/esm/client/v2/algod/algod.js +16 -0
  19. package/dist/esm/client/v2/algod/algod.js.map +1 -1
  20. package/dist/esm/client/v2/algod/models/types.js +116 -0
  21. package/dist/esm/client/v2/algod/models/types.js.map +1 -1
  22. package/dist/esm/client/v2/algod/simulateTransaction.js +57 -0
  23. package/dist/esm/client/v2/algod/simulateTransaction.js.map +1 -0
  24. package/dist/esm/composer.js +70 -19
  25. package/dist/esm/composer.js.map +1 -1
  26. package/dist/esm/encoding/encoding.js +12 -2
  27. package/dist/esm/encoding/encoding.js.map +1 -1
  28. package/dist/esm/signer.js +15 -0
  29. package/dist/esm/signer.js.map +1 -1
  30. package/dist/esm/transaction.js +15 -0
  31. package/dist/esm/transaction.js.map +1 -1
  32. package/dist/types/client/v2/algod/algod.d.ts +14 -0
  33. package/dist/types/client/v2/algod/models/types.d.ts +103 -0
  34. package/dist/types/client/v2/algod/simulateTransaction.d.ts +19 -0
  35. package/dist/types/composer.d.ts +28 -1
  36. package/dist/types/encoding/encoding.d.ts +7 -0
  37. package/dist/types/signer.d.ts +5 -0
  38. package/dist/types/transaction.d.ts +9 -0
  39. package/dist/types/types/transactions/builder.d.ts +1 -1
  40. package/dist/types/types/utils.d.ts +1 -1
  41. package/package.json +1 -1
  42. package/src/client/v2/algod/algod.ts +17 -0
  43. package/src/client/v2/algod/models/types.ts +222 -0
  44. package/src/client/v2/algod/simulateTransaction.ts +74 -0
  45. package/src/composer.ts +114 -31
  46. package/src/encoding/encoding.ts +13 -2
  47. package/src/signer.ts +18 -1
  48. package/src/transaction.ts +18 -0
  49. package/src/types/transactions/builder.ts +4 -4
  50. 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
- ABIValue,
4
+ abiCheckTransactionType,
8
5
  ABIMethod,
9
6
  ABIReferenceType,
10
- abiTypeIsTransaction,
11
- abiCheckTransactionType,
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
- const methodResult: ABIResult = {
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
- methodResult.rawReturnValue = new Uint8Array(lastLog.slice(4));
684
- methodResult.returnValue = method.returns.type.decode(
685
- methodResult.rawReturnValue
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
  }
@@ -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
- const options = { sortKeys: true };
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 */
@@ -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<A = {}, O = {}> = DistributiveOverwrite<
49
- TransactionBase & A,
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
@@ -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> = T extends unknown
30
+ export type DistributiveOverwrite<T, K extends Partial<T>> = T extends unknown
31
31
  ? Overwrite<T, K>
32
32
  : never;
33
33