o1-labs / o1js

TypeScript framework for zk-SNARKs and zkApps
https://docs.minaprotocol.com/en/zkapps/how-to-write-a-zkapp
Apache License 2.0
475 stars 105 forks source link

Custom token transfers don't work based on the order of account updates. #1636

Closed berzanorg closed 1 month ago

berzanorg commented 1 month ago

There was no issue when I was using o1js v0.17.0, but after I updated my project to v1.1.0 it started to throw the error below.

Error: Cannot push to an immutable forest

This code works: (fixed version)

const mintTx = await Mina.transaction(userAccount2, async () => {
    AccountUpdate.fundNewAccount(userAccount2)
    token.transfer(userAccount2, userAccount1, UInt64.from(1000))
})

But this doesn't work: (old version)

const mintTx = await Mina.transaction(userAccount2, async () => {
    token.transfer(userAccount2, userAccount1, UInt64.from(1000))
    AccountUpdate.fundNewAccount(userAccount2)
})

And throws this error, Error: Cannot push to an immutable forest.

You can replicate the same error just by using a basic custom token contract like below:

export class TokenContract extends BaseTokenContract {
    @method async mint(amount: UInt64, receiver: PublicKey) {
        this.internal.mint({
            address: receiver,
            amount,
        })
    }

    @method async approveBase(forest: AccountUpdateForest) {
        this.checkZeroBalanceChange(forest)
    }
}

Maybe having a more clear error message would make it easier to debug. Or if it is possible, making both of the snippets work like in the previous versions would be very good.

mitschabaude commented 1 month ago

@berzanorg you're just missing an await:

const mintTx = await Mina.transaction(userAccount2, async () => {
-  token.transfer(userAccount2, userAccount1, UInt64.from(1000))
+  await token.transfer(userAccount2, userAccount1, UInt64.from(1000))
   AccountUpdate.fundNewAccount(userAccount2)
})
mitschabaude commented 1 month ago

It seems hard to give consistently good error messages for this problem :/

Here's what happens: