Difference between revisions of "Super.init() caller"
| (3 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
| − | + | When you extend Token, redefining init() with a call to super.init() inside causes issues: | |
- "minting = false, sending = true" (should be the opposite) | - "minting = false, sending = true" (should be the opposite) | ||
| Line 18: | Line 18: | ||
| − | Full Code you can test | + | Full Code you can test, just comment the init() entirely in TokenA to see the difference in logs while running it: |
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
const Run = require('../../libs/run.0.6.44.node.min.js'); | const Run = require('../../libs/run.0.6.44.node.min.js'); | ||
| − | const | + | const log = console.log |
let run = new Run({ network: 'mock', trust: 'state' }) | let run = new Run({ network: 'mock', trust: 'state' }) | ||
| Line 134: | Line 134: | ||
TokenA.currency = 'TokenA' | TokenA.currency = 'TokenA' | ||
| + | |||
| + | async function displayTokensOnAddress() { | ||
| + | await run.inventory.sync() | ||
| + | const tokens = run.inventory.jigs | ||
| + | log("---tokens on address:", tokens.length) | ||
| + | for (const token of tokens) { | ||
| + | log("token:", token.constructor.ticker, token.amount / (10 ** token.constructor.decimals), token.constructor.origin) | ||
| + | } | ||
| + | log("---end---\n") | ||
| + | } | ||
async function _main() { | async function _main() { | ||
const owner = run.owner.address | const owner = run.owner.address | ||
| − | await displayTokensOnAddress( | + | await displayTokensOnAddress() |
TokenA = run.deploy(TokenA) | TokenA = run.deploy(TokenA) | ||
| Line 149: | Line 159: | ||
await run.sync() | await run.sync() | ||
| − | await displayTokensOnAddress( | + | await displayTokensOnAddress() |
} | } | ||
| − | + | _main() | |
</syntaxhighlight> | </syntaxhighlight> | ||
[[Category:Issues]] | [[Category:Issues]] | ||
Latest revision as of 08:13, 1 February 2026
When you extend Token, 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 nonetheless, since it detects the situation 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 log = console.log
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 displayTokensOnAddress() {
await run.inventory.sync()
const tokens = run.inventory.jigs
log("---tokens on address:", tokens.length)
for (const token of tokens) {
log("token:", token.constructor.ticker, token.amount / (10 ** token.constructor.decimals), token.constructor.origin)
}
log("---end---\n")
}
async function _main() {
const owner = run.owner.address
await displayTokensOnAddress()
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()
}
_main()