Difference between revisions of "Super.init() caller"

From RunWiki
Jump to: navigation, search
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.
+
 
 +
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)