Files
smom-dbis-138/contracts/emoney/AccountWalletRegistry.sol
defiQUG 1fb7266469 Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control.
- Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities.
- Created .gitmodules to include OpenZeppelin contracts as a submodule.
- Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment.
- Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks.
- Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring.
- Created scripts for resource import and usage validation across non-US regions.
- Added tests for CCIP error handling and integration to ensure robust functionality.
- Included various new files and directories for the orchestration portal and deployment scripts.
2025-12-12 14:57:48 -08:00

150 lines
6.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./interfaces/IAccountWalletRegistry.sol";
/**
* @title AccountWalletRegistry
* @notice Maps regulated fiat accounts (IBAN, ABA) to Web3 wallets
* @dev Stores hashed account references (no PII on-chain). Supports 1-to-many mappings.
*/
contract AccountWalletRegistry is IAccountWalletRegistry, AccessControl {
bytes32 public constant ACCOUNT_MANAGER_ROLE = keccak256("ACCOUNT_MANAGER_ROLE");
// accountRefId => array of wallet links
mapping(bytes32 => WalletLink[]) private _accountToWallets;
// walletRefId => array of accountRefIds
mapping(bytes32 => bytes32[]) private _walletToAccounts;
// accountRefId => walletRefId => index in _accountToWallets array
mapping(bytes32 => mapping(bytes32 => uint256)) private _walletIndex;
// walletRefId => accountRefId => exists flag
mapping(bytes32 => mapping(bytes32 => bool)) private _walletAccountExists;
/**
* @notice Initializes the registry with an admin address
* @param admin Address that will receive DEFAULT_ADMIN_ROLE
*/
constructor(address admin) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
}
/**
* @notice Links an account to a wallet
* @dev Requires ACCOUNT_MANAGER_ROLE. Creates a new link or reactivates an existing one.
* @param accountRefId The hashed account reference ID
* @param walletRefId The hashed wallet reference ID
* @param provider The provider identifier (e.g., "METAMASK", "FIREBLOCKS")
*/
function linkAccountToWallet(
bytes32 accountRefId,
bytes32 walletRefId,
bytes32 provider
) external override onlyRole(ACCOUNT_MANAGER_ROLE) {
require(accountRefId != bytes32(0), "AccountWalletRegistry: zero accountRefId");
require(walletRefId != bytes32(0), "AccountWalletRegistry: zero walletRefId");
require(provider != bytes32(0), "AccountWalletRegistry: zero provider");
// Check if link already exists
if (_walletAccountExists[walletRefId][accountRefId]) {
// Reactivate existing link
uint256 index = _walletIndex[accountRefId][walletRefId];
require(index < _accountToWallets[accountRefId].length, "AccountWalletRegistry: index out of bounds");
WalletLink storage link = _accountToWallets[accountRefId][index];
require(link.walletRefId == walletRefId, "AccountWalletRegistry: link mismatch");
link.active = true;
link.linkedAt = uint64(block.timestamp);
} else {
// Create new link
WalletLink memory newLink = WalletLink({
walletRefId: walletRefId,
linkedAt: uint64(block.timestamp),
active: true,
provider: provider
});
_accountToWallets[accountRefId].push(newLink);
_walletIndex[accountRefId][walletRefId] = _accountToWallets[accountRefId].length - 1;
_walletAccountExists[walletRefId][accountRefId] = true;
// Add to reverse mapping
_walletToAccounts[walletRefId].push(accountRefId);
}
emit AccountWalletLinked(accountRefId, walletRefId, provider, uint64(block.timestamp));
}
/**
* @notice Unlinks an account from a wallet (deactivates the link)
* @dev Requires ACCOUNT_MANAGER_ROLE. Sets link to inactive but doesn't remove it.
* @param accountRefId The hashed account reference ID
* @param walletRefId The hashed wallet reference ID
*/
function unlinkAccountFromWallet(
bytes32 accountRefId,
bytes32 walletRefId
) external override onlyRole(ACCOUNT_MANAGER_ROLE) {
require(accountRefId != bytes32(0), "AccountWalletRegistry: zero accountRefId");
require(walletRefId != bytes32(0), "AccountWalletRegistry: zero walletRefId");
require(_walletAccountExists[walletRefId][accountRefId], "AccountWalletRegistry: link not found");
uint256 index = _walletIndex[accountRefId][walletRefId];
require(index < _accountToWallets[accountRefId].length, "AccountWalletRegistry: index out of bounds");
WalletLink storage link = _accountToWallets[accountRefId][index];
require(link.walletRefId == walletRefId, "AccountWalletRegistry: link mismatch");
link.active = false;
emit AccountWalletUnlinked(accountRefId, walletRefId);
}
/**
* @notice Returns all wallet links for an account
* @param accountRefId The hashed account reference ID
* @return Array of wallet links
*/
function getWallets(bytes32 accountRefId) external view override returns (WalletLink[] memory) {
return _accountToWallets[accountRefId];
}
/**
* @notice Returns all account references for a wallet
* @param walletRefId The hashed wallet reference ID
* @return Array of account reference IDs
*/
function getAccounts(bytes32 walletRefId) external view override returns (bytes32[] memory) {
return _walletToAccounts[walletRefId];
}
/**
* @notice Checks if an account and wallet are linked
* @param accountRefId The hashed account reference ID
* @param walletRefId The hashed wallet reference ID
* @return true if linked (regardless of active status)
*/
function isLinked(bytes32 accountRefId, bytes32 walletRefId) external view override returns (bool) {
return _walletAccountExists[walletRefId][accountRefId];
}
/**
* @notice Checks if an account and wallet are actively linked
* @param accountRefId The hashed account reference ID
* @param walletRefId The hashed wallet reference ID
* @return true if linked and active
*/
function isActive(bytes32 accountRefId, bytes32 walletRefId) external view override returns (bool) {
if (!_walletAccountExists[walletRefId][accountRefId]) {
return false;
}
uint256 index = _walletIndex[accountRefId][walletRefId];
if (index >= _accountToWallets[accountRefId].length) {
return false;
}
WalletLink memory link = _accountToWallets[accountRefId][index];
return link.active && link.walletRefId == walletRefId;
}
}