R25 Contract Integration Guide
1. Understand the Two Operating Models
Vaults operate in either synchronous or asynchronous mode.
Synchronous Vault:
User approval -> Deposit/Redeem -> Transaction confirmation -> Assets or Shares are delivered immediately
Asynchronous Vault:
User submits a request
-> Pending (waiting for keeper processing)
-> Settled (the keeper settles the request and the Assets or Shares have been delivered)
For an asynchronous Vault:
requestDeposit/requestRedeemsubmit requests.settleDeposit/settleRedeemare called by a keeper to settle requests.- There is no separate user claim step. Claim-style entry points such as
deposit/redeemrevert. - The current implementation has no
Claimable/Claimedstates and no standaloneRequestManager.
An asynchronous request is not finally priced when it is submitted. The final amount of Shares or Assets is determined by the keeper settlement result.
2. Common Parameters
| Parameter | Description |
|---|---|
assets | Amount of the underlying Asset, such as USDC, expressed using the Asset Token's decimals |
shares | Amount of Vault Shares, expressed using the ShareToken's decimals |
receiver | Address that ultimately receives Shares or underlying Assets in a synchronous flow |
owner | Address that provides the Assets or Shares |
controller | Controller of an asynchronous request, used for request queries and business attribution |
inviteCode | Optional referral or channel code used only for attribution |
requestId | Asynchronous request ID; deposit and redeem request IDs increment independently |
The Asset Token and ShareToken may use different decimals. Integrators must read them separately.
3. Prerequisites
Deposits
- The user has sufficient Assets.
- If the Vault has a deposit window, deposits are currently open.
- If the Vault has amount limits, the amount satisfies the minimum, maximum, and total-cap limits.
- If the Vault has a whitelist, the whitelist check passes.
- The user has approved the Vault to spend the Assets.
- The current Vault price is valid.
Approval:
asset.approve(vault, assets);
The spender must be the Vault address.
Whitelist target:
| Scenario | Address that must be whitelisted |
|---|---|
| A user wallet calls a synchronous Vault directly | The user wallet, i.e. msg.sender |
| A project contract calls a synchronous Vault on the user's behalf | The project contract, i.e. msg.sender |
Asynchronous requestDeposit | The Asset provider, i.e. owner |
Redemptions
- The user has sufficient Shares.
- If the Vault has a redemption window, redemptions are currently open.
- If the Vault has a lock-up period, the product is no longer locked.
- If the Vault has redemption limits, the amount satisfies those limits.
- The current Vault price is valid.
Redemptions do not check the deposit whitelist.
A user redeeming their own Shares does not need an additional approval. If a project contract calls a synchronous redemption on the user's behalf, the user must approve the project contract:
share.approve(projectContract, shares);
Delegated permissions in asynchronous flows:
| Operation | Authorized caller |
|---|---|
| Submit a deposit or redeem request | The owner, or an operator authorized by the owner |
| Cancel a request | The current implementation allows the owner, or an operator authorized by the owner |
| Settle a request | A keeper, i.e. an address with VAULT_KEEPER_ROLE |
Operator authorization:
vault.setOperator(projectContract, true);
Event Addresses
Relevant events for a Vault transaction may be emitted by three contracts:
| Contract | How to obtain the address | Main events |
|---|---|---|
| Asset Token | vault.asset() | Approval, Asset Transfer |
| ShareToken | vault.share() | Share Approval, Share Transfer |
| CoreVaultSync / CoreVaultAsync | Current Vault address | Deposit, Withdraw, DepositRequest, RedeemRequest, DepositRequestSettled, RedeemRequestSettled, DepositRequestCancelled, RedeemRequestCancelled, ReferralRecorded, OperatorSet |
The current implementation has no standalone RequestManager and no vault.requestManager(). Integrators must not monitor only the Vault address, or they will miss token transfer events emitted by the Asset Token and ShareToken.
4. Synchronous Deposits
4.1 Recommended Interface: User Specifies the Asset Amount
function deposit(
uint256 assets,
address receiver
) external returns (uint256 shares);
Version with a referral code:
function deposit(
uint256 assets,
address receiver,
string calldata inviteCode
) external returns (uint256 shares);
| Parameter | Description |
|---|---|
assets | Amount of Assets deposited by the user |
receiver | Address receiving the Shares |
inviteCode | Optional referral or channel code |
Returned shares | Actual number of Shares received by receiver |
Call sequence:
- Call
previewDeposit(assets)to estimate the number of Shares. - The user calls
asset.approve(vault, assets). - Call
deposit(assets, receiver). - Monitor the
Depositevent. - After receiving
Deposit, mark the deposit order as completed.
Events in the flow:
| Event | Emitting contract | Meaning |
|---|---|---|
Asset Approval | Asset Token | The user has approved the Vault to spend Assets; this does not mean the deposit is complete |
Asset Transfer | Asset Token | Assets have moved from the user to the Vault custody address |
Share Transfer(0, receiver, shares) | ShareToken | Shares have been minted to receiver |
Vault Deposit | CoreVaultSync | The synchronous deposit is complete |
ReferralRecorded | CoreVaultSync | The referral code has been recorded for attribution only |
4.2 Optional Interface: User Specifies the Target Number of Shares
function mint(
uint256 shares,
address receiver
) external returns (uint256 assets);
| Parameter | Description |
|---|---|
shares | Number of Shares the user wants to receive |
receiver | Address receiving the Shares |
Returned assets | Actual amount of Assets paid by the user |
Before calling, use previewMint(shares) to estimate the required Asset amount.
For ordinary user deposits, deposit is recommended.
5. Synchronous Redemptions
5.1 Recommended Interface: User Specifies the Number of Shares to Redeem
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
| Parameter | Description |
|---|---|
shares | Number of Shares used in this redemption |
receiver | Address receiving the Assets |
owner | Owner of the Shares |
Returned assets | Actual amount of Assets received by receiver |
Call sequence:
- Call
previewRedeem(shares)to estimate the Asset amount. - No Share approval is required when the user calls for their own Shares.
- For a delegated call, the
ownerfirst approves the project contract to use the Shares. - Call
redeem(shares, receiver, owner). - Monitor the
Withdrawevent. - After receiving
Withdraw, mark the redemption order as completed.
Events in the flow:
| Event | Emitting contract | Meaning |
|---|---|---|
Share Transfer(owner, 0, sharesToBurn) | ShareToken | The net Shares used for redemption have been burned after deducting any Share-denominated redemption fee |
Share Transfer(owner, feeReceiver, feeShares) | ShareToken | If a Share-denominated redemption fee applies, the fee Shares have been transferred |
Asset Transfer(..., receiver, assets) | Asset Token | Assets have been sent to receiver |
Vault Withdraw | CoreVaultSync | The synchronous redemption is complete |
When a Share-denominated redemption fee is enabled, the input shares is split into feeShares and sharesToBurn. The order result must be determined from the Vault's Withdraw event, not inferred from a single Share Transfer event.
5.2 Optional Interface: User Specifies the Target Asset Amount
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
| Parameter | Description |
|---|---|
assets | Amount of Assets the user wants to receive |
receiver | Address receiving the Assets |
owner | Owner of the Shares |
Returned shares | Actual number of Shares used |
Before calling, use previewWithdraw(assets) to estimate the required number of Shares.
For ordinary user redemptions, redeem is recommended.
6. Asynchronous Deposits
6.1 Submit a Request
function requestDeposit(
uint256 assets,
address controller,
address owner
) external returns (uint256 requestId);
Version with a referral code:
function requestDeposit(
uint256 assets,
address controller,
address owner,
string calldata inviteCode
) external returns (uint256 requestId);
| Parameter | Description |
|---|---|
assets | Amount of Assets locked from owner |
controller | Controller of the request |
owner | User providing the Assets and the address checked against the whitelist |
inviteCode | Optional referral or channel code |
Returned requestId | Deposit request ID |
For a user acting directly, the usual values are:
controller = user address
owner = user address
Call sequence:
- The user calls
asset.approve(vault, assets). - Call
requestDeposit(assets, controller, owner). - Monitor
DepositRequest, create the order, and set its status toPending. - Wait for a keeper to call
settleDeposit(requestId)orbatchSettleDeposits(requestIds). - Monitor
DepositRequestSettledandDeposit. - After receiving the settlement event, set the deposit order status to
Settled.
Before a project contract submits a request on behalf of owner, the owner must authorize it:
vault.setOperator(projectContract, true);
6.2 Keeper Settlement of Shares
function settleDeposit(
uint256 requestId
) external returns (uint256 shares);
Batch version:
function batchSettleDeposits(
uint256[] calldata requestIds
) external returns (uint256 shares);
| Parameter | Description |
|---|---|
requestId | ID of the deposit request to settle |
Returned shares | Actual number of Shares minted to owner |
In the current implementation, the keeper mints Shares directly to owner during settlement. The user neither needs nor is able to call deposit(assets, receiver, controller) afterward to claim them.
The following asynchronous Vault methods do not represent claimable amounts:
vault.maxDeposit(controller); // Returns 0
vault.claimableDepositRequest(id, user); // Returns 0
6.3 Business Events
| Stage | Event | Emitting contract | Business meaning | Order status |
|---|---|---|---|---|
| Request submission | Asset Transfer(owner, escrow, assets) | Asset Token | Assets have moved from owner to custody and are locked | Pending |
| Request submission | DepositRequest | CoreVaultAsync | Assets are locked and the deposit request has been submitted | Pending |
| Keeper settlement | DepositRequestSettled | CoreVaultAsync | Shares have been calculated using the current NAV and settled | Settled |
| Keeper settlement | Share Transfer(0, owner, shares) | ShareToken | Shares have been minted to owner | Settled |
| Keeper settlement | Vault Deposit | CoreVaultAsync | The asynchronous deposit settlement is complete | Settled |
7. Asynchronous Redemptions
7.1 Submit a Request
function requestRedeem(
uint256 shares,
address controller,
address owner
) external returns (uint256 requestId);
| Parameter | Description |
|---|---|
shares | Number of Shares locked from owner |
controller | Controller of the request |
owner | Owner of the Shares |
Returned requestId | Redeem request ID |
For a user acting directly, the usual values are:
controller = user address
owner = user address
Call sequence:
- Call
requestRedeem(shares, controller, owner). - Monitor
RedeemRequest, create the order, and set its status toPending. - Wait for a keeper to call
settleRedeem(requestId)orbatchSettleRedeems(requestIds). - Monitor
RedeemRequestSettledandWithdraw. - After receiving the settlement event, set the redemption order status to
Settled.
No additional Share approval is required when the user calls directly or an authorized operator calls on the user's behalf. Before a project contract calls on behalf of the user, the recommended authorization is:
vault.setOperator(projectContract, true);
7.2 Keeper Settlement of Assets
function settleRedeem(
uint256 requestId
) external returns (uint256 assets);
Batch version:
function batchSettleRedeems(
uint256[] calldata requestIds
) external returns (uint256 assets);
| Parameter | Description |
|---|---|
requestId | ID of the redeem request to settle |
Returned assets | Actual amount of Assets sent to owner |
In the current implementation, the keeper sends Assets directly to owner during settlement. The user neither needs nor is able to call redeem(shares, receiver, controller) afterward to claim them.
The following asynchronous Vault methods do not represent claimable amounts:
vault.maxRedeem(controller); // Returns 0
vault.claimableRedeemRequest(id, user); // Returns 0
7.3 Business Events
| Stage | Event | Emitting contract | Business meaning | Order status |
|---|---|---|---|---|
| Request submission | Share Transfer(owner, escrow, shares) | ShareToken | Shares are locked | Pending |
| Request submission | RedeemRequest | CoreVaultAsync | The redeem request has been submitted | Pending |
| Keeper settlement | RedeemRequestSettled | CoreVaultAsync | Assets have been calculated using the current NAV and settled | Settled |
| Keeper settlement | Share Transfer(escrow, feeReceiver, feeShares) | ShareToken | If a Share-denominated redemption fee applies, the fee Shares have been transferred | Settled |
| Keeper settlement | Share Transfer(escrow, 0, sharesToBurn) | ShareToken | The net Shares have been burned after deducting the redemption fee | Settled |
| Keeper settlement | Asset Transfer(..., owner, assets) | Asset Token | Assets have been sent to owner | Settled |
| Keeper settlement | Vault Withdraw | CoreVaultAsync | The asynchronous redemption settlement is complete | Settled |
The result of an asynchronous redemption must be determined from the RedeemRequestSettled and Withdraw events, not inferred from a single Share Transfer event.
8. Cancel an Asynchronous Request
Cancel a deposit request:
function cancelDepositRequest(
uint256 requestId
) external returns (uint256 assets);
Cancel a redeem request:
function cancelRedeemRequest(
uint256 requestId
) external returns (uint256 shares);
| Parameter | Description |
|---|---|
requestId | ID of the request to cancel |
Returned assets | Assets refunded when a deposit request is cancelled |
Returned shares | Shares refunded when a redeem request is cancelled |
Rules:
- The current implementation allows the
owner, or an operator authorized by theowner, to cancel. - Only a
Pendingrequest can be cancelled. - A
Settledrequest cannot be cancelled. - Cancelling a deposit request returns the Assets to
owner. - Cancelling a redeem request returns the Shares to
owner.
Events:
event DepositRequestCancelled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 assets
);
event RedeemRequestCancelled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 shares
);
Refund transfer events:
- Cancel deposit: the Asset Token emits
Transfer(escrow, owner, assets). - Cancel redeem: the ShareToken emits
Transfer(escrow, owner, shares).
After receiving DepositRequestCancelled or RedeemRequestCancelled, set the order status to Cancelled.
9. Main Event Parameters
Deposit
Emitted by CoreVaultSync or CoreVaultAsync.
event Deposit(
address indexed sender,
address indexed owner,
uint256 assets,
uint256 shares
);
| Parameter | Description |
|---|---|
sender | The actual caller for a synchronous deposit; the keeper for an asynchronous settlement |
owner | The Share receiver for a synchronous deposit; the request owner for an asynchronous settlement |
assets | Asset amount associated with this deposit or settlement |
shares | Actual number of Shares received |
Withdraw
Emitted by CoreVaultSync or CoreVaultAsync.
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
| Parameter | Description |
|---|---|
sender | The actual caller for a synchronous redemption; the keeper for an asynchronous settlement |
receiver | The Asset receiver for a synchronous redemption; the request owner for an asynchronous settlement |
owner | The Share owner for a synchronous redemption; the request owner for an asynchronous settlement |
assets | Actual amount of Assets sent |
shares | Actual number of Shares used or locked |
DepositRequest
Emitted by CoreVaultAsync.
event DepositRequest(
address indexed controller,
address indexed owner,
uint256 indexed requestId,
address sender,
uint256 assets
);
| Parameter | Description |
|---|---|
controller | Controller of the request |
owner | Asset provider |
requestId | Request ID |
sender | User or project contract that actually submitted the transaction |
assets | Amount of Assets locked for the deposit request |
RedeemRequest
Emitted by CoreVaultAsync.
event RedeemRequest(
address indexed controller,
address indexed owner,
uint256 indexed requestId,
address sender,
uint256 shares
);
| Parameter | Description |
|---|---|
controller | Controller of the request |
owner | Owner of the Shares |
requestId | Request ID |
sender | User or project contract that actually submitted the transaction |
shares | Number of Shares locked for the redeem request |
DepositRequestSettled
Emitted by CoreVaultAsync.
event DepositRequestSettled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 assets,
uint256 shares
);
This event means the deposit request has been settled and the Shares have been minted directly to owner.
RedeemRequestSettled
Emitted by CoreVaultAsync.
event RedeemRequestSettled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 shares,
uint256 assets
);
This event means the redeem request has been settled and the Assets have been sent directly to owner.
Cancellation Events
Emitted by CoreVaultAsync.
event DepositRequestCancelled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 assets
);
event RedeemRequestCancelled(
uint256 indexed requestId,
address indexed controller,
address indexed owner,
uint256 shares
);
Token and Authorization Events
| Event | Emitting contract | Parameter meaning |
|---|---|---|
Approval(owner, spender, value) | Asset Token or ShareToken | owner authorizes spender to use value tokens |
Transfer(from, to, value) | Asset Token or ShareToken | value Assets or Shares move from from to to |
ReferralRecorded(sender, referralCode) | CoreVaultSync or CoreVaultAsync | sender used referralCode; attribution only |
OperatorSet(controller, operator, approved) | CoreVaultAsync | controller grants or revokes delegated access for operator |
10. Order Status Updates
| Business event | Emitting contract | Integrator order status |
|---|---|---|
Synchronous Deposit | CoreVaultSync | Completed |
Synchronous Withdraw | CoreVaultSync | Completed |
DepositRequest / RedeemRequest | CoreVaultAsync | Pending |
DepositRequestSettled / RedeemRequestSettled | CoreVaultAsync | Settled |
DepositRequestCancelled / RedeemRequestCancelled | CoreVaultAsync | Cancelled |
The recommended unique business key for an asynchronous order is:
(chainId, vault, requestType, requestId)
Use requestType to distinguish deposit from redeem, because deposit and redeem request IDs increment independently in this implementation.
11. Contract ABIs
The following smart contract ABI (Application Binary Interface) JSON files are available for download: