diff --git a/src/sorobandata_builder.js b/src/sorobandata_builder.js index 8beea47b..e4e0d6da 100644 --- a/src/sorobandata_builder.js +++ b/src/sorobandata_builder.js @@ -35,10 +35,8 @@ export class SorobanDataBuilder { constructor(sorobanData) { let data; - if (typeof sorobanData === 'string') { - data = SorobanDataBuilder.fromXDR(sorobanData, 'base64'); - } else if (ArrayBuffer.isView(sorobanData)) { - data = SorobanDataBuilder.fromXDR(sorobanData, 'raw'); + if (typeof sorobanData === 'string' || ArrayBuffer.isView(sorobanData)) { + data = SorobanDataBuilder.fromXDR(sorobanData); } else if (!sorobanData) { data = new xdr.SorobanTransactionData({ resources: new xdr.SorobanResources({ @@ -102,22 +100,37 @@ export class SorobanDataBuilder { return this; } + /** + * Appends the given ledger keys to the existing storage access footprint. + * @param {xdr.LedgerKey[]} readOnly read-only keys to add + * @param {xdr.LedgerKey[]} readWrite read-write keys to add + * @returns {SorobanDataBuilder} this builder instance + */ + appendFootprint(readOnly, readWrite) { + return this.setFootprint( + this.getReadOnly().concat(readOnly), + this.getReadWrite().concat(readWrite) + ); + } + /** * Sets the storage access footprint to be a certain set of ledger keys. * * You can also set each field explicitly via * {@link SorobanDataBuilder.setReadOnly} and - * {@link SorobanDataBuilder.setReadWrite}. + * {@link SorobanDataBuilder.setReadWrite} or add to the existing footprint + * via {@link SorobanDataBuilder.appendFootprint}. * * Passing `null|undefined` to either parameter will IGNORE the existing * values. If you want to clear them, pass `[]`, instead. * * @param {xdr.LedgerKey[]|null} [readOnly] the set of ledger keys to set in - * the read-only portion of the transaction's `sorobanData` + * the read-only portion of the transaction's `sorobanData`, or `null | + * undefined` to keep the existing keys * @param {xdr.LedgerKey[]|null} [readWrite] the set of ledger keys to set in - * the read-write portion of the transaction's `sorobanData` - * - * @returns {SorobanDataBuilder} + * the read-write portion of the transaction's `sorobanData`, or `null | + * undefined` to keep the existing keys + * @returns {SorobanDataBuilder} this builder instance */ setFootprint(readOnly, readWrite) { if (readOnly !== null) { @@ -160,4 +173,18 @@ export class SorobanDataBuilder { build() { return xdr.SorobanTransactionData.fromXDR(this._data.toXDR()); // clone } + + // + // getters follow + // + + /** @returns {xdr.LedgerKey[]} the read-only storage access pattern */ + getReadOnly() { + return this._data.resources().footprint().readOnly(); + } + + /** @returns {xdr.LedgerKey[]} the read-write storage access pattern */ + getReadWrite() { + return this._data.resources().footprint().readWrite(); + } } diff --git a/test/unit/sorobandata_builder_test.js b/test/unit/sorobandata_builder_test.js index cae369ef..623087c5 100644 --- a/test/unit/sorobandata_builder_test.js +++ b/test/unit/sorobandata_builder_test.js @@ -59,6 +59,20 @@ describe('SorobanTransactionData can be built', function () { expect(data2.resources().footprint().readWrite()).to.eql([]); }); + it('appends footprints', function () { + const builder = new dataBuilder(); + + const data = builder + .setFootprint([key], [key]) + .appendFootprint([key, key], []); + const built = data.build(); + + expect(data.getReadOnly()).to.eql([key, key, key]); + expect(data.getReadWrite()).to.eql([key]); + expect(built.resources().footprint().readOnly()).to.eql([key, key, key]); + expect(built.resources().footprint().readWrite()).to.eql([key]); + }); + it('makes copies on build()', function () { const builder = new dataBuilder(); const first = builder.build(); diff --git a/types/index.d.ts b/types/index.d.ts index 8bb10139..7287d6d7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1139,7 +1139,8 @@ export function humanizeEvents( ): SorobanEvent[]; export class SorobanDataBuilder { - constructor(data?: string | xdr.SorobanTransactionData); + constructor(data?: string | Uint8Array | Buffer | xdr.SorobanTransactionData); + static fromXDR(data: Uint8Array | Buffer | string): SorobanDataBuilder; setRefundableFee(fee: IntLike): SorobanDataBuilder; setResources( @@ -1153,9 +1154,16 @@ export class SorobanDataBuilder { readOnly?: xdr.LedgerKey[] | null, readWrite?: xdr.LedgerKey[] | null ): SorobanDataBuilder; + appendFootprint( + readOnly: xdr.LedgerKey[], + readWrite: xdr.LedgerKey[] + ): SorobanDataBuilder; + + setReadOnly(keys: xdr.LedgerKey[]): SorobanDataBuilder; + setReadWrite(keys: xdr.LedgerKey[]): SorobanDataBuilder; - setReadOnly(keys?: xdr.LedgerKey[]): SorobanDataBuilder; - setReadWrite(keys?: xdr.LedgerKey[]): SorobanDataBuilder; + getReadOnly(): xdr.LedgerKey[]; + getReadWrite(): xdr.LedgerKey[]; build(): xdr.SorobanTransactionData; }