#Can we pass arugments to Experimental.callback?

1 messages · Page 1 of 1 (latest)

naive maple
#

Wondering if this is possible 🤔

public withdraw(to: Experimental.callback) {
 const amount = UInt64.from(...) // amount gets computed on the fly
 this.balance.subInPlace(amount);
 const toAccountUpdate = to(amount); // callback account update can access the computed amount, and issue an account update with it
 Token.approveAccountUpdates([this.self, toAccountUpdate]);
}
formal flame
#

Well, it doesn't work right now obviously. So, we could try to implement something like that, but we would need to think about the semantics, like, what computation is included in which proof.

naive maple
#

just to add, the callback account update(s) wont be nested under withdraw for this to work as i expect

formal flame
#

The way it currently works is that calling of the callback is not proven inside the method that receives it as input. It can't be, because the receiving method doesn't statically know the circuit involved in calling the callback (it can take any callback). Also, it makes sense that executing a callback with no arguments is like receiving the return value as a witness, which is the current semantics.

But in the case there's an additional argument passed into the callback from the receiving method, I feel that we should also link the input parameter (here amount) to the return value (toAccountUpdate) somehow

#

which could possibly be achieved if the returned account update gets the input baked in as part of callData

formal flame
naive maple
#

and it you start nesting the updates the interoperability suffers also due to the fact the mayUseToken must be then different for different nesting

formal flame
#

But you're right about the interoperability

naive maple
#

but then the ‘to’ token holder must output a different mayUseToken configuration, which might mean an extra method or extra param again

#

i think keeping the AU layout flat so that we can then approve(from, to) with no children is a safer approach to interoperability, im tryinng to simplify as much as i can

formal flame
#

but this would happen anyway?

naive maple
#

but the nesting simply comes from the fact that new AccountUpdate in the callback is called in the withdraw ‘context’ so when its attached to tx it gets to be nested under withdraw, would be nice if the callback had its own context as a sibling of withdraw instead

formal flame
#

the to account update would be nested under the TokenContract after being passed to it

naive maple
#

no, if the structure is flat then to uses parentsOwnToken, if its nested in withdraw then its inheritFromParent

#

yes but if you nest it further under withdraw then its token->withdraw->to instead of token->to token->withdraw

formal flame
#

aah I didn't realize you're nesting this.self under the token contract

#

is that even possible? 😄

#

it seems to be a cycle to me

naive maple
#

im trying to design a token standard where both send/receive: proof is supported therefore from/to AUs of the ‘user’ are to be constructed in the tx, not in the ‘withdraw’

#

zkApp->tokenHolder.withdraw
zkApp->Token.approve(tokenHolder.self)
i think ^^
and then in the same TX i want

UserTokenHolder.withdraw(..)

#

^ + Token.approve(userTokenHolder.self)

#

so user only issues ‘sub balance’ and zkapp’s token holder issues add balance

#

this means if user has a token holder zkapp then they can prove their AU, same case when the ‘to’ is a zkapp with receive: proof

#

the reasoning is the the ‘user’ AU is not part of the zkApp the user interacts with so that you can support proof for receive & send

formal flame
#

makes sense

naive maple
#

i think its a sound approach and pretty much the only way not to couple user’s zkapp proof with the zkaapp they want to interact with

formal flame
#

I also think it's sound; the zkapp requires the balance input by adding balance somewhere

naive maple
#

i was pulling my hair out until this clicked for me, so now trying to design the best interace for it also for callbacks

#

yeah both operate on an amount, thats why i wanted to let the zkapp compute the amount and pass it to a callback

#

otherwise i will have to precompute the amount so that i can create both AUs independently

#

which should also be OK but with the callback argument it’d be simplier to understand and work with flow wise

formal flame
#

conceptually it means we have to represent a function (amount: UInt64) => AccountUpdate as a circuit input and include it in the proof in such a way that we can prove that really that function was executed

naive maple
#

i think the interface im going for is a non-method token.transfer(from:? address, to?: address, amount: Uint32/64), this will be a wrapper which allows you to issuue either one or two account updates, where also one might require signature etc, this can be used by both token holders and its gonna be really simple to use

naive maple
formal flame
#

however, the function is opaque to withdraw, it can be anything (chosen by the prover), so we shouldn't actually have to worry about representing it as circuit inside withdraw

naive maple
#

actually the callback must be fully decoupled from the circuit bcs otherwise you get no interoperability again

formal flame
#

but it should be represented in the circuit of the method which calls another method with the callback

naive maple
#

represented how? it could be just random JS called in the circuit with a js value, which happens to be computed by the withdraw circuit, the callback doesnt need to be proven, bcs its contents are a standalone proof of the user’s token holder, unrelated to the withdraw circuit

#

same as if you did them side by side in a TX, but they just happen to have access to the same JS value (amount)

#

its purely syntactic/api sugar

formal flame
#

yeah it's unrelated to the withdraw circuit, but not to a circuit which calls withdraw

#

well, let me think about this

#

good idea anyway!