Skip to main content

Vouchers

Vouchers serve as a mechanism for facilitating on-chain actions initiated in the execution layer.

Imagine vouchers as digital authorization tickets that grant dApps the authority to execute specific actions directly on the base layer. These vouchers encapsulate the details of the desired on-chain action, such as a token swap request or asset transfer.

A voucher explicitly specifies the action that the dApp intends to execute on the base layer.

For instance, in a DeFi application built on Cartesi, users may want to swap one token for another. The dApp generates a voucher that authorizes the on-chain smart contract to execute the swap on the user's behalf.

The Application contract is crucial in validating and executing the received voucher on the blockchain. This execution process occurs through the executeOutput() function, which handles different types of outputs including vouchers and DELEGATECALL vouchers.

The result of the voucher execution is recorded on the base layer. This recording typically involves submitting claims by a consensus contract, ensuring the integrity and transparency of the executed on-chain action.

import { stringToHex, encodeFunctionData, erc20Abi, zeroHash } from "viem";

async function handle_advance(data) {
console.log("Received advance request data " + JSON.stringify(data));
const sender = data["metadata"]["msg_sender"];
const erc20Token = "0x784f0c076CC55EAD0a585a9A13e57c467c91Dc3a"; // Sample ERC20 token address

const call = encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [sender, BigInt(10)],
});

let voucher = {
destination: erc20Token,
payload: call,
value: zeroHash,
};

await emitVoucher(voucher);
return "accept";
}


const emitVoucher = async (voucher) => {
try {
await fetch(rollup_server + "/voucher", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(voucher),
});
} catch (error) {
//Do something when there is an error
}
};

create a voucher

Refer to the documentation here for asset handling and creating vouchers in your dApp.

DELEGATECALL Vouchers

Security Considerations

DELEGATECALL Vouchers are a powerful feature that should be used with extreme caution. Incorrect implementation can lead to serious security vulnerabilities as the target contract's code has full access to the Application contract's storage and funds.

DELEGATECALL Vouchers are an extension of vouchers that enables advanced smart contract interactions through the DELEGATECALL opcode.

Unlike regular vouchers, DELEGATECALL vouchers allow dApps to separate their execution logic from their storage context. When using DELEGATECALL voucher, the Application contract always maintains the storage, context, and funds (both ETH and tokens), while the target contract provides only the execution logic. This separation enables more flexible and reusable smart contract patterns while keeping all state changes and assets within the Application contract.

When a DELEGATECALL voucher is executed through the Application contract, the code at the target address is executed with the following characteristics:

  • All storage operations occur in the Application contract's storage space
  • All funds (ETH and tokens) remain in and are managed by the Application contract
  • The msg.sender and msg.value from the original transaction are preserved
  • The execution logic comes from the target contract, but operates on the Application contract's state and funds

This mechanism, where the Application contract maintains the state and funds while borrowing logic from other contracts, enables powerful patterns such as:

  • Paid Vouchers: Vouchers that provide payment to the user who executes them.

  • Future Vouchers: Vouchers that are time-locked and can only be executed after a specific timestamp.

  • Expirable Vouchers: Vouchers that have an expiration timestamp, after which they can no longer be executed.

  • Targeted Vouchers: Vouchers that are restricted to execution by specific addresses or a list of authorized addresses.

  • Atomic Vouchers: A sequence of message calls that must be executed in order, ensuring atomicity of the operations.

  • Re-executable Vouchers: Vouchers that can be executed multiple times, unlike standard vouchers which can only be executed once.

  • Ordered Vouchers: Vouchers that must be executed in a specific sequence. For example, voucher A can only be executed after voucher B has been executed.

import { encodeFunctionData } from "viem";

const abi = [
"function safeTransfer(address,address,uint256)"
];

async function emitSafeERC20Transfer(token, to, amount) {
const call = encodeFunctionData({
abi,
functionName: "safeTransfer",
args: [token, to, amount],
});

const voucher = {
destination: "0xfafafafafafafafafafafafafafafafafafafafa", // address of the contract containing the logic
payload: call,
};

await fetch(rollup_server + "/delegate-call-voucher", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(voucher),
});
}

Implementation Considerations

When implementing DELEGATECALL vouchers, consider the following:

  1. Storage Layout: Since all storage operations happen in the Application contract, the storage layout of the target contract must be compatible with the Application contract's layout to prevent unintended storage collisions.

  2. Security: Since DELEGATECALL operations execute code in the context of the Application contract, careful validation of the target contract and its code is essential to prevent malicious modifications to the Application's state.

  3. State Management: All state changes occur in the Application contract's storage, making it the single source of truth for the application's state.

Execution Context

In a DELEGATECALL voucher execution:

  • The Application contract provides the execution context and storage
  • The target contract provides only the logic to be executed
  • All storage operations affect the Application contract's state
  • msg.sender and msg.value from the original transaction are preserved

This architecture, where the Application contract maintains all state while being able to execute logic from other contracts, makes DELEGATECALL vouchers particularly useful for customizable logics while keeping all application state centralized in the Application contract.

Epoch Configuration

An epoch refers to a specific period during which a batch of updates is processed off-chain, and upon agreement by validators, the finalized state is recorded on-chain.

Epoch Length is the number of blocks that make up an epoch. It determines how long each epoch lasts in terms of block counts. For instance, if an epoch length is set to 7200 blocks, the epoch will end once 7200 blocks have been processed. This length directly influences how frequently updates are finalized and recorded on the blockchain.

Vouchers and DELEGATECALL vouchers are executed on the blockchain upon the closure of the corresponding epoch. This ensures that all state changes and logic executions are properly validated and recorded in the blockchain.

One common use of vouchers in Cartesi dApps is to withdraw assets. Users initiate asset withdrawals by generating vouchers, which are then executed on the blockchain upon the closure of the corresponding epoch.

You can manually set the epoch length to facilitate quicker asset deposits and withdrawals.

epoch duration

Refer to the documentation here to manually configure epoch length during development.

On this page

Useful resources to learn more

We use cookies to ensure that we give you the best experience on our website. By using the website, you agree to the use of cookies.