Payment of transaction fees by zkApps means that the network fees (equivalent to the gas charged in ethereum) for transactions initiated by ordinary users are paid by smart contracts under the mina protocol. Users can make zkApps pay for their transactions by generating proofs.
Two main types of transaction fees paid by zkApps:
-
zkApps pay network fees for any transaction initiated by the user.
-
zkApps pay network fees for transactions associated with themselves.
Benefits and use cases of transaction fees paid by zkApps
-
Developers of zkApps can build and run programs like “fee paying relayers” to pay for users, but this requires hosting the private key of their wallet used to pay on the server, and there is a risk of leakage of the private key. If zkApps can pay the fee through proof verification, it will be more secure.
-
For some zkApps that focus on privacy transactions, supporting zkApps to pay for users can better protect users’ privacy.
-
Create a non-custodial smart contract wallet with better user experience and no reliance on third-party centralized services.
-
Developers or operators of zkApps can pay transaction fees for their users, lowering the threshold for users to use and experience.
-
NFT issuers can make their issued NFTs transferable among users for free, and users can enter the NFT world without purchasing mina coins.
-
Users can obtain the right to send transactions for free through the project’s tokens or NFT credentials, and zkApps can also consume the user’s project tokens or NFTs to pay for users, increasing the utility of the project’s issued tokens or NFTs.
-
Developers can set up zkApps to accept donations from anyone to pay for user transactions, which ensures that donations can only be used to pay for network fees.
And more…
Ideally, users can generate proof by executing the payment method in the smart contract, and let the smart contract pay for the user’s transaction through the authorization of the proof. This method allows developers to freely define payment conditions and assertions.
A succinct example of snarkyjs pseudocode that can describe the above idea of paying fees is as follows:
class SimpleZkapp extends SmartContract {
@state(Field) x = State<Field>();
@State(Field) whitelistRoot = State<Field>();
deploy() {
this.x.set(Field(initialState));
this.whitelistRoot.set(initialWhitelistRoot);
}
@method
update(y: Field) {
let x = this.x.get();
this.x.set(x.add(y));
}
// add a new decorator(payfee) for payment of fees.
// This method determines whether to pay for any of the user's transactions by verifying
// that the sender of the transaction is in the whitelist.
@payfee
payFeesForWhitelist(currentTx: Transaction, proof: MerkleTreeProof): UInt64 {
const fromAddress = currentTx.from;
currentTx.from.assertEqual(fromAddress);
const whitelistRoot = this.whitelistRoot.get();
// Verify that the sender's address is in the whitelist
verifyProof(whitelistRoot, fromAddress, proof).assertEqual(true);
// Set and return the allowable fee for each transaction
return UInt64.fromNumber(100_000_000);
}
// This method allows network fees to be paid for any transaction that interacts with the current zkApp.
@payfee
payFeesForUser(currentTx: Transaction): UInt64 {
const toAddress = this.address;
currentTx.to.assertEqual(toAddress);
// Set and return the allowable fee for each transaction
return UInt64.fromNumber(100_000_000);
}
}
let simpleZkapp = new SimpleZkapp(xxxx);
// zkApps pay network fees for any transaction initiated by the user.
await Mina.transaction(() => {
simpleZkapp.update(Field(10));
}
).payFees(simpleZkapp, (currentTx: Transaction): UInt64 => {
return simpleZkapp.payFeesForWhitelist(currentTx, proof);
}).prove().send();
// zkApps pay network fees for transactions associated with themselves.
await Mina.transaction(() => {
simpleZkapp.update(Field(10));
}
).payFees(simpleZkapp, (currentTx: Transaction): UInt64 => {
return simpleZkapp.payFeesForUser(currentTx);
}).prove().send();