Difference between revisions of "Super.init() caller"
| Line 9: | Line 9: | ||
satoshis: undefined | satoshis: undefined | ||
}</syntaxhighlight> | }</syntaxhighlight> | ||
| − | + | ||
| − | + | ||
| + | Note that despite these issues, it works nontheless, since it detects as 'sending' instead of 'minting', which manages to still pass the check and mint the token. | ||
Revision as of 07:49, 1 February 2026
Redefining init() with a call to super.init() inside causes issues:
- "minting = false, sending = true" (should be the opposite)
- 'caller' variable which should be the class TokenA,
but becomes instead:
Object <Object <Object <Object <Complex prototype>>>> {
location: 'error://Undeployed',
origin: 'error://Undeployed',
nonce: 0,
owner: 'mo61dRQheTcBMf1d7UEv91ybaDqXUyKUwd',
satoshis: undefined
}
Note that despite these issues, it works nontheless, since it detects as 'sending' instead of 'minting', which manages to still pass the check and mint the token.
Full Code you can test (just comment the init() entirely in TokenA) to see the difference in logs while running it:
const Run = require('../../libs/run.0.6.44.node.min.js');
const { runMain, log, displayTokensOnAddress } = require('../helpers.js');
let run = new Run({ network: 'mock', trust: 'state' })
// pure copy of the Token20 with only some added logging
class Token20Copy extends Jig {
init(amount, owner) {
this._checkAmount(amount)
// The base Token class cannot be created on its own
const extended = this.constructor !== Token20Copy
if (!extended) throw new Error('Token must be extended')
// Make sure we are calling from ourself
const minting = caller === this.constructor
const sending = caller && caller.constructor === this.constructor
console.log("minting =", minting, ", sending =", sending, ", \n caller =", caller)
if (!minting && !sending) throw new Error('Must create token using mint()')
this.sender = sending ? caller.owner : null
this.amount = amount
if (owner) this.owner = owner
}
static mint(amount, owner) {
this.supply += amount
return new this(amount, owner)
}
send(to, amount = this.amount) {
this._checkAmount(amount)
if (this.amount === amount) {
this.destroy()
} else if (this.amount > amount) {
this.amount -= amount
} else {
throw new Error('Not enough funds')
}
return new this.constructor(amount, to)
}
combine(...tokens) {
// If no tokens to combine, nothing to do
if (!tokens.length) return this
// Each token to combine must all be of this type
const all = tokens.concat(this)
if (all.some(token => token.constructor !== this.constructor)) {
throw new Error('Cannot combine different token classes')
}
// Check for duplicate tokens in the array
const countOf = token => all.reduce((count, next) => next === token ? count + 1 : count, 0)
if (all.some(token => countOf(token) > 1)) throw new Error('Cannot combine duplicate tokens')
// Destroy each token, absorbing it into this one
tokens.forEach(token => {
this.amount += token.amount
token.destroy()
})
// There is no sender for combined tokens
this.sender = null
// Make sure our new amount is within safe range
this._checkAmount(this.amount)
return this
}
destroy() {
super.destroy()
this.amount = 0
this.sender = null
}
_checkAmount(amount) {
if (typeof amount !== 'number') throw new Error('amount is not a number')
if (!Number.isInteger(amount)) throw new Error('amount must be an integer')
if (amount <= 0) throw new Error('amount must be positive')
if (amount > Number.MAX_SAFE_INTEGER) throw new Error('amount too large')
}
}
class TokenA extends Token20Copy {
/** Redefining init() with a call to super.init() inside causes issues:
* - "minting = false, sending = true" (should be the opposite)
* - 'caller' variable which should be the class TokenA,
* but becomes instead: Object <Object <Object <Object <Complex prototype>>>> {
* location: 'error://Undeployed',
* origin: 'error://Undeployed',
* nonce: 0,
* owner: 'mo61dRQheTcBMf1d7UEv91ybaDqXUyKUwd',
* satoshis: undefined
* }
*
* Note that despite these issues, it works nontheless, since it detects as 'sending' instead of 'minting',
* which manages to still pass the check and mint the token.
**/
init(amount, owner) {
super.init(amount, owner)
}
}
TokenA.decimals = 2
TokenA.ticker = 'TokenA'
TokenA.currency = 'TokenA'
async function _main() {
const owner = run.owner.address
await displayTokensOnAddress(owner, run)
TokenA = run.deploy(TokenA)
await run.sync()
TokenA = await run.load(TokenA.origin)
log("TokenA.owner =", TokenA.owner)
log("minting TokenA")
let tokenACoins = TokenA.mint(10 * 10 ** TokenA.decimals, owner)
await run.sync()
await displayTokensOnAddress(owner, run)
}
runMain(_main, run, null)