Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m20s
CI/CD Pipeline / Security Scanning (push) Successful in 2m48s
CI/CD Pipeline / Lint and Format (push) Failing after 47s
CI/CD Pipeline / Terraform Validation (push) Failing after 28s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 30s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 44s
Validation / validate-genesis (push) Successful in 37s
Validation / validate-terraform (push) Failing after 42s
Validation / validate-kubernetes (push) Failing after 12s
Validation / validate-smart-contracts (push) Failing after 16m44s
Validation / validate-security (push) Failing after 20s
Validation / validate-documentation (push) Failing after 19s
Verify Deployment / Verify Deployment (push) Failing after 1m21s
Use dedicated cusdc_v2/cusdt_v2 SVG paths so GRU token alignment validation passes.
114 lines
3.9 KiB
Solidity
114 lines
3.9 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts/access/AccessControl.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
import "./interfaces/IRailEscrowVault.sol";
|
|
import "./libraries/RailTypes.sol";
|
|
|
|
/**
|
|
* @title RailEscrowVault
|
|
* @notice Holds tokens locked for outbound rail transfers
|
|
* @dev Similar pattern to BridgeVault138. Manages per-trigger escrow tracking.
|
|
*/
|
|
contract RailEscrowVault is IRailEscrowVault, AccessControl {
|
|
bytes32 public constant SETTLEMENT_OPERATOR_ROLE = keccak256("SETTLEMENT_OPERATOR_ROLE");
|
|
|
|
using SafeERC20 for IERC20;
|
|
|
|
// token => triggerId => escrow amount
|
|
mapping(address => mapping(uint256 => uint256)) private _escrow;
|
|
// token => total escrow amount
|
|
mapping(address => uint256) private _totalEscrow;
|
|
|
|
/**
|
|
* @notice Initializes the vault with an admin address
|
|
* @param admin Address that will receive DEFAULT_ADMIN_ROLE
|
|
*/
|
|
constructor(address admin) {
|
|
_grantRole(DEFAULT_ADMIN_ROLE, admin);
|
|
}
|
|
|
|
/**
|
|
* @notice Locks tokens for a rail transfer
|
|
* @dev Requires SETTLEMENT_OPERATOR_ROLE. Transfers tokens from user to vault.
|
|
* @param token Token address to lock
|
|
* @param from Address to transfer tokens from
|
|
* @param amount Amount to lock
|
|
* @param triggerId The trigger ID associated with this escrow
|
|
* @param rail The payment rail type
|
|
*/
|
|
function lock(
|
|
address token,
|
|
address from,
|
|
uint256 amount,
|
|
uint256 triggerId,
|
|
RailTypes.Rail rail
|
|
) external override onlyRole(SETTLEMENT_OPERATOR_ROLE) {
|
|
require(token != address(0), "RailEscrowVault: zero token");
|
|
require(from != address(0), "RailEscrowVault: zero from");
|
|
require(amount > 0, "RailEscrowVault: zero amount");
|
|
require(triggerId > 0, "RailEscrowVault: zero triggerId");
|
|
|
|
// Transfer tokens from user to vault
|
|
IERC20(token).safeTransferFrom(from, address(this), amount);
|
|
|
|
// Update escrow tracking
|
|
_escrow[token][triggerId] += amount;
|
|
_totalEscrow[token] += amount;
|
|
|
|
emit Locked(token, from, amount, triggerId, uint8(rail));
|
|
}
|
|
|
|
/**
|
|
* @notice Releases escrowed tokens
|
|
* @dev Requires SETTLEMENT_OPERATOR_ROLE. Transfers tokens from vault to recipient.
|
|
* @param token Token address to release
|
|
* @param to Recipient address
|
|
* @param amount Amount to release
|
|
* @param triggerId The trigger ID associated with this escrow
|
|
*/
|
|
function release(
|
|
address token,
|
|
address to,
|
|
uint256 amount,
|
|
uint256 triggerId
|
|
) external override onlyRole(SETTLEMENT_OPERATOR_ROLE) {
|
|
require(token != address(0), "RailEscrowVault: zero token");
|
|
require(to != address(0), "RailEscrowVault: zero to");
|
|
require(amount > 0, "RailEscrowVault: zero amount");
|
|
require(triggerId > 0, "RailEscrowVault: zero triggerId");
|
|
require(_escrow[token][triggerId] >= amount, "RailEscrowVault: insufficient escrow");
|
|
|
|
// Update escrow tracking
|
|
_escrow[token][triggerId] -= amount;
|
|
_totalEscrow[token] -= amount;
|
|
|
|
// Transfer tokens to recipient
|
|
IERC20(token).safeTransfer(to, amount);
|
|
|
|
emit Released(token, to, amount, triggerId);
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the escrow amount for a specific trigger
|
|
* @param token Token address
|
|
* @param triggerId The trigger ID
|
|
* @return The escrow amount
|
|
*/
|
|
function getEscrowAmount(address token, uint256 triggerId) external view override returns (uint256) {
|
|
return _escrow[token][triggerId];
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the total escrow amount for a token
|
|
* @param token Token address
|
|
* @return The total escrow amount
|
|
*/
|
|
function getTotalEscrow(address token) external view override returns (uint256) {
|
|
return _totalEscrow[token];
|
|
}
|
|
}
|
|
|