A comprehensive system for managing Custody Agreements (CA) across multiple EVM chains with secure proof of possession verification.
The system consists of three main components:
- OTCCustody: Core contract for CA (Proof of Possession Management) operations and actions including Custody Agreement (CA) management, deployment and whitelisting of various Connectors, calling various actions on Connectors including cross-chain interactions, and funds management between custodies.
- Connector: User-centric smart manager accounts that can be used to manage CA operations integrated with multiple DeFi protocols including Across, CCIP, AAVE, Uniswap V3, and more.
- CA (Custody Agreement): A data structure representing the custody relationship between parties, including:
- Proof of possession verification
- Token custody details
- Cross-chain state management
OTCCustody.sol
: Main contract for core business logic including CA management, Connector whitelisting, and other actions on custodies.CCIPConnector.sol
: Handles cross-chain message passing for cross-chain CA updatesCCIPReceiver.sol
: Receives and processes cross-chain messagesUniswapV3Connector.sol
: Uniswap V3 Connector implementationAcrossConnector.sol
: Across Protocol Connector implementation (V3)
01-otcCustody.test.ts
: Core OTCCustody functionality tests02-etf-operations.test.ts
: ETF-specific operations03-settlement.test.ts
: Settlement system tests04-ca-helper.test.ts
: CAHelper utility tests05-uniswap-v3-connector.test.ts
: Uniswap V3 Connector integration tests06-ccip-connector.test.ts
: CCIP Connector integration tests08-across-connector.test.ts
: Across Connector integration tests
06-ccip-ca-update.ts
: Cross-chain CA update script (Currently working on SepoliaBase testnet)07-across-deposit.ts
: Script for Across's deposit and relay functions (Currently working on SepoliaBase testnet and handled by MockSpokePool)
CAHelper.ts
: Helper class for CA operations including Merkle proof generation and verification.
The core contract that:
- Manages CA lifecycle
- Verifies proof of possession
- Handles token custody
- Coordinates with Connectors
A bridge adapter that handles cross-chain operations:
- Message passing between chains
- Token bridging
- State synchronization
A data structure representing the custody relationship between parties, including:
- Proof of possession verification
- Token custody details
- Cross-chain state management
- Node.js >= 18
- pnpm (recommended) or npm
- Hardhat
- Solidity ^0.8.28
# Clone the repository
git clone https://github.com/FundMakerFdn/evm-contracts.git
cd evm-contracts
# Install dependencies
pnpm install
# Compile contracts
pnpm compile
Create a .env
file:
PRIVATE_KEY=your_private_key
ARBITRUM_RPC_URL=your_arbitrum_rpc
BASE_RPC_URL=your_base_rpc
ETHERSCAN_API_KEY=your_etherscan_key
# Run all tests
pnpm test
# Run specific test file
pnpm test tests/01-otcCustody.test.ts
# Run with gas reporting
REPORT_GAS=true pnpm test
# Deploy to Arbitrum
pnpm hardhat run scripts/03-deploy-arbi.ts --network arbitrum
# Deploy to Base
pnpm hardhat run scripts/04-deploy-base.ts --network base
- User calls
sendUpdateCA
on OTCCustody source with Merkle proof - OTCCustody runs Merkle proof verification
- OTCCustody updates CA locally on source chain
- Bot listens to
updateCA
event - Prepares call data for source Connector's
sendUpdateCA
function - Call data includes
_verificationData
with Merkle proof - Bot calls
sendUpdateCA
of Connector with prepared call data - Connector calls
getCA(custodyId)
of OTCCustody and fetches the latest CA - Connector calls
sendMessage
of CCIP Helper - Message contains: New CA, Verification data
- CCIP Router receives message
- Forwards to destination CCIP Receiver
- Calls
ccipReceive
with encoded message containing: New CA, Verification data - Destination CCIP Receiver receives message
- Calls
handleCCIPMessage
of Connector destination - Passes decoded message with: New CA, Verification data
- Connector destination receives message
- Calls
updateCA
of OTCCustody destination - Destination OTCCustody runs Merkle proof verification
- Updates CA locally on destination chain
- Create new Connector contract implementing
IConnector
interface - Add Connector-specific tests in tests folder (e.g.
tests/07-across-connector.test.ts
) - Update production deployment scripts in
scripts/07-deploy-across.ts
to
- Write unit tests for core functionality
- Add integration tests for cross-chain operations
- Test with different token types
- Verify gas optimization
- Always verify Merkle proofs
- Check Connector whitelist
- Validate cross-chain messages
- Use secure random number generation
- Implement proper access control
- Fork the repository
- Create feature branch
- Commit changes
- Push to branch
- Create Pull Request
- Currently working on SepoliaBase testnet
- Using MockSpokePool for Across's deposit and relay functions
- All Connectors are deployed using Factory pattern via
deployConnector
function inOTCCustody.sol
except forAcrossConnector
andCCIPConnector
which are deployed independently. - All actions on Connectors are performed via
callConnector
function inOTCCustody.sol
except forAcross
andCCIP
which are handled by the Connectors themselves. - All of the off-chain actions related to CA (Custody Agreement) are handled by the
CAHelper.ts
utility class. This includes Merkle proof generation and verification, CA management, and other actions on CA. - Whenever a custody is created in OTCCustody, a new CA is created locally using the
CAHelper.ts
utility class. This CA has a unique ID which is used to identify the CA calledcustodyId
. - At the current implementation, the
custodyId
is the first ever merkle root of the CA which can be fetched viagetCustodyID()
function in CAHelper. - When you add any action to the CA using
CAHelper.ts
, you can fetch the latest merkle root of the CA usinggetCARoot()
function in CAHelper.
MIT
(Note for later), Voting power of Index is not made crosschain, votes snapshot needs to be bridgeable.