Skip to content

Address Provider

The AddressProvider serves as the entry point contract for Curve's various registries and is deployed on all chains where Curve is operational. The contract holds the most important contract addresses.

GitHub

Source code of the AddressProvider.vy contract can be found on GitHub. A list of all deployed contracts can be found here.

Contract Upgradability

The AddressProvider contract is managed by an admin who is currently an individual at Curve, rather than the Curve DAO1. This admin has the ability to update, add or remove new IDs within the contract. When integrating this contract into systems or relying on it for critical components, it is essential to consider that these IDs and their associated addresses can be modified at any time.


Reading IDs

For the full mapping of IDs please see get_id_info.

ID information is stored in a struct, containing an address, a detailed description, its version, and the timestamp marking its most recent modification:

struct AddressInfo:
    addr: address
    description: String[256]
    version: uint256
    last_modified: uint256

Google Colab Notebook

A Google Colab notebook that provides a full mapping of IDs by iterating over all ids via calling the get_id_info can be found here: Google Colab Notebook

The notebook is compatible with querying IDs for different chains and returns a table as shown below:

ids

AddressProvider.ids() -> DynArray[uint256, 1000]

Getter function for all the IDs of active registry items in the AddressProvider.

Returns: active ids (DynArray[uint256, 1000])

Source code
_ids: DynArray[uint256, 1000]

@view
@external
def ids() -> DynArray[uint256, 1000]:
    """
    @notice returns IDs of active registry items in the AddressProvider.
    @returns An array of IDs.
    """
    _ids: DynArray[uint256, 1000] = []
    for _id in self._ids:
        if self.check_id_exists[_id]:
            _ids.append(_id)

    return _ids

This method returns all populated IDs.

>>> AddressProvider.ids()
0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 25, 18

get_id_info

AddressProvider.get_id_info(arg0: uint256) -> tuple: view

Getter function to retrieve informations about a specific ID.

Returns: AddressInfo struct containing the addr (address), description (String[256]), version (uint256) and last_modified (uint256).

Input Type Description
arg0 uint256 ID to get the informations for
Source code
struct AddressInfo:
    addr: address
    description: String[256]
    version: uint256
    last_modified: uint256

get_id_info: public(HashMap[uint256, AddressInfo])

This method returns the address of the contract, the description, the ID version (which is incremented by 1 each time the ID is updated), and the timestamp of the last modification. When calling the function for an unpopulated ID, it returns an empty AddressInfo struct.

>>> AddressProvider.get_id_info(0)
'0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5, Stableswap Custom Pool Registry, 1, 1712655599'

>>> AddressProvider.get_id_info(9)
'0x0000000000000000000000000000000000000000, '', 0, 0'

get_address

AddressProvider.get_address(arg0: uint256) -> address: view

Getter for the contract address of a ID.

Returns: contract (address).

Input Type Description
arg0 uint256 ID to get the contract address for
Source code
struct AddressInfo:
    addr: address
    description: String[256]
    version: uint256
    last_modified: uint256

get_id_info: public(HashMap[uint256, AddressInfo])

@view
@external
def get_address(_id: uint256) -> address:
    """
    @notice Fetch the address associated with `_id`
    @dev Returns empty(address) if `_id` has not been defined, or has been unset
    @param _id Identifier to fetch an address for
    @return Current address associated to `_id`
    """
    return self.get_id_info[_id].addr

This method returns the address of an ID.

>>> AddressProvider.get_address(0)
'0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5'

check_id_exists

AddressProvider.check_id_exists(arg0: uint256) -> bool: view

Function to check if an ID exists.

Returns: true or false (bool).

Input Type Description
arg0 uint256 ID to check
Source code
check_id_exists: public(HashMap[uint256, bool])

This method checks if a certain ID exists.

>>> AddressProvider.check_id_exists(0)
'true'
>>> AddressProvider.check_id_exists(9)
'false'

num_entries

AddressProvider.num_entries() -> uint256: view

Getter for the number of entries. The count increments by one upon calling _add_new_id and decreases by one upon calling _remove_id.

Returns: number of entries (uint256).

Source code
num_entries: public(uint256)

This method returns the total number of IDs added to the AddressProvider.

>>> AddressProvider.num_entries()
20

Adding, Removing and Updating IDs

IDs can be added, removed, or adjusted by the admin of the contract.

Contract Upgradability

The AddressProvider contract is managed by an admin who is currently an individual at Curve, rather than the Curve DAO1. This admin has the ability to update, add or remove new IDs within the contract. When integrating this contract into systems or relying on it for critical components, it is essential to consider that these IDs and their associated addresses can be modified at any time.

update_id

AddressProvider.update_id(_id: uint256, _new_address: address, _new_description: String[64])

Guarded Methods

This function can only be called by the admin of the contract.

Function to update the address and description of an ID.

Emits: EntryModified

Input Type Description
_id uint256 ID to update
_new_address address New address
_new_description String[64] New description
Source code
event EntryModified:
    id: indexed(uint256)
    version: uint256

@external
def update_id(
    _id: uint256,
    _new_address: address,
    _new_description: String[64],
):
    """
    @notice Update entries at an ID
    @param _id Address assigned to the input _id
    @param _new_address Address assigned to the _id
    @param _new_description Human-readable description of the identifier
    """
    assert msg.sender == self.admin  # dev: admin-only function
    assert self.check_id_exists[_id]  # dev: id does not exist

    # Update entry at _id:
    self.get_id_info[_id].addr = _new_address
    self.get_id_info[_id].description = _new_description

    # Update metadata (version, update time):
    self._update_entry_metadata(_id)

@internal
def _update_entry_metadata(_id: uint256):

    version: uint256 = self.get_id_info[_id].version + 1
    self.get_id_info[_id].version = version
    self.get_id_info[_id].last_modified = block.timestamp

    log EntryModified(_id, version)
>>> soon

update_address

AddressProvider.update_address(_id: uint256, _address: address)

Guarded Methods

This function can only be called by the admin of the contract.

Function to update the address of an ID.

Emits: EntryModified

Input Type Description
_id uint256 ID to change the address for
_address address New address to change it to
Source code
event EntryModified:
    id: indexed(uint256)
    version: uint256

check_id_exists: public(HashMap[uint256, bool])
get_id_info: public(HashMap[uint256, AddressInfo])

@external
def update_address(_id: uint256, _address: address):
    """
    @notice Set a new address for an existing identifier
    @param _id Identifier to set the new address for
    @param _address Address to set
    """
    assert msg.sender == self.admin  # dev: admin-only function
    assert self.check_id_exists[_id]  # dev: id does not exist

    # Update address:
    self.get_id_info[_id].addr = _address

    # Update metadata (version, update time):
    self._update_entry_metadata(_id)

@internal
def _update_entry_metadata(_id: uint256):

    version: uint256 = self.get_id_info[_id].version + 1
    self.get_id_info[_id].version = version
    self.get_id_info[_id].last_modified = block.timestamp

    log EntryModified(_id, version)
>>> soon

update_description

AddressProvider.update_description(_id: uint256, _description: String[256])

Guarded Methods

This function can only be called by the admin of the contract.

Function to update the description of an ID.

Emits: EntryModified

Input Type Description
_id uint256 ID to change the description for
_description String[256] New description
Source code
event EntryModified:
    id: indexed(uint256)
    version: uint256

check_id_exists: public(HashMap[uint256, bool])
get_id_info: public(HashMap[uint256, AddressInfo])

@external
def update_description(_id: uint256, _description: String[256]):
    """
    @notice Update description for an existing _id
    @param _id Identifier to set the new description for
    @param _description New description to set
    """
    assert msg.sender == self.admin  # dev: admin-only function
    assert self.check_id_exists[_id]  # dev: id does not exist

    # Update description:
    self.get_id_info[_id].description = _description

    # Update metadata (version, update time):
    self._update_entry_metadata(_id)

@internal
def _update_entry_metadata(_id: uint256):

    version: uint256 = self.get_id_info[_id].version + 1
    self.get_id_info[_id].version = version
    self.get_id_info[_id].last_modified = block.timestamp

    log EntryModified(_id, version)
>>> soon

add_new_id

AddressProvider.add_new_id(_id: uint256, _address: address, _description: String[64])

Guarded Methods

This function can only be called by the admin of the contract.

Function to add a new registry item to the AddressProvider.

Emits: NewEntry

Input Type Description
_id uint256 ID to add; Reverts if ID number is already used
_address address New address
_description String[64] New description
Source code
event NewEntry:
    id: indexed(uint256)
    addr: address
    description: String[64]

@external
def add_new_id(
    _id: uint256,
    _address: address,
    _description: String[64],
):
    """
    @notice Enter a new registry item
    @param _id ID assigned to the address
    @param _address Address assigned to the ID
    @param _description Human-readable description of the ID
    """
    assert msg.sender == self.admin  # dev: admin-only function

    self._add_new_id(_id, _address, _description)

@internal
def _add_new_id(
    _id: uint256,
    _address: address,
    _description: String[64]
):

    assert not self.check_id_exists[_id]  # dev: id exists

    self.check_id_exists[_id] = True
    self._ids.append(_id)

    # Add entry:
    self.get_id_info[_id] = AddressInfo(
        {
            addr: _address,
            description: _description,
            version: 1,
            last_modified: block.timestamp,
        }
    )
    self.num_entries += 1

    log NewEntry(_id, _address, _description)
>>> soon

add_new_ids

AddressProvider.add_new_ids(_ids: DynArray[uint256, 25], _addresses: DynArray[address, 25], _descriptions: DynArray[String[64], 25])

Guarded Methods

This function can only be called by the admin of the contract.

Function to add mutiple new registry items to the AddressProvider at once.

Emits: NewEntry

Input Type Description
_ids DynArray[uint256, 25] IDs to add; Reverts if ID number is already used
_addresss DynArray[address, 25] ID addresses
_descriptions DynArray[String[64], 25] ID descriptions
Source code
event NewEntry:
    id: indexed(uint256)
    addr: address
    description: String[64]

@external
def add_new_ids(
    _ids: DynArray[uint256, 25],
    _addresses: DynArray[address, 25],
    _descriptions: DynArray[String[64], 25],
):
    """
    @notice Enter new registry items
    @param _ids IDs assigned to addresses
    @param _addresses Addresses assigned to corresponding IDs
    @param _descriptions Human-readable description of each of the IDs
    """
    assert msg.sender == self.admin  # dev: admin-only function

    # Check lengths
    assert len(_ids) == len(_addresses) 
    assert len(_addresses) == len(_descriptions)

    for i in range(len(_ids), bound=20):
        self._add_new_id(
            _ids[i], 
            _addresses[i], 
            _descriptions[i]
        )

@internal
def _add_new_id(
    _id: uint256,
    _address: address,
    _description: String[64]
):

    assert not self.check_id_exists[_id]  # dev: id exists

    self.check_id_exists[_id] = True
    self._ids.append(_id)

    # Add entry:
    self.get_id_info[_id] = AddressInfo(
        {
            addr: _address,
            description: _description,
            version: 1,
            last_modified: block.timestamp,
        }
    )
    self.num_entries += 1

    log NewEntry(_id, _address, _description)
>>> soon

remove_id

AddressProvider.remove_id(_id: uint256) -> bool

Guarded Methods

This function can only be called by the admin of the contract.

Function to remove a registry item from the AddressProvider.

Returns: true (bool).

Emits: EntryRemoved

Input Type Description
_id uint256 ID to remove
Source code
event EntryRemoved:
    id: indexed(uint256)

@external
def remove_id(_id: uint256) -> bool:
    """
    @notice Unset an existing identifier
    @param _id Identifier to unset
    @return bool success
    """
    assert msg.sender == self.admin  # dev: admin-only function

    return self._remove_id(_id)

@internal
def _remove_id(_id: uint256) -> bool:

    assert self.check_id_exists[_id]  # dev: id does not exist

    # Clear ID:
    self.get_id_info[_id].addr = empty(address)
    self.get_id_info[_id].last_modified = 0
    self.get_id_info[_id].description = ''
    self.get_id_info[_id].version = 0

    self.check_id_exists[_id] = False

    # Reduce num entries:
    self.num_entries -= 1

    # Emit 0 in version to notify removal of id:
    log EntryRemoved(_id)

    return True
>>> soon

remove_ids

AddressProvider.remove_ids(_ids: DynArray[uint256, 20]) -> bool

Guarded Methods

This function can only be called by the admin of the contract.

Function to remove mutiple registry items from the AddressProvider at once.

Returns: true (bool).

Emits: EntryRemoved

Input Type Description
_ids DynArray[uint256, 20] IDs to remove
Source code
event EntryRemoved:
    id: indexed(uint256)

@external
def remove_ids(_ids: DynArray[uint256, 20]) -> bool:
    """
    @notice Unset existing identifiers
    @param _id DynArray of identifier to unset
    @return bool success
    """
    assert msg.sender == self.admin  # dev: admin-only function

    for _id in _ids:
        assert self._remove_id(_id)

    return True

@internal
def _remove_id(_id: uint256) -> bool:

    assert self.check_id_exists[_id]  # dev: id does not exist

    # Clear ID:
    self.get_id_info[_id].addr = empty(address)
    self.get_id_info[_id].last_modified = 0
    self.get_id_info[_id].description = ''
    self.get_id_info[_id].version = 0

    self.check_id_exists[_id] = False

    # Reduce num entries:
    self.num_entries -= 1

    # Emit 0 in version to notify removal of id:
    log EntryRemoved(_id)

    return True
>>> soon

Contract Ownership

The ownership of the contract follows the classic two-step ownership model used across most Curve contracts.

admin

AddressProvider.admin() -> address: view

Getter for the admin of the contract. This address can add, remove or update ID's.

Returns: admin (address).

Source code
admin: public(address)

@external
def __init__():
    self.admin  = tx.origin
>>> AddressProvider.admin()
'0x2d12D0907A388811e3AA855A550F959501d303EE'

future_admin

AddressProvider.future_admin() -> address: view

Getter for the future admin of the contract.

Returns: future admin (address).

Source code
future_admin: public(address)
>>> AddressProvider.future_admin()
'0x0000000000000000000000000000000000000000'

commit_transfer_ownership

AddressProvider.commit_transfer_ownership(_new_admin: address) -> bool

Guarded Methods

This function can only be called by the admin of the contract.

Function to initiate a transfer of contract ownership.

Returns: true (bool).

Events: CommitNewAdmin

Input Type Description
_new_admin address Address to transfer the ownership to
Source code
event CommitNewAdmin:
    admin: indexed(address)

future_admin: public(address)

@external
def commit_transfer_ownership(_new_admin: address) -> bool:
    """
    @notice Initiate a transfer of contract ownership
    @dev Once initiated, the actual transfer may be performed three days later
    @param _new_admin Address of the new owner account
    @return bool success
    """
    assert msg.sender == self.admin  # dev: admin-only function
    self.future_admin = _new_admin

    log CommitNewAdmin(_new_admin)

    return True
>>> soon

apply_transfer_ownership

AddressProvider.apply_transfer_ownership() -> bool

Guarded Methods

This function can only be called by the future_admin of the contract.

Function to finalize a transfer of contract ownership.

Returns: true (bool).

Emits: NewAdmin

Source code
event NewAdmin:
    admin: indexed(address)

admin: public(address)
future_admin: public(address)

@external
def apply_transfer_ownership() -> bool:
    """
    @notice Finalize a transfer of contract ownership
    @dev May only be called by the next owner
    @return bool success
    """
    assert msg.sender == self.future_admin  # dev: admin-only function

    new_admin: address = self.future_admin
    self.admin = new_admin

    log NewAdmin(new_admin)

    return True
>>> soon

revert_transfer_ownership

AddressProvider.revert_transfer_ownership() -> bool

Guarded Methods

This function can only be called by the admin of the contract.

Function to revert the transfer of contract ownership.

Returns: true (bool).

Source code
admin: public(address)
future_admin: public(address)

@external
def revert_transfer_ownership() -> bool:
    """
    @notice Revert a transfer of contract ownership
    @dev May only be called by the current owner
    @return bool success
    """
    assert msg.sender == self.admin  # dev: admin-only function
    self.future_admin = empty(address)

    return True
>>> soon

  1. Reasoning: Due to the nature of the contract (it does not hold any user funds or has any monetary influence), it is not considered a crucial contract. It should only be used as a pure informational source. Additionally, the Curve ecosystem changes very rapidly and therefore requires fast updates for such a contract. Always putting up a DAO vote to change IDs would not be feasible.