Skip to content

The Mandate.sol Contract

Mandate.sol is the base implementation for Powers Protocol Mandates. It provides the core functionality for creating modular, role-restricted governance actions that serve as the building blocks of the Powers protocol. Each mandate is a singleton contract that can be used by multiple Powers protocols.

1. Core Concepts

Mandates serve four key functions in the Powers protocol:

  1. Transform Data: Give roles powers to transform input data into executable calldata.
  2. Validate: Validate input and execution data.
  3. External Calls: Call external contracts and validate return data.
  4. Return Data: Return execution data to the Powers protocol.

Mandates can be customized through inheriting and implementing bespoke logic in the handleRequest, _replyPowers, and _externalCall functions.

2. The Mandate Execution Flow

The execution of a mandate is a multi-step process managed by the executeMandate function, which is the main entry point and can only be called by an authorized Powers.sol contract.

Executing the Mandate (executeMandate)

This is the main function that orchestrates the entire process.

  1. Initial Validation: Checks that the caller is the Powers contract.
  2. Translation: Calls handleRequest to get the action details on basis of input calldata.
  3. External Call: Calls _externalCall to execute any external contract interactions.
  4. Completion: Calls _replyPowers to finalize the action and report back to Powers.

Simulating the Mandate (handleRequest)

To allow for off-chain simulation and validation, the handleRequest view function processes a request and returns the expected outcome without modifying state.

  • It generates a unique actionId.
  • Runs any additional checks specific to the mandate.
  • It processes input parameters and prepares the target contract calls, values, and calldata.
  • It returns the target contract calls, values, and calldata without making any state changes.
  • Note: This function must be overridden by implementing contracts.

External Calls (_externalCall)

The internal _externalCall function is meant to be used to call external contracts.

  • This is especially useful for async mandates or complex integrations.
  • It receives the execution data prepared by handleRequest.
  • It can be overridden by implementing contracts.

Returning calldata (_replyPowers)

The internal _replyPowers function sends the execution data (targets, values, calldatas) back to the Powers.sol contract's fulfill function, which executes the actual on-chain calls.

  • It can be overridden by implementing contracts.
  • Important: For async calls where _replyPowers should not return immediately, implementing contracts should ensure the targets array is empty or modify the logic to prevent the callback.

3. Technical Specifications

Source

Key Functions

  • Execution: initializeMandate, executeMandate, handleRequest, _externalCall, _replyPowers
  • Helpers: getNameDescription, getInputParams, getConfig

State Variables

  • mandates: mapping(bytes32 mandateHash => MandateData) public mandates;

Structs

  • MandateData: Tracks a mandate's configuration (nameDescription, inputParams, config, powers).

Events & Errors

  • Events: Mandate__Deployed, Mandate__Initialized
  • Errors: revert("Only Powers") and other custom errors depending on implementation.

4. Implementation Best Practices

  • Async Mandates: For mandates that require asynchronous execution (e.g., cross-chain bridges), use _externalCall to initiate the external process and ensure _replyPowers does not inadvertently complete the action before the external process returns.
  • Security: Mandates should be thoroughly tested. Validate all inputs and ensure proper access controls.
  • Gas Optimization: Minimize state changes, use efficient data structures, and order checks from least to most expensive.
  • Clarity: Use clear and descriptive names for mandates and their parameters. Document all conditions and requirements.