> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Portal

> The EVM entry point for publishing, funding, fulfilling, proving, withdrawing, and refunding intents.

The **Portal** combines the source-chain `IntentSource` and destination-chain `Inbox` implementations. It coordinates an intent's lifecycle while per-intent vaults hold its reward.

This reference describes the [Routes 2.12.0 source](https://github.com/eco/eco-routes/tree/ea5111ba0cd644089d04f922e05a5253dbd21fb8/contracts). Use the ABI for your deployed version.

## Prerequisites

* The source and destination Portal addresses and their matching ABIs.
* The complete intent, including its route, reward, and deadlines.
* RPC access and funds for transaction gas on each chain you submit to.
* For fulfillment, the route tokens and any prover message fees.

API integrations should start with the returned `execution` object instead of reconstructing contract calldata. See [Integrate the Routes API](/get-started/integrate-routes-api).

## Source-chain operations

| Operation | Behavior |
| - | - |
| `publish` | Emit the intent without requiring full funding |
| `publishAndFund` | Publish and fund in one transaction |
| `publishAndFundFor` | Publish and fund on behalf of a funder, with an optional permit contract |
| `fund`, `fundFor` | Fund an existing intent, optionally allowing partial funding |
| `intentVaultAddress` | Compute the deterministic vault address |
| `isIntentFunded` | Check whether the required rewards are funded |
| `getIntentHash` | Compute the intent, route, and reward hashes |
| `getRewardStatus` | Read the reward lifecycle state |

Several methods have struct and encoded-route overloads. Use the deployed ABI to select the correct overload. A raw ERC-20 transfer to a vault can fund its balance without emitting `IntentFunded`; check funding rather than relying only on that event.

`IntentPublished` can be emitted more than once for the same active intent. Deduplicate by intent hash and handle chain reorganizations when indexing events.

## Destination-chain fulfillment

`fulfill` accepts the intent hash, decoded route, reward hash, and claimant. The Portal checks the route's deadline, Portal address, hash, and fulfillment state. It then transfers `route.tokens` from the caller to the Executor and runs `route.calls`.

The caller must approve the destination Portal for those tokens and supply at least `route.nativeAmount`. The claimant identifies the account that will receive the source-chain reward; it is not necessarily the transaction sender.

`fulfillAndProve` combines fulfillment with a call to the selected destination-side prover. `prove` can initiate proving separately for one or more fulfilled intent hashes.

The prover's `sourceChainDomainID` may differ from the chain ID. Derive it from the selected prover's configuration. Message fees and prover-specific data are also part of that integration.

## Withdrawal and refunds

| Operation | Behavior |
| - | - |
| `withdraw` | Read `reward.prover`, check its claimant and destination, and release the reward |
| `batchWithdraw` | Withdraw several rewards; array lengths must match |
| `refund` | Refund eligible assets to `reward.creator`; any account can submit the call |
| `refundTo` | Refund eligible assets to another address; only `reward.creator` can call it |
| `recoverToken` | Recover an ERC-20 token outside the reward to the creator |

For an unproven intent, refund eligibility begins at `reward.deadline`. The 2.12.0 Portal also recognizes a proven cancellation: after `route.deadline`, any account can call `cancel` or `cancelAndProve` on the destination Portal for an unfulfilled intent, and once that cancellation is proven on the source chain the refund is available before `reward.deadline`. Cancellation alone does not release funds. See [Refunds by intent type](/resources/intent-types#refunds) for what each route shape returns.

Expiry does not automatically execute a refund. Check the transaction outcome and returned balances. See [Vault](/routes/architecture/vault) for payout details.

## Events and state

| Signal | Meaning |
| - | - |
| `IntentPublished` | Intent data was published; it may still need funding |
| `IntentFunded` | Funding was attempted, with a flag indicating completion |
| `IntentFulfilled` | The destination transaction recorded fulfillment |
| `IntentProven` | A proving operation emitted its result; interpret it in the emitting contract's context |
| `IntentWithdrawn` | The source reward was withdrawn |
| `IntentRefunded` | The source refund operation executed |

The contract reward states are `Initial`, `Funded`, `Withdrawn`, and `Refunded`. They are distinct from the API's aggregated transfer statuses.

## Troubleshooting

| Error or symptom | Check |
| - | - |
| `InsufficientFunds` | Vault balances, approvals, and whether partial funding is allowed |
| `InvalidPortal` or `InvalidHash` | Destination deployment and exact route/reward encoding |
| `IntentExpired` | Destination route deadline |
| `IntentAlreadyFulfilled` | Existing destination claimant and transaction history |
| `InsufficientNativeAmount` | Route native amount and any message fee |
| `InvalidStatusForWithdrawal` | Whether the reward has already been withdrawn or refunded |
| `InvalidStatusForRefund` | Reward deadline and current state |
| `IntentNotClaimed` during refund | A valid fulfillment proof exists while the reward remains unclaimed |

Simulate the complete transaction and estimate gas using current chain state before submitting it.

## Next steps

Read [Vault](/routes/architecture/vault), [Executor](/routes/architecture/executor), or [ERC-7683](/routes/architecture/erc-7683) for the corresponding contract surface.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.