}
/**
- * Set the subtype and link to configure this as a change representative block.
+ * Set the subtype, link, and target account to configure this as a change
+ * representative block.
*
- * @returns {Block} This block so that additional calls can be chained
+ * @param {(string|Account)} account - Account to choose as representative, or its address or public key
+ * @returns {Block} This block with link, representative, and subtype configured
*/
- change (): Block {
- if (this.subtype != null) {
- throw new Error(`Block is already configured as ${this.subtype}`)
- }
+ change (representative: string | Account): Block
+ change (representative: unknown): Block {
+ const { link, representative: rep, subtype } = this
try {
+ if (this.subtype != null) {
+ throw new Error(`Block already configured as ${this.subtype}`)
+ }
this.subtype = 'change'
+
+ if (typeof representative !== 'string' && !(representative instanceof Account)) {
+ throw new TypeError('Invalid account')
+ }
+ this.representative = (typeof representative === 'string')
+ ? Account.import(representative)
+ : representative
+
this.link = hex.toBytes(BURN_PUBLIC_KEY)
return this
} catch (err) {
- this.subtype = undefined
- this.link = undefined
+ this.link = link
+ this.representative = rep
+ this.subtype = subtype
throw new TypeError('Failed to configure send block', { cause: err })
}
}
- /**
- * Set a block hash as the source send of a receive block.
- *
- * @param {string} hash - Hash of send block to be received
- * @returns {Block} This block so that additional calls can be chained
- */
- from (hash: string): Block
- /**
- * Set a send block as the source of a receive block.
- *
- * @param {Block} block - Send block to be received
- * @returns {Block} This block so that additional calls can be chained
- */
- from (block: Block): Block
- from (send: unknown): Block {
- try {
- if (typeof send !== 'string' && !(send instanceof Block)) {
- throw new TypeError('Invalid send to be received')
- }
- if (this.subtype !== 'receive') {
- throw new TypeError('Invalid subtype')
- }
- this.link = (typeof send === 'string')
- ? hex.toBytes(send)
- : send.hash
- return this
- } catch (err) {
- throw new Error('Failed to receive a corresponding send', { cause: err })
- }
- }
-
/**
* Calculates proof-of-work using a pool of Web Workers.
*
}
/**
- * Set the amount of nano that this block will receive from a paired send.
- *
- * @param {bigint} amount - Amount that was sent from sender in raw
- * @returns {Block} This block so that additional calls can be chained
- */
- receive (amount: bigint): Block
- /**
- * Set the amount of nano that this block will receive from a paired send.
- *
- * @param {number} amount - Amount that was sent from sender in nano (10³⁰ raw)
- * @returns {Block} This block so that additional calls can be chained
- */
- receive (amount: number): Block
- /**
- * Set the amount of nano that this block will receive from a paired send.
+ * Set the amount of nano that this block will receive from a corresponding
+ * send block.
*
- * @param {string} amount - Amount that was sent from sender in raw
- * @returns {Block} This block so that additional calls can be chained
+ * @param {(string|Block)} sendBlock - Corresponding send block or its hash
+ * @param {(bigint|number|string)} amount - Amount to be received from sender
+ * @param {string} [unit] - Unit of measure for amount. Default: "NANO" (10³⁰ RAW)
+ * @returns {Block} This block with balance, link, and subtype configured
*/
- receive (amount: string): Block
- receive (amount: unknown): Block {
- const currentBalance = this.balance
+ receive (sendBlock: string | Block, amount: bigint | number | string, unit?: string): Block
+ receive (sendBlock: unknown, amount: unknown, unit: unknown): Block {
+ const { balance, link, subtype } = this
try {
if (this.subtype != null) {
- throw new Error(`Block is already configured as ${this.subtype}`)
+ throw new Error(`Block already configured as ${this.subtype}`)
}
this.subtype = 'receive'
- switch (typeof amount) {
- case 'bigint': {
- this.balance += amount
- break
- }
- case 'number': {
- this.balance += BigInt(amount) * (1n << 30n)
- break
- }
- case 'string': {
- this.balance += BigInt(amount)
- break
- }
- default: {
- throw new TypeError('Invalid amount')
- }
+
+ unit ??= UNITS.RAW
+ if (typeof unit !== 'string' || typeof UNITS[unit] !== 'number') {
+ throw new TypeError('Invalid unit')
}
+
+ if (typeof amount !== 'bigint' && typeof amount !== 'number' && typeof amount !== 'string') {
+ throw new TypeError('Invalid amount')
+ }
+ this.balance += BigInt(amount) * (1n << BigInt(UNITS[unit.toUpperCase()]))
+
+ if (typeof sendBlock !== 'string' && !(sendBlock instanceof Block)) {
+ throw new TypeError('Invalid send block')
+ }
+ this.link = (typeof sendBlock === 'string')
+ ? hex.toBytes(sendBlock)
+ : sendBlock.hash
+
return this
} catch (err) {
- this.subtype = undefined
- this.balance = currentBalance
+ this.balance = balance
+ this.link = link
+ this.subtype = subtype
throw new TypeError('Failed to configure receive block', { cause: err })
}
}
/**
* Set the amount of nano that this block will send to a recipient account.
*
- * @param {bigint} amount - Amount to send to recipient in raw
- * @returns {Block} This block so that additional calls can be chained
- */
- send (amount: bigint): Block
- /**
- * Set the amount of nano that this block will send to a recipient account.
- *
- * @param {number} amount - Amount to send to recipient in nano (10³⁰ raw)
- * @returns {Block} This block so that additional calls can be chained
- */
- send (amount: number): Block
- /**
- * Set the amount of nano that this block will send to a recipient account.
- *
- * @param {string} amount - Amount to send to recipient in raw
- * @returns {Block} This block so that additional calls can be chained
+ * @param {(string|Account)} account - Account to target or its address or public key
+ * @param {(bigint|number|string)} amount - Amount to send to recipient
+ * @param {string} [unit] - Unit of measure for amount. Default: "NANO" (10³⁰ RAW)
+ * @returns {Block} This block with balance, link, and subtype configured
*/
- send (amount: string): Block
- send (amount: unknown): Block {
- const currentBalance = this.balance
+ send (account: string | Account, amount: bigint | number | string, unit?: string): Block
+ send (account: unknown, amount: unknown, unit: unknown): Block {
+ const { balance, link, subtype } = this
try {
if (this.subtype != null) {
- throw new Error(`Block is already configured as ${this.subtype}`)
+ throw new Error(`Block already configured as ${this.subtype}`)
}
this.subtype = 'send'
- switch (typeof amount) {
- case 'bigint': {
- this.balance -= amount
- break
- }
- case 'number': {
- this.balance -= BigInt(amount) * (1n << 30n)
- break
- }
- case 'string': {
- this.balance -= BigInt(amount)
- break
- }
- default: {
- throw new TypeError('Invalid amount')
- }
+
+ unit ??= UNITS.RAW
+ if (typeof unit !== 'string' || typeof UNITS[unit] !== 'number') {
+ throw new TypeError('Invalid unit')
+ }
+
+ if (typeof amount !== 'bigint' && typeof amount !== 'number' && typeof amount !== 'string') {
+ throw new TypeError('Invalid amount')
+ }
+ this.balance -= BigInt(amount) * (1n << BigInt(UNITS[unit.toUpperCase()]))
+
+ if (this.balance < 0) {
+ throw new RangeError('Insufficient funds', { cause: this.balance })
}
+
+ if (typeof account !== 'string' && !(account instanceof Account)) {
+ throw new TypeError('Invalid account')
+ }
+ this.link = (typeof account === 'string')
+ ? hex.toBytes(Account.import(account).publicKey)
+ : hex.toBytes(account.publicKey)
+
return this
} catch (err) {
- this.subtype = undefined
- this.balance = currentBalance
+ this.balance = balance
+ this.link = link
+ this.subtype = subtype
throw new TypeError('Failed to configure send block', { cause: err })
}
}
}
- /**
- * Set the recipient of a send block or the target representative of a change
- * block.
- *
- * @param {string} account - Address or public key of Account to target
- * @returns {Block} This block so that additional calls can be chained
- */
- to (account: string): Block
- /**
- * Set the recipient of a send block or the target representative of a change
- * block.
- *
- * @param {Account} account - Account to target
- * @returns {Block} This block so that additional calls can be chained
- */
- to (account: Account): Block
- to (account: unknown): Block {
- try {
- if (typeof account !== 'string' && !(account instanceof Account)) {
- throw new TypeError('Invalid account')
- }
- switch (this.subtype) {
- case 'change': {
- this.representative = (typeof account === 'string')
- ? Account.import(account)
- : account
- break
- }
- case 'send': {
- this.link = (typeof account === 'string')
- ? hex.toBytes(Account.import(account).publicKey)
- : hex.toBytes(account.publicKey)
- break
- }
- default: {
- throw new TypeError('Invalid subtype')
- }
- }
- return this
- } catch (err) {
- throw new Error('Failed to change to, or send to, an Account', { cause: err })
- }
- }
-
/**
* Verifies the signature of the block. If a key is not provided, the public
* key of the block's account will be used if it exists.