Skip to main 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]: view

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
Example

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 information about a specific ID.

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

InputTypeDescription
arg0uint256ID to get the information for
<>Source code
struct AddressInfo:
addr: address
description: String[256]
version: uint256
last_modified: uint256

get_id_info: public(HashMap[uint256, AddressInfo])
Example

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(_id: uint256) -> address: view

Getter for the contract address of an ID.

Returns: contract (address).

InputTypeDescription
_iduint256ID 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
Example

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).

InputTypeDescription
arg0uint256ID to check
<>Source code
check_id_exists: public(HashMap[uint256, bool])
Example

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)
Example

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 Method

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

Function to update the address and description of an ID.

Emits: EntryModified

InputTypeDescription
_iduint256ID to update
_new_addressaddressNew address
_new_descriptionString[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)
Example

This function updates the ID at index 0.

>>> AddressProvider.update_id(0, "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E", "crvUSD Token")

update_address

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

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

Function to update the address of an ID.

Emits: EntryModified

InputTypeDescription
_iduint256ID to change the address for
_addressaddressNew 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)
Example

This example changes the address for ID 0.

>>> AddressProvider.update_address(0, "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E")

update_description

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

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

Function to update the description of an ID.

Emits: EntryModified

InputTypeDescription
_iduint256ID to change the description for
_descriptionString[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)

add_new_id

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

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

Function to add a new registry item to the AddressProvider.

Emits: NewEntry

InputTypeDescription
_iduint256ID to add; Reverts if ID number is already used
_addressaddressNew address
_descriptionString[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)

add_new_ids

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

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

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

Emits: NewEntry

InputTypeDescription
_idsDynArray[uint256, 25]IDs to add; Reverts if ID number is already used
_addressesDynArray[address, 25]ID addresses
_descriptionsDynArray[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)

remove_id

AddressProvider.remove_id(_id: uint256) -> bool
Guarded Method

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

InputTypeDescription
_iduint256ID 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

remove_ids

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

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

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

Returns: true (bool).

Emits: EntryRemoved

InputTypeDescription
_idsDynArray[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

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
Example
>>> 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)
Example
>>> AddressProvider.future_admin()
'0x0000000000000000000000000000000000000000'

commit_transfer_ownership

AddressProvider.commit_transfer_ownership(_new_admin: address) -> bool
Guarded Method

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

Function to initiate a transfer of contract ownership.

Returns: true (bool).

Emits: CommitNewAdmin

InputTypeDescription
_new_adminaddressAddress 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

apply_transfer_ownership

AddressProvider.apply_transfer_ownership() -> bool
Guarded Method

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

revert_transfer_ownership

AddressProvider.revert_transfer_ownership() -> bool
Guarded Method

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

Footnotes

  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. 2