Contributing: Adding New Protocols

This guide explains how to add support for new staking pools, lending/borrowing protocols, and other DeFi integrations to eth-portfolio. The system is designed for extensibility, using abstract base classes (ABCs) and a modular protocol architecture.

Choosing the Appropriate Base Class

eth-portfolio supports several types of protocols, each with a corresponding abstract base class. To add a new protocol, first determine which category your integration fits into:

  • Generic Protocol (ProtocolABC): Use this for most DeFi protocols that do not fit a more specific category. This is the most flexible base class and is suitable for lending, borrowing, or any protocol with custom logic. See: Adding a New Lending/Borrowing or Generic Protocol

  • Staking Pool (StakingPoolABC): Use this for protocols where users stake tokens to earn rewards, and the pool may have multiple tokens or custom reward logic. See: Adding a New Staking Pool

  • Single-Token Staking Pool (SingleTokenStakingPoolABC): Use this for staking pools that only accept a single token and have a straightforward staking/reward structure. See: Adding a New Single-Token Staking Pool

  • Protocol with Staking (ProtocolWithStakingABC): Use this if your protocol combines lending/borrowing or other DeFi features with an integrated staking component. See: Adding a Protocol with Staking

If you are unsure, start with ProtocolABC for lending/borrowing or custom protocols, and use the staking pool base classes for staking integrations. See the subsections below for details and examples.

Adding a New Staking Pool

Subclass StakingPoolABC from eth_portfolio/protocols/_base.py for pools with multiple tokens or custom logic.

Steps: 1. Subclass StakingPoolABC. 2. Implement the _balances method to return a TokenBalances mapping for a given address and block. 3. Implement any required methods such as contract, deploy_block, etc. 4. Register your pool in the appropriate protocol module.

Example:

from eth_portfolio.protocols._base import StakingPoolABC

class MyStakingPool(StakingPoolABC):
    def contract(self):
        # Return a web3 contract instance for the staking pool
        ...

    async def _balances(self, address, block=None):
        # Query the staked balance and rewards for the address
        ...

See eth_portfolio/protocols/liquity.py for real-world examples.

Adding a New Single-Token Staking Pool

Subclass SingleTokenStakingPoolABC from eth_portfolio/protocols/_base.py for pools that only accept a single token.

Example:

from eth_portfolio.protocols._base import SingleTokenStakingPoolABC

class MySingleTokenStakingPool(SingleTokenStakingPoolABC):
    def contract(self):
        ...

    async def _balances(self, address, block=None):
        ...

See eth_portfolio/protocols/liquity.py and eth_portfolio/protocols/convex.py for examples.

Adding a New Lending/Borrowing or Generic Protocol

Subclass ProtocolABC from eth_portfolio/protocols/_base.py for lending, borrowing, or other custom DeFi protocols.

Steps: 1. Subclass ProtocolABC. 2. Implement the _balances method to return a TokenBalances mapping, including supplied, borrowed, and reward tokens. 3. Register your protocol in the appropriate module.

Example:

from eth_portfolio.protocols._base import ProtocolABC

class MyLendingProtocol(ProtocolABC):
    async def _balances(self, address, block=None):
        # Query supplied and borrowed balances for the address
        ...

See eth_portfolio/protocols/dsr.py and eth_portfolio/protocols/lending/ for examples.

Adding a Protocol with Staking

If your protocol combines lending/borrowing with staking, subclass ProtocolWithStakingABC from eth_portfolio/protocols/_base.py.

Example:

from eth_portfolio.protocols._base import ProtocolWithStakingABC

class MyProtocolWithStaking(ProtocolWithStakingABC):
    async def _balances(self, address, block=None):
        # Query balances and staking positions
        ...

See eth_portfolio/protocols/convex.py for an example.

Best Practices and Tips

  • Use Async Methods: All balance queries should be asynchronous for performance.

  • Handle Edge Cases: Account for protocol-specific quirks, such as non-standard tokens or special reward logic.

  • Testing: Add tests for your protocol to ensure correctness and compatibility.

  • Documentation: Document your protocol’s behavior and any configuration requirements.

References

  • Abstract base classes: eth_portfolio/protocols/_base.py

  • Example staking pools: eth_portfolio/protocols/liquity.py, eth_portfolio/protocols/convex.py

  • Example lending protocols: eth_portfolio/protocols/dsr.py, eth_portfolio/protocols/lending/

  • Protocol registration: eth_portfolio/protocols/__init__.py