UNPKG

@logsn/arweave

Version:
194 lines (193 loc) 7.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Tag = void 0; const ArweaveUtils = require("./utils"); const deepHash_1 = require("./deepHash"); const merkle_1 = require("./merkle"); class BaseObject { get(field, options) { if (!Object.getOwnPropertyNames(this).includes(field)) { throw new Error(`Field "${field}" is not a property of the Arweave Transaction class.`); } // Handle fields that are Uint8Arrays. // To maintain compat we encode them to b64url // if decode option is not specificed. if (this[field] instanceof Uint8Array) { if (options && options.decode && options.string) { return ArweaveUtils.bufferToString(this[field]); } if (options && options.decode && !options.string) { return this[field]; } return ArweaveUtils.bufferTob64Url(this[field]); } if (this[field] instanceof Array) { if (options?.decode !== undefined || options?.string !== undefined) { if (field === "tags") { console.warn(`Did you mean to use 'transaction["tags"]' ?`); } throw new Error(`Cannot decode or stringify an array.`); } return this[field]; } if (options && options.decode == true) { if (options && options.string) { return ArweaveUtils.b64UrlToString(this[field]); } return ArweaveUtils.b64UrlToBuffer(this[field]); } return this[field]; } } class Tag extends BaseObject { name; value; constructor(name, value, decode = false) { super(); this.name = name; this.value = value; } } exports.Tag = Tag; class Transaction extends BaseObject { format = 2; id = ""; last_tx = ""; owner = ""; tags = []; target = ""; quantity = "0"; data_size = "0"; data = new Uint8Array(); data_root = ""; reward = "0"; signature = ""; // Computed when needed. chunks; constructor(attributes = {}) { super(); Object.assign(this, attributes); // If something passes in a Tx that has been toJSON'ed and back, // or where the data was filled in from /tx/data endpoint. // data will be b64url encoded, so decode it. if (typeof this.data === "string") { this.data = ArweaveUtils.b64UrlToBuffer(this.data); } if (attributes.tags) { this.tags = attributes.tags.map((tag) => { return new Tag(tag.name, tag.value); }); } } addTag(name, value) { this.tags.push(new Tag(ArweaveUtils.stringToB64Url(name), ArweaveUtils.stringToB64Url(value))); } toJSON() { return { format: this.format, id: this.id, last_tx: this.last_tx, owner: this.owner, tags: this.tags, target: this.target, quantity: this.quantity, data: ArweaveUtils.bufferTob64Url(this.data), data_size: this.data_size, data_root: this.data_root, data_tree: this.data_tree, reward: this.reward, signature: this.signature, }; } setOwner(owner) { this.owner = owner; } setSignature({ id, owner, reward, tags, signature, }) { this.id = id; this.owner = owner; if (reward) this.reward = reward; if (tags) this.tags = tags; this.signature = signature; } async prepareChunks(data) { // Note: we *do not* use `this.data`, the caller may be // operating on a transaction with an zero length data field. // This function computes the chunks for the data passed in and // assigns the result to this transaction. It should not read the // data *from* this transaction. if (!this.chunks && data.byteLength > 0) { this.chunks = await (0, merkle_1.generateTransactionChunks)(data); this.data_root = ArweaveUtils.bufferTob64Url(this.chunks.data_root); } if (!this.chunks && data.byteLength === 0) { this.chunks = { chunks: [], data_root: new Uint8Array(), proofs: [], }; this.data_root = ""; } } // Returns a chunk in a format suitable for posting to /chunk. // Similar to `prepareChunks()` this does not operate `this.data`, // instead using the data passed in. getChunk(idx, data) { if (!this.chunks) { throw new Error(`Chunks have not been prepared`); } const proof = this.chunks.proofs[idx]; const chunk = this.chunks.chunks[idx]; return { data_root: this.data_root, data_size: this.data_size, data_path: ArweaveUtils.bufferTob64Url(proof.proof), offset: proof.offset.toString(), chunk: ArweaveUtils.bufferTob64Url(data.slice(chunk.minByteRange, chunk.maxByteRange)), }; } async getSignatureData() { switch (this.format) { case 1: let tags = this.tags.reduce((accumulator, tag) => { return ArweaveUtils.concatBuffers([ accumulator, tag.get("name", { decode: true, string: false }), tag.get("value", { decode: true, string: false }), ]); }, new Uint8Array()); return ArweaveUtils.concatBuffers([ this.get("owner", { decode: true, string: false }), this.get("target", { decode: true, string: false }), this.get("data", { decode: true, string: false }), ArweaveUtils.stringToBuffer(this.quantity), ArweaveUtils.stringToBuffer(this.reward), this.get("last_tx", { decode: true, string: false }), tags, ]); case 2: if (!this.data_root) { await this.prepareChunks(this.data); } const tagList = this.tags.map((tag) => [ tag.get("name", { decode: true, string: false }), tag.get("value", { decode: true, string: false }), ]); return await (0, deepHash_1.default)([ ArweaveUtils.stringToBuffer(this.format.toString()), this.get("owner", { decode: true, string: false }), this.get("target", { decode: true, string: false }), ArweaveUtils.stringToBuffer(this.quantity), ArweaveUtils.stringToBuffer(this.reward), this.get("last_tx", { decode: true, string: false }), tagList, ArweaveUtils.stringToBuffer(this.data_size), this.get("data_root", { decode: true, string: false }), ]); default: throw new Error(`Unexpected transaction format: ${this.format}`); } } } exports.default = Transaction;