IBExWalletAPI
Advanced

Safe Modules & Operations

IBEX Safe Modules & Operations — External API Reference

This document provides a comprehensive reference for all Safe (Gnosis Safe) modules, options, and operations exposed through the IBEX-FI API. It is intended for external integrators building on top of the IBEX-FI platform.


Table of Contents

  1. Overview: Safe Modules & Options
  2. Module: Recovery
  3. Module: Multisig (Owners & Threshold)
  4. Module: Automation / Allowance
  5. Operations Endpoint Reference
  6. Automation Trigger & Callback Endpoints
  7. Automation Config Update Endpoint
  8. Database Impact

1. Overview: Safe Modules & Options

Every Safe wallet managed by IBEX supports the following features, all accessible through the unified batch operations API (POST /v1.2/safes/operations/batch-intentPUT /v1.2/safes/operations/batch-execute).

CategoryOperation Type(s)Description
RecoveryENABLE_RECOVERY, CANCEL_RECOVERYSocial recovery module — lets a guardian recover the Safe if the owner loses access.
Multisig / OwnersADD_OWNER, REMOVE_OWNER, CHANGE_THRESHOLDAdd/remove co-signers and change the approval threshold (M-of-N).
Allowance (Automation)ENABLE_AUTOMATION_MODULEEnable the Safe Allowance Module and configure automatic percentage-based token transfers triggered on deposit.
Token TransfersTRANSFER_EURe, TRANSFER_TOKENSend ERC-20 tokens (EURe or any token) from the Safe.
Message SigningSIGN_MESSAGEEIP-191 / EIP-712 off-chain message signing.
DeFiAAVE_SUPPLY, AAVE_WITHDRAW, SWAP_FROM_QUOTEAave lending and CoW Swap token swaps.

All operations use ERC-4337 (Account Abstraction) with WebAuthn (passkey) authentication. Gas is sponsored by IBEX (paymaster), so the end-user never pays gas.

Batch support: Multiple heterogeneous operations can be grouped into a single atomic transaction via MultiSend, requiring only one WebAuthn signature.


2. Module: Recovery

Allows a trusted guardian to recover the Safe by replacing the owner key.

ENABLE_RECOVERY

Activates the on-chain recovery module on the Safe.

Operation payload:

{
  "type": "ENABLE_RECOVERY",
  "firstName": "Jane",
  "lastName": "Doe",
  "birthDate": "1990-05-15",
  "birthCity": "Paris",
  "birthCountry": "FR"
}
FieldTypeRequiredDescription
typestringMust be "ENABLE_RECOVERY"
firstNamestringGuardian's first name
lastNamestringGuardian's last name
birthDatestringGuardian's birth date (YYYY-MM-DD)
birthCitystringGuardian's birth city
birthCountrystringGuardian's birth country (ISO 3166-1 alpha-2)

On-chain effect: Calls enableModule(recoveryModuleAddress) on the Safe.

Database effect: Sets hasRecovery = true and stores recoveryModuleAddress on the Safe record.

CANCEL_RECOVERY

Cancels a pending recovery procedure.

{
  "type": "CANCEL_RECOVERY"
}

3. Module: Multisig (Owners & Threshold)

These operations manage the Safe's signer list and the required approval threshold.

ADD_OWNER

Adds a new co-signer (owner) to the Safe and sets the new threshold.

{
  "type": "ADD_OWNER",
  "owner": "0x1234567890abcdef1234567890abcdef12345678",
  "threshold": 2
}
FieldTypeRequiredDescription
typestringMust be "ADD_OWNER"
ownerstringEVM address of the new owner (0x...)
thresholdnumberNew signature threshold (≥ 1)

On-chain effect: Calls addOwnerWithThreshold(owner, threshold) on the Safe.

REMOVE_OWNER

Removes an existing owner from the Safe and sets the new threshold.

{
  "type": "REMOVE_OWNER",
  "owner": "0x1234567890abcdef1234567890abcdef12345678",
  "threshold": 1
}
FieldTypeRequiredDescription
typestringMust be "REMOVE_OWNER"
ownerstringEVM address of the owner to remove (0x...)
thresholdnumberNew signature threshold after removal (≥ 1)

On-chain effect: Calls removeOwner(prevOwner, owner, threshold) on the Safe. The prevOwner is resolved automatically from the Safe's on-chain owner linked list.

CHANGE_THRESHOLD

Changes the approval threshold without modifying owners.

{
  "type": "CHANGE_THRESHOLD",
  "threshold": 2
}
FieldTypeRequiredDescription
typestringMust be "CHANGE_THRESHOLD"
thresholdnumberNew signature threshold (≥ 1, ≤ number of owners)

On-chain effect: Calls changeThreshold(threshold) on the Safe.


4. Module: Automation / Allowance

The Automation Module leverages the Safe Allowance Module (a standard Gnosis Safe module) to enable automatic percentage-based token transfers when tokens are deposited into the Safe.

Architecture

┌──────────────┐      ┌─────────────────────┐      ┌──────────────────────┐
│  User / App  │─────>│  IBEX-FI API        │─────>│  Safe (on-chain)     │
│              │      │  batch-intent +     │      │  ┌────────────────┐  │
│              │      │  batch-execute      │      │  │ Allowance      │  │
│              │      │                     │      │  │ Module         │  │
│              │      │  Worker (delegate)  │─────>│  │ executeAllow.. │  │
│              │      └─────────────────────┘      │  └────────────────┘  │
│              │                                   └──────────────────────┘
└──────────────┘

Key concepts:

  • Single Global Module: One Allowance Module contract is deployed per chain (stored in the Chains table). No per-user contract deployment needed.
  • Delegate (Worker): A backend-managed EOA (the "worker") is registered as a delegate on the Allowance Module. This delegate can call executeAllowanceTransfer without owner signatures.
  • Percentage-based: The module is configured with a percentage (0–100). When tokens arrive on the Safe, the backend triggers an automatic transfer of that percentage to the configured target address.
  • Counterfactual Safe: If the Safe is not yet deployed on-chain, the ENABLE_AUTOMATION_MODULE operation will include the initCode for Safe deployment in the UserOperation (exactly like ENABLE_RECOVERY).

ENABLE_AUTOMATION_MODULE

Activates the Allowance Module on the Safe and sets up the allowance configuration. This is a single atomic on-chain transaction (via MultiSend) that performs three actions:

  1. enableModule(allowanceModuleAddress) — Registers the module on the Safe
  2. addDelegate(workerAddress) — Registers the backend worker as a delegate
  3. setAllowance(delegate, token, amount, resetTimeMin, resetBaseMin) — Sets the token allowance

Operation payload:

{
  "type": "ENABLE_AUTOMATION_MODULE",
  "targetAddress": "0xaabbccddee11223344556677889900aabbccddee",
  "percentage": 50,
  "frequency": "NONE",
  "tokenAddress": "0xcB444e90D8198415266c6a2724b7900fb12FC56E",
  "workerAddress": "0x9988776655443322110099887766554433221100"
}
FieldTypeRequiredDescription
typestringMust be "ENABLE_AUTOMATION_MODULE"
targetAddressstringDestination address for automatic transfers
percentagenumberPercentage to transfer on each deposit (0–100)
frequencystringFrequency constraint: "DAILY", "WEEKLY", "90_DAYS", or "NONE"
tokenAddressstringERC-20 token address (0x0...0 for all tokens)
workerAddressstringOverride for the delegate address (defaults to server-configured AUTOMATION_MODULE_WORKER_ADDRESS)

Frequency values and their reset periods:

FrequencyReset Period (on-chain resetTimeMin)Description
NONE0No rate limit — can trigger at any time
DAILY1440 min (24 h)Once per day
WEEKLY10080 min (7 d)Once per week
90_DAYS129600 min (90 d)Once per 90 days

On-chain effect: Calls MultiSend with enableModule + addDelegate + setAllowance in a single UserOperation.

Error conditions:

  • Returns 409 Conflict if the automation module is already enabled on the Safe.

How Automatic Transfers Work (Post-Activation)

Once the module is activated, the transfer flow is:

  1. Deposit detected: BCReader (blockchain reader) detects an ERC-20 transfer to the Safe address.
  2. Callback: BCReader sends an erc20_received event to the IBEX backend (via WebSocket or HTTP callback).
  3. Calculation: The backend computes transferAmount = receivedAmount × percentage / 100.
  4. Execution: The backend worker calls executeAllowanceTransfer(safe, token, to, amount, ...) on the Allowance Module contract using its delegate private key.
  5. Confirmation: The transfer transaction is confirmed on-chain.

This flow requires no user interaction — it is fully automated once the module is enabled.


5. Operations Endpoint Reference

All Safe operations follow a two-step flow: intent (prepare) then execute (sign & submit).

Step 1 — POST /v1.2/safes/operations/batch-intent

Prepares a batch of one or more operations and returns WebAuthn challenge data.

Authentication: JWT (Bearer token)

Request headers:

HeaderRequiredDescription
AuthorizationBearer <jwt>``
X-Blockchain-IdChain ID (defaults to server DEFAULT_CHAIN_ID)
Content-Typeapplication/json

Request body:

{
  "safeAddress": "0xAbCdEf1234567890AbCdEf1234567890AbCdEf12",
  "chainId": 100,
  "operations": [
    {
      "type": "ENABLE_AUTOMATION_MODULE",
      "targetAddress": "0x9988776655443322110099887766554433221100",
      "percentage": 50,
      "frequency": "NONE",
      "tokenAddress": "0xcB444e90D8198415266c6a2724b7900fb12FC56E"
    }
  ]
}
FieldTypeRequiredDescription
safeAddressstringSafe wallet address
chainIdnumberTarget blockchain ID (e.g. 100 for Gnosis)
idempotencyKeystringClient-provided key to avoid duplicate batches
options.atomicbooleanIf true (default), all operations must succeed or all revert
options.autoApprovebooleanAuto-insert ERC-20 approvals before transfers (default true)
options.ttlSecnumberIntent TTL in seconds (default 300, range 60–3600)
operationsarrayArray of operation objects (min 1)

200 Response:

{
  "batchId": "a1b2c3d4e5f6a1b2c3d4e5f6",
  "expiresAt": "2026-03-07T15:05:00.000Z",
  "operationCount": 1,
  "credentialRequestOptions": {
    "challenge": "dXNlck9wSGFzaEJhc2U2NHVybA",
    "timeout": 60000,
    "rpId": "ibex.fi",
    "userVerification": "required",
    "allowCredentials": [
      {
        "id": "Y3JlZGVudGlhbElk",
        "type": "public-key"
      }
    ]
  }
}
FieldTypeDescription
batchIdstringUnique batch identifier (pass to batch-execute)
expiresAtstringISO 8601 expiration timestamp
operationCountnumberNumber of operations in the batch
credentialRequestOptionsobjectWebAuthn PublicKeyCredentialRequestOptions — use to sign with the passkey

Step 2 — PUT /v1.2/safes/operations/batch-execute

Submits the signed WebAuthn credential to execute the batch on-chain.

Authentication: JWT (Bearer token)

Request body:

{
  "batchId": "a1b2c3d4e5f6a1b2c3d4e5f6",
  "credential": {
    "id": "Y3JlZGVudGlhbElk",
    "rawId": "Y3JlZGVudGlhbElk",
    "type": "public-key",
    "response": {
      "authenticatorData": "SZYN5YgOjGh0...",
      "clientDataJSON": "eyJ0eXBlIjoi...",
      "signature": "MEUCIQC..."
    }
  }
}
FieldTypeRequiredDescription
batchIdstringThe batchId returned by batch-intent
credentialobjectSigned WebAuthn credential (from navigator.credentials.get())

200 Response:

{
  "userOpHash": "0x1234abcd5678ef901234abcd5678ef901234abcd5678ef901234abcd5678ef90"
}
FieldTypeDescription
userOpHashstringERC-4337 UserOperation hash — can be used to track execution status

Tracking Execution — GET /v1.2/safes/operations/\{userOpHash\}/status

Poll this endpoint to check the on-chain status.

200 Response:

{
  "userOpHash": "0x1234abcd...",
  "safeAddress": "0xAbCdEf...",
  "chainId": 100,
  "status": "CONFIRMED",
  "transactionHash": "0xdeadbeef...",
  "createdAt": "2026-03-07T15:00:00.000Z",
  "updatedAt": "2026-03-07T15:01:30.000Z",
  "operations": [
    { "index": 0, "type": "ENABLE_AUTOMATION_MODULE" }
  ],
  "error": null
}

Status lifecycle:

StatusDescription
CREATEDOperation prepared but not yet signed
SIGNEDWebAuthn signature attached
EXECUTEDSubmitted to the bundler / on-chain
CONFIRMEDConfirmed with sufficient block confirmations
FAILEDExecution reverted or timed out

6. Automation Trigger & Callback Endpoints

These system-level endpoints are used by the IBEX infrastructure (BCReader / cron) but are documented here for completeness.

POST /system/automation-module/on-token-received

HTTP callback endpoint called by BCReader when an ERC-20 token is received on a watched Safe. Triggers the automatic allowance transfer if the automation module is active.

Authentication: API Key (x-api-key header)

Request body:

{
  "type": "erc20_received",
  "success": true,
  "data": {
    "address": "0xAbCdEf1234567890AbCdEf1234567890AbCdEf12",
    "blockchainId": 100,
    "tokenAddress": "0xcB444e90D8198415266c6a2724b7900fb12FC56E",
    "tokenSymbol": "USDC.e",
    "tokenDecimals": 6,
    "from": "0x9988776655443322110099887766554433221100",
    "amount": "0.001",
    "transactionHash": "0xabc123...",
    "blockNumber": 39000000,
    "timestamp": "2026-03-07T15:00:00Z"
  }
}

200 Response (transfer executed):

{
  "success": true,
  "transferHash": "0xdef456...",
  "transferAmount": "0.0005"
}

200 Response (transfer skipped):

{
  "success": false,
  "skipped": true,
  "reason": "safe_not_found_or_automation_disabled"
}

Possible reason values when skipped:

ReasonDescription
worker_private_key_not_configuredBackend worker key not set
safe_not_found_or_automation_disabledSafe not found or hasAutomationModule = false or moduleEnabled = false
no_module_addressNo automationModuleAddress in DB
no_target_addressNo moduleTargetAddress in DB
token_mismatchReceived token doesn't match configured token
zero_transfer_amountCalculated transfer amount is 0

POST /system/automation-module/trigger

Cron endpoint that finds all eligible Safes and triggers reclaim operations based on frequency rules.

Authentication: API Key (x-api-key header)

Query parameters:

ParamTypeDefaultDescription
chainIdnumberall chainsFilter by chain ID
limitnumber10Max number of Safes to process

200 Response:

{
  "success": true,
  "processed": 2,
  "results": [
    {
      "safeAddress": "0xAbCdEf...",
      "blockchainId": 100,
      "status": "triggered",
      "targetAddress": "0x9988...",
      "percentage": 50
    },
    {
      "safeAddress": "0x112233...",
      "blockchainId": 100,
      "status": "error",
      "error": "Transaction reverted"
    }
  ]
}

7. Automation Config Update Endpoint

PUT /v1.2/safes/\{safeAddress\}/automation-module/config

Updates the automation module configuration for a Safe (off-chain parameters only — does not modify on-chain state).

Authentication: JWT (Bearer token)

Path parameters:

ParamTypeDescription
safeAddressstringSafe wallet address

Request body (all fields optional):

{
  "targetAddress": "0xNewTargetAddress...",
  "percentage": 75,
  "frequency": "DAILY",
  "tokenAddress": "0xcB444e90D8198415266c6a2724b7900fb12FC56E",
  "enabled": true
}
FieldTypeDescription
targetAddressstringNew destination address for auto-transfers
percentagenumberNew percentage (0–100)
frequencystring"DAILY", "WEEKLY", "90_DAYS", or "NONE"
tokenAddressstringERC-20 token filter (0x0...0 for any token)
enabledbooleanEnable/disable the module without removing it

200 Response:

{
  "success": true,
  "updated": ["targetAddress", "percentage"]
}

8. Database Impact

Safe Table

When the automation module is enabled or configured, the following columns are affected:

ColumnTypeSet WhenDescription
hasAutomationModuleBooleanAfter on-chain batch-execute confirmationtrue once the module is activated on-chain
automationModuleAddressStringDuring batch-intent (pre-execution)Address of the global Allowance Module contract
moduleTargetAddressStringDuring batch-intentDestination address for auto-transfers
modulePercentageIntDuring batch-intentPercentage (0–100) to auto-transfer
moduleFrequencyStringDuring batch-intent"DAILY", "WEEKLY", "90_DAYS", or "NONE"
moduleCreationDateDateTimeOn activationTimestamp of module activation
moduleEnabledBooleanDefault true, toggleable via config endpointSoft enable/disable switch
moduleTokenAddressStringDuring batch-intentERC-20 token address for allowance (0x0...0 = any)
moduleMaxAllowanceStringDuring batch-intentMax allowance amount (string representation of BigInt)
moduleResetTimeMinStringDuring batch-intentOn-chain resetTimeMin (minutes between resets)
moduleResetBaseMinStringDuring batch-intentOn-chain resetBaseMin (always "0")
moduleLastTriggeredAtDateTimeAfter each auto-transfer or cron triggerTimestamp of the last automatic transfer execution

Write sequence during ENABLE_AUTOMATION_MODULE:

  1. batch-intent (Step 1): Pre-stores automationModuleAddress, moduleTargetAddress, modulePercentage, moduleFrequency, moduleTokenAddress, moduleMaxAllowance, moduleResetTimeMin, moduleResetBaseMin on the Safe record. hasAutomationModule remains false.
  2. batch-execute (Step 2): After on-chain confirmation, sets hasAutomationModule = true.
  3. on-token-received (auto-transfer): Updates moduleLastTriggeredAt to the current timestamp.

Chains Table

ColumnTypeDescription
automationModuleAddressStringGlobal Allowance Module contract address for this chain (set during seed/migration)

SafeOperation Table

Each batch-intent + batch-execute creates one SafeOperation record:

ColumnTypeDescription
userOpHashString (PK)ERC-4337 UserOperation hash
safeAddressStringAssociated Safe
blockchainIdIntChain ID
statusEnumCREATEDSIGNEDEXECUTEDCONFIRMED (or FAILED)
transactionHashString?On-chain transaction hash (set after execution)
paymasterEnumAlways SPONSORED

Operation Table

Each individual operation within a batch creates one Operation record:

ColumnTypeDescription
typeEnum (OperationType)e.g. ENABLE_AUTOMATION_MODULE, ADD_OWNER, ENABLE_RECOVERY
indexIntPosition within the batch (0-based)
dataJSONContains params (original request) and encoded (on-chain tx data: to, data, operation, value)

Recovery-Specific Database Impact

Column (on Safe)TypeSet WhenDescription
hasRecoveryBooleanAfter on-chain confirmation of ENABLE_RECOVERYtrue once recovery module is active
recoveryModuleAddressStringAfter on-chain confirmationAddress of the recovery module contract

Note: Personal data (firstName, lastName, etc.) submitted with ENABLE_RECOVERY is stored temporarily in the Operation.data JSON during processing, then purged (set to \{\}) after the recovery is registered with the IBEX Safe service.


Full Example: Enable Automation Module (End-to-End)

1. Prepare the operation

curl -X POST "https://api.ibex.fi/v1.2/safes/operations/batch-intent" \
  -H "Authorization: Bearer eyJhbGciOiJFUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -H "X-Blockchain-Id: 100" \
  -d '{
    "safeAddress": "0xAbCdEf1234567890AbCdEf1234567890AbCdEf12",
    "chainId": 100,
    "operations": [{
      "type": "ENABLE_AUTOMATION_MODULE",
      "targetAddress": "0x9988776655443322110099887766554433221100",
      "percentage": 50,
      "frequency": "NONE",
      "tokenAddress": "0xcB444e90D8198415266c6a2724b7900fb12FC56E"
    }]
  }'

Response:

{
  "batchId": "a1b2c3d4e5f6a1b2c3d4",
  "expiresAt": "2026-03-07T15:05:00.000Z",
  "operationCount": 1,
  "credentialRequestOptions": {
    "challenge": "dXNlck9wSGFzaEJhc2U2NHVybA",
    "timeout": 60000,
    "rpId": "ibex.fi",
    "userVerification": "required",
    "allowCredentials": [{ "id": "Y3JlZA", "type": "public-key" }]
  }
}

2. Sign with WebAuthn and execute

curl -X PUT "https://api.ibex.fi/v1.2/safes/operations/batch-execute" \
  -H "Authorization: Bearer eyJhbGciOiJFUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -H "X-Blockchain-Id: 100" \
  -d '{
    "batchId": "a1b2c3d4e5f6a1b2c3d4",
    "credential": {
      "id": "Y3JlZA",
      "rawId": "Y3JlZA",
      "type": "public-key",
      "response": {
        "authenticatorData": "SZYN5Y...",
        "clientDataJSON": "eyJ0eX...",
        "signature": "MEUCIQ..."
      }
    }
  }'

Response:

{
  "userOpHash": "0x1234abcd5678ef901234abcd5678ef901234abcd5678ef901234abcd5678ef90"
}

3. Poll status until confirmed

curl -X GET "https://api.ibex.fi/v1.2/safes/operations/0x1234abcd.../status" \
  -H "Authorization: Bearer eyJhbGciOiJFUzI1NiIs..." \
  -H "X-Blockchain-Id: 100"

Response:

{
  "userOpHash": "0x1234abcd...",
  "status": "CONFIRMED",
  "transactionHash": "0xdeadbeef...",
  "operations": [{ "index": 0, "type": "ENABLE_AUTOMATION_MODULE" }]
}

4. Automatic transfer triggers on deposit

When someone sends tokens to the Safe, the backend automatically transfers 50% to the configured targetAddress:

Deposit: 1.0 USDC.e → Safe
Auto-transfer: 0.5 USDC.e → targetAddress (via executeAllowanceTransfer)
Remaining: 0.5 USDC.e in Safe

5. Batch example: Multiple operations in one transaction

{
  "safeAddress": "0xAbCdEf...",
  "chainId": 100,
  "operations": [
    {
      "type": "ENABLE_AUTOMATION_MODULE",
      "targetAddress": "0x9988...",
      "percentage": 50,
      "frequency": "NONE",
      "tokenAddress": "0xcB444..."
    },
    {
      "type": "ADD_OWNER",
      "owner": "0xNewOwner...",
      "threshold": 2
    },
    {
      "type": "TRANSFER_TOKEN",
      "tokenAddress": "0xcB444...",
      "to": "0xRecipient...",
      "amount": "1000000"
    }
  ]
}

All three operations are bundled into a single MultiSend transaction requiring only one WebAuthn signature.


Appendix: Complete OperationType Enum

TRANSFER_EURe
TRANSFER_TOKEN
MONERIUM_CREATE_IBAN
MONERIUM_WITHDRAW_EURe
SIGN_MESSAGE
ENABLE_RECOVERY
INITIATE_RECOVERY
EXECUTE_RECOVERY
CANCEL_RECOVERY
AAVE_SUPPLY
AAVE_WITHDRAW
SWAP_FROM_QUOTE
ADD_OWNER
REMOVE_OWNER
CHANGE_THRESHOLD
ENABLE_AUTOMATION_MODULE