abstract class Block {
account: Account
type: 'state' = 'state'
- abstract subtype: 'send' | 'receive' | 'change'
+ abstract subtype?: 'send' | 'receive' | 'change'
abstract previous: string
- abstract representative: Account
+ abstract representative?: Account
abstract balance: bigint
abstract link: string
abstract signature?: string
* @returns {Promise<string>} Block data hashed to a byte array
*/
get hash (): string {
+ if (this.representative == null) {
+ throw new Error('Block hash missing representative')
+ }
const data = [
PREAMBLE,
this.account.publicKey,
"type": this.type,
"account": this.account.address,
"previous": this.previous,
- "representative": this.representative.address,
+ "representative": this.representative?.address ?? '',
"balance": this.balance.toString(),
"link": this.link,
"signature": this.signature ?? '',
}
}
+ /**
+ * Set the subtype and link to configure this as a change representative block.
+ *
+ * @returns {Block} This block so that additional calls can be chained
+ */
+ change (): Block {
+ if (this.subtype != null) {
+ throw new Error(`Block is already configured as ${this.subtype}`)
+ }
+ try {
+ this.subtype = 'change'
+ return this
+ } catch (err) {
+ this.subtype = undefined
+ throw new TypeError('Failed to configure send block', { cause: err })
+ }
+ }
+
/**
* Calculates proof-of-work using a pool of Web Workers.
*
return res.hash
}
+ /**
+ * 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
+ */
+ send (amount: string): Block
+ send (amount: unknown): Block {
+ const currentBalance = this.balance
+ try {
+ if (this.subtype != null) {
+ throw new Error(`Block is 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')
+ }
+ }
+ return this
+ } catch (err) {
+ this.subtype = undefined
+ this.balance = currentBalance
+ throw new TypeError('Failed to configure send block', { cause: err })
+ }
+ }
+
/**
* Signs the block using a private key. If successful, the result is stored in
* the object's `signature` property.
}
}
+ /**
+ * 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.link = Account.import(BURN_ADDRESS).publicKey
+ this.representative = (typeof account === 'string')
+ ? Account.import(account)
+ : account
+ break
+ }
+ case 'send': {
+ this.link = (typeof account === 'string')
+ ? Account.import(account).publicKey
+ : account.publicKey
+ this.representative = this.account.representative
+ 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.