Bancor Simulator
Contents
Bancor Simulator¶
Bancor Simulator is an open-source python package developed by the Bancor Research. It aims to assist the design, testing, and validation of Bancor v3 tokenomics.
See official documentation for complete details.
Warning: This documentation is a work in progress with potentially broken links, unfinished sections, and commands for including code segments. Moreover, the entirety of the codebase and documentation is subject to change without warning.
Introduction¶
All state transition functions and accompanying data structures described in the product specification BIP15: Proposing Bancor 3 are the core system level operations of this library.
Organization¶
This is the project directory structure:
bancor_analytics/ <------- Tableau Dashboard Project
bancor_emulator/ <------- Solidity Emulation Project
bancor_simulator/ <------- ** Spec & Simulation Project **
├── v3/ <------- Current Version
│ └── simulation/ <------- Agent-based simulation module
│ │ └── agents.py <------- Mesa Agent-based implementations of the Bancor protocol.
│ │ └── batch_run.py <------- Script used to perform a parameter sweep.
│ │ └── model.py <------- Main Bancor Simulation module interface.
│ │ └── random_walk.py <------- Generalized behavior for random walking
│ │ └── run.py <------- Runs the simulation server with browser-based UI
│ │ └── server.py <------- Configures the browser-based interface.
│ │ └── utils.py <------- Misc utility functions
│ │
│ └── spec/ <------- State transition functions and data structures described in BIP15.
│ └── actions.py <------- Deposit, trade, & withdrawal algorithm logic.
│ └── emulation.py <------- Verifies solidity result parity.
│ └── network.py <------- Main BancorDapp application interface.
│ └── rewards.py <------- Autocompounding and standard rewards logic.
│ └── state.py <------- State variables, constants, data structures, and CRUD interfaces.
│ └── utils.py <------- Misc utility functions
│
└── main.py <------- Application
** These docs apply.
Notation¶
Code snippets appearing in this style
are to be interpreted as Python 3 code.
Formatting & Style¶
Code is formatted according to PEP8, which is the official Python style guide. In order to overcome the burden on the developers to fix formatting, we use Black which reports on format errors and automatically fixes them.
Types¶
Standard Types¶
Python decimals.Decimal(precision=155)
is used for all floating-point values for reason of obtaining theoretical accuracy. After a theoretical result is produced, the emulator module provides a python-based solidity contract replica result in order to assess any fixed-point math and/or other implementation deviations.
Custom Types¶
We define the following Python custom types for type hinting and readability:
Name |
Type |
Description |
---|---|---|
|
|
an epoch number |
Constants¶
Non-Configurable Constants¶
The following values are (non-configurable) constants used throughout the specification.
MODEL = "Bancor Network"
VERSION = "1.0.0"
GENESIS_EPOCH = Epoch(0)
SECONDS_PER_DAY = 86400
MAX_UINT112 = 2 ** 112 - 1
PRECISION = 155
Configurable Genesis Variables¶
The following values are (configurable) genesis variables used throughout the specification.
Note: Where applicable, the default values correspond to those used in BIP15 examples, or are otherwise expected to be those values which are actually implemented on the Bancor dApp.
DEFAULT_TIMESTAMP = 0
DEFAULT_WHITELIST = ["dai", "eth", "link", "bnt", "tkn", "wbtc"]
DEFAULT_USERS = ["alice", "bob", "charlie", "trader", "user", "protocol"]
DEFAULT_DECIMALS = 18
DEFAULT_QDECIMALS = Decimal(10) ** -DEFAULT_DECIMALS
DEFAULT_PRICE_FEEDS_PATH = "https://bancorml.s3.us-east-2.amazonaws.com/price_feeds.parquet"
DEFAULT_EXP_DECAY_DISTRIBUTION = 1
DEFAULT_FLAT_DISTRIBUTION = 0
DEFAULT_WITHDRAWAL_FEE = Decimal('0.002')
DEFAULT_TRADING_FEE = Decimal('0.0025')
DEFAULT_NETWORK_FEE = Decimal('0.0025')
DEFAULT_BNT_FUNDING_LIMIT = Decimal('1000000')
DEFAULT_BNT_MIN_LIQUIDITY = Decimal('10000')
DEFAULT_COOLDOWN_TIME = 604800
DEFAULT_ALPHA = Decimal("0.2").quantize(DEFAULT_QDECIMALS)
DEFAULT_LOWER_EMA_LIMIT = Decimal("0.99").quantize(DEFAULT_QDECIMALS)
DEFAULT_UPPER_EMA_LIMIT = Decimal("1.01").quantize(DEFAULT_QDECIMALS)
DEFAULT_NUM_TIMESTAMPS = SECONDS_PER_DAY * 30
DEFAULT_PRICE_FEEDS = pd.DataFrame(
{
"INDX": (0 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"vbnt": (1.0 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"tkn": (2.5 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"bnt": (2.5 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"link": (15.00 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"eth": (2500.00 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
"wbtc": (40000.00 for _ in range(DEFAULT_NUM_TIMESTAMPS)),
}
)
Misc dependencies¶
Token
¶
The following object represents token values in the system. Supported operations include add, subtract, and set which are anologous to credit, debit, and overwrite in traditional book-keeping parlance.
class Token(object):
"""
Represents a token balance with common math operations to increase, decrease, and set the balance.
"""
def __init__(self, balance: Decimal = Decimal('0'), qdecimals: Decimal = DEFAULT_QDECIMALS):
self.balance = balance
self.qdecimals = qdecimals
def add(self, value: Decimal):
self.balance += self.validate(value)
def subtract(self, value: Decimal):
self.balance -= self.validate(value)
def set(self, value: Decimal):
self.balance = self.validate(value)
def validate(self, value) -> Decimal:
return Decimal(str(value)).quantize(self.qdecimals)
Data Structures¶
The following data structures are built with pydantic dataclass objects.
Note: The definitions below are ordered topologically to facilitate execution of the BIP15 spec.
Misc dependencies¶
Config
¶
Global dataclass config settings inherited by all dataclasses.
class Config:
validate_assignment = True
arbitrary_types_allowed = True
GlobalSettings
¶
@dataclass(config=Config)
class GlobalSettings:
"""
Represents the default global settings. These can be overridden by the BancorDapp configuration upon instantiation.
"""
timestamp: int = DEFAULT_TIMESTAMP
model: str = MODEL
version: str = VERSION
eightee_places: int = DEFAULT_QDECIMALS
max_uint112: int = MAX_UINT112
precision: int = PRECISION
decimals: int = DEFAULT_DECIMALS
whitelisted_tokens: List[str] = field(default_factory=lambda: DEFAULT_WHITELIST)
active_users: List[str] = field(default_factory=lambda: DEFAULT_USERS)
price_feeds_path: str = DEFAULT_PRICE_FEEDS_PATH
cooldown_time: int = DEFAULT_COOLDOWN_TIME
network_fee: Decimal = DEFAULT_NETWORK_FEE
withdrawal_fee: Decimal = DEFAULT_WITHDRAWAL_FEE
bnt_min_liquidity: Decimal = DEFAULT_BNT_MIN_LIQUIDITY
trading_fee: Decimal = DEFAULT_TRADING_FEE
bnt_funding_limit: Decimal = DEFAULT_BNT_FUNDING_LIMIT
alpha: Decimal = DEFAULT_ALPHA
Cooldown
¶
@dataclass(config=Config)
class Cooldown:
"""
Represents a pending withdrawal cooldown state.
"""
id: int
created_at: int
user_name: str
tkn_name: str
is_complete: bool
tkn: Any = field(default_factory=Token)
pooltoken: Any = field(default_factory=Token)
StandardProgram
¶
@dataclass(config=Config)
class StandardProgram:
"""
Represents an standard reward program state.
"""
id: int
tkn_name: str
rewards_token: str
is_enabled: bool
is_active: bool
start_time: int
end_time: int
last_update_time: int
reward_rate: Decimal
remaining_rewards: Any = field(default_factory=Token)
reward_per_token: Any = field(default_factory=Token)
total_unclaimed_rewards: Any = field(default_factory=Token)
staked_reward_amt: Any = field(default_factory=Token)
pooltoken_amt: Any = field(default_factory=Token)
providers: list = field(default_factory=list)
AutocompoundingProgram
¶
@dataclass(config=Config)
class AutocompoundingProgram:
"""
Represents an autocompounding reward program state.
"""
id: int
tkn_name: str
owner_id: str
half_life_days: int
start_time: int
created_at: int
_half_life_seconds: int = 0
total_rewards: Any = field(default_factory=Token)
remaining_rewards: Any = field(default_factory=Token)
prev_token_amt_distributed: Any = field(default_factory=Token)
total_duration_in_seconds: Decimal = Decimal("0")
distribution_type: str = "exp"
is_active: bool = False
is_enabled: bool = False
@property
def flat_distribution_rate_per_second(self):
"""
Returns the rate per second of the distribution.
"""
return self.total_rewards.balance.quantize(DEFAULT_QDECIMALS) / self.total_duration_in_seconds
@property
def half_life_seconds(self):
"""
Returns the half-life of the distribution in seonds.
"""
return (
self.half_life_days * SECONDS_PER_DAY
if self._half_life_seconds == 0
else self._half_life_seconds
)
@half_life_seconds.setter
def half_life_seconds(self, value):
"""
Sets the half-life of the distribution in seonds.
"""
self._half_life_seconds = value
UserStandardProgram
¶
@dataclass(config=Config)
class UserStandardProgram:
"""
Represents a standard reward program user state
"""
id: int
staked_amt: Any = field(default_factory=Token)
pending_rewards: Any = field(default_factory=Token)
reward_per_token_paid: Any = field(default_factory=Token)
User
¶
@dataclass(config=Config)
class User:
"""
Represents a user agent state.
"""
user_name: str
pending_withdrawals: Dict[int, Cooldown] = field(
default_factory=lambda: defaultdict(Cooldown)
)
pending_standard_rewards: Dict[int, UserStandardProgram] = field(
default_factory=lambda: defaultdict(UserStandardProgram)
)
wallet: Dict[str, Token] = field(default_factory=lambda: defaultdict(Token))
Tokens
¶
@dataclass(config=Config)
class Tokens(GlobalSettings):
"""
Represents all ledger and other configuration balances associated with a particular token's current state.
"""
timestamp: int = DEFAULT_TIMESTAMP
master_vault: Any = field(default_factory=Token)
staking_ledger: Any = field(default_factory=Token)
pooltoken_supply: Any = field(default_factory=Token)
protocol_wallet_pooltokens: Any = field(default_factory=Token)
vortex_ledger: Any = field(default_factory=Token)
vbnt_burned: Any = field(default_factory=Token)
external_protection_vault: Any = field(default_factory=Token)
standard_rewards_vault: Any = field(default_factory=Token)
bnt_trading_liquidity: Any = field(default_factory=Token)
tkn_trading_liquidity: Any = field(default_factory=Token)
bnt_funding_limit: Decimal = DEFAULT_BNT_FUNDING_LIMIT
bnt_funding_amt: Any = field(default_factory=Token)
_vbnt_price: Any = field(default_factory=Token)
spot_rate: Decimal = Decimal("0")
inv_spot_rate: Decimal = Decimal("0")
ema_rate: Decimal = Decimal("0")
ema_last_updated: Decimal = Decimal("0")
_inv_ema_rate: Decimal = Decimal("0")
is_trading_enabled: bool = False
@property
def bnt_remaining_funding(self):
"""
Computes the BNT funding remaining for the pool.
"""
return self.bnt_funding_limit - self.bnt_funding_amt.balance.quantize(DEFAULT_QDECIMALS)
@property
def vbnt_price(self):
"""
Returns the price of the current vbnt token. Only valid when name==bnt
"""
assert (
self.name == "bnt"
), f"vbnt_price attempted to be accessed in {self.name} state, call bnt state instead"
return self._vbnt_price
@property
def is_price_stable(self):
"""
True if the spot price deviation from the EMA is less than 1% (or other preset threshold amount).
"""
return (
Decimal("0.99") * self.ema_rate
<= self.spot_rate
<= Decimal("1.01") * self.ema_rate
)
@property
def avg_tkn_trading_liquidity(self):
"""
The tkn trading liquidity adjusted by the ema.
"""
return (
self.bnt_trading_liquidity.balance.quantize(DEFAULT_QDECIMALS) / self.ema_rate
if self.ema_rate > 0
else 0
)
@property
def tkn_excess(self):
"""
The difference between the master_vault balance and the average trading liquidity.
"""
return self.master_vault.balance.quantize(DEFAULT_QDECIMALS) - self.avg_tkn_trading_liquidity
@property
def tkn_excess_bnt_equivalence(self):
"""
Computes the equivalent bnt value of the non-trading tkn balance of the master_vault.
"""
return self.tkn_excess * self.ema_rate
@property
def bnt_bootstrap_liquidity(self):
"""
Computes the bnt_min_liquidity multiplied by 2.
"""
return 2 * self.bnt_min_liquidity
@property
def inv_ema_rate(self) -> Decimal:
"""
The inverse EMA rate.
"""
return self._inv_ema_rate
@inv_ema_rate.setter
def inv_ema_rate(self, val):
"""
Sets a new inverse EMA rate value.
"""
self._inv_ema_rate = (self.inv_spot_rate * Decimal(0.2)) + (Decimal(0.8) * val)
@property
def inv_ema(self) -> Fraction:
"""
Returns a fraction as two separate outputs
"""
return Fraction(self.inv_ema_rate)
@property
def ema(self) -> Fraction:
"""
Returns a fraction as two separate outputs
"""
return Fraction(self.ema_rate)
@property
def ema_descale(self) -> int:
"""
Used for descaling the ema into at most 112 bits per component.
"""
return (
int(max(self.ema.numerator, self.ema.denominator)) + self.max_uint112 - 1
) // self.max_uint112
@property
def ema_compressed_numerator(self) -> int:
"""
Used to measure the deviation of solidity fixed point math on v3 calclulations.
"""
return int(self.ema.numerator / self.ema_descale)
@property
def ema_compressed_denominator(self) -> int:
"""
Used to measure the deviation of solidity fixed point math on v3 calclulations.
"""
return int(self.ema.denominator / self.ema_descale)
@property
def is_ema_update_allowed(self) -> bool:
"""
Returns True if the moving average has not been updated on the existing block.
"""
return int(self.timestamp) != int(self.ema_last_updated)
@property
def ema_deviation(self) -> Decimal:
"""
Returns the deviation between these values as emaRate/emaCompressedRate.
"""
if self.ema_compressed_numerator > 0:
return self.ema_rate * Decimal(
self.ema_compressed_denominator / self.ema_compressed_numerator
)
else:
return Decimal("0")
System State¶
State
¶
@dataclass(config=Config)
class State(GlobalSettings):
"""
Represents the system state at the current timestamp. Main interface for all other dataclasses.
"""
transaction_id: int = 0
timestamp: int = DEFAULT_TIMESTAMP
price_feeds: PandasDataFrame = None
whitelisted_tokens: list = field(default_factory=list)
tokens: Dict[str, Tokens] = field(
default_factory=lambda: defaultdict(Tokens)
)
users: Dict[str, User] = field(default_factory=lambda: defaultdict(User))
standard_reward_programs: Dict[int, StandardProgram] = field(
default_factory=lambda: defaultdict(StandardProgram)
)
autocompounding_reward_programs: Dict[str, AutocompoundingProgram] = field(
default_factory=lambda: defaultdict(AutocompoundingProgram)
)
history: list = field(default_factory=list)
logger: Any = logger
json_export: dict = field(default_factory=dict)
@property
def valid_rewards_programs(self):
"""
Returns all valid autocompounding programs for the current state.
"""
return [
p
for p in self.autocompounding_reward_programs
if self.autocompounding_reward_programs[p].is_active
and self.autocompounding_reward_programs[p].is_enabled
]
@property
def usernames(self):
"""
Returns a list of all current users
"""
return [user for user in self.users]
@property
def withdrawal_ids(self):
"""
Returns a list of all withdrawal_ids
"""
return sum([len(self.users[user].pending_withdrawals) for user in self.users])
@property
def autocompounding_programs_count(self) -> int:
"""
Returns the count of active autocompounding reward programs
"""
return len(
[
self.autocompounding_reward_programs[tkn_name]
for tkn_name in self.autocompounding_reward_programs
if self.autocompounding_reward_programs[tkn_name].is_active
]
)
@property
def active_autocompounding_programs(self) -> list:
"""
Returns the active autocompounding reward programs
"""
return [tkn_name for tkn_name in self.autocompounding_reward_programs if
self.autocompounding_reward_programs[tkn_name].is_active]
@property
def active_standard_programs(self) -> list:
"""
Returns the active standard reward programs
"""
return [tkn_name for tkn_name in self.whitelisted_tokens if self.standard_reward_programs[tkn_name].is_active]
@property
def standard_programs_count(self) -> int:
"""
Returns the count of active standard reward programs
"""
return len(
[
self.standard_reward_programs[tkn_name]
for tkn_name in self.whitelisted_tokens
if self.standard_reward_programs[tkn_name].is_active
]
)
@property
def bnt_price(self) -> Decimal:
"""
Returns the bnt price feed at the current timestamp.
"""
return Decimal(self.price_feeds.at[self.timestamp, "bnt"])
@property
def bnt_virtual_balance(self) -> Decimal:
"""
Returns the inverse of the bnt price feed at the current timestamp
"""
return Decimal("1") / self.bnt_price
@property
def bnbnt_rate(self) -> Decimal:
"""
Returns the inverse of the bnt price feed at the current timestamp
"""
if (
self.tokens["bnt"].staking_ledger.balance.quantize(DEFAULT_QDECIMALS) == 0
and self.tokens["bnt"].pooltoken_supply.balance.quantize(DEFAULT_QDECIMALS) == 0
):
bnbnt_rate = Decimal("1")
else:
bnbnt_rate = Decimal(
self.tokens["bnt"].pooltoken_supply.balance.quantize(DEFAULT_QDECIMALS) / self.tokens[
"bnt"].staking_ledger.balance.quantize(DEFAULT_QDECIMALS)
)
return bnbnt_rate
State Helper (CRUD) Functions¶
Get Values¶
These functions get the current state variable value.
get_autocompounding_remaining_rewards(state, tkn_name)
get_autocompounding_start_time(state, tkn_name)
get_avg_tkn_trading_liquidity(state, tkn_name)
get_bnbnt_rate(state, tkn_name)
get_bnt_bootstrap_liquidity(state, tkn_name)
get_bnt_funding_amt(state, tkn_name)
get_bnt_funding_limit(state, tkn_name)
get_bnt_min_liquidity(state, tkn_name)
get_bnt_remaining_funding(state, tkn_name)
get_bnt_trading_liquidity(state, tkn_name)
get_bnt_virtual_balance(state, tkn_name)
get_description(state, tkn_name)
get_distribution_type(state, tkn_name)
get_ema_last_updated(state, tkn_name)
get_ema_rate(state, tkn_name)
get_external_protection_description(state, tkn_name)
get_external_protection_vault(state, tkn_name)
get_flat_distribution_rate_per_second(state, tkn_name)
get_half_life_seconds(state, tkn_name)
get_inv_spot_rate(state, tkn_name)
get_is_ema_update_allowed(state, tkn_name)
get_is_price_stable(state, tkn_name)
get_is_trading_enabled(state, tkn_name)
get_json_virtual_balances(state, tkn_name)
get_max_bnt_deposit(state, tkn_name)
get_network_fee(state, tkn_name)
get_pooltoken_balance(state, tkn_name)
get_pooltoken_description(state, tkn_name)
get_pooltoken_name(state, tkn_name)
get_prev_token_amt_distributed(state, tkn_name)
get_prices(state, tkn_name)
get_protocol_wallet_balance(state, tkn_name)
get_protocol_wallet_description(state, tkn_name)
get_rate_report(state, tkn_name)
get_remaining_standard_rewards(state, tkn_name)
get_spot_rate(state, tkn_name)
get_staked_balance(state, tkn_name)
get_staking_description(state, tkn_name)
get_standard_program(state, tkn_name)
get_standard_reward_end_time(state, tkn_name)
get_standard_reward_last_update_time(state, tkn_name)
get_standard_reward_per_token(state, tkn_name)
get_standard_reward_providers(state, tkn_name)
get_standard_reward_rate(state, tkn_name)
get_standard_reward_start_time(state, tkn_name)
get_standard_reward_tkn_name(state, tkn_name)
get_timestamp(state, tkn_name)
get_tkn_bootstrap_liquidity(state, tkn_name)
get_tkn_excess(state, tkn_name)
get_tkn_excess_bnt_equivalence(state, tkn_name)
get_tkn_price(state, tkn_name)
get_tkn_trading_liquidity(state, tkn_name)
get_tkn_virtual_balance(state, tkn_name)
get_total_bnt_trading_liquidity(state, tkn_name)
get_total_holdings(state, user_name, tkn_name)
get_total_rewards(state, tkn_name)
get_total_standard_rewards_staked(state, tkn_name)
get_trade_inputs(state, tkn_name)
get_trading_fee(state, tkn_name)
get_trading_liquidity_description(state, tkn_name)
get_unclaimed_rewards(state, tkn_name)
get_user_balance(state, user_name, tkn_name)
get_user_pending_rewards_staked_balance(state, user_name, tkn_name)
get_user_pending_standard_rewards(state, user_name, tkn_name)
get_user_pending_withdrawals(state, user_name, tkn_name)
get_user_reward_per_token_paid(state, user_name, tkn_name)
get_user_wallet_tokens(state, user_name, tkn_name)
get_usernames(state, tkn_name)
get_vault_balance(state, tkn_name)
get_vault_description(state, tkn_name)
get_vault_tvl(state, tkn_name)
get_virtual_rate(state, tkn_name)
get_vortex_balance(state)
get_vortex_description(state, tkn_name)
get_whitelisted_tokens(state, tkn_name)
get_withdrawal_id(state, tkn_name)
Example¶
v3 = BancorDapp()
state = v3.get_state()
user_name = "Alice"
tkn_name = "bnt"
balance = get_user_balance(state, user_name, tkn_name)
Note: The operation is similar for pooltokens and vbnt tokens.
pooltoken_name = f"bn{tkn_name}"
balance = get_user_balance(state, user_name, pooltoken_name)
Modify State¶
The following methods provide an interface to modify State
.
Note: For reason of readability and clarity, the following operations are handled by methods of the State
class, whereas the above get operations above are handled by functions. Thus, we include the state.
prefix for each method below, where typing is assumed state: State
Set Values¶
state.set_autocompounding_remaining_rewards(tkn_name, value)
state.set_bnt_funding_amt(tkn_name, value)
state.set_bnt_funding_limit(tkn_name, value)
state.set_bnt_trading_liquidity(tkn_name, value)
state.set_ema_rate(tkn_name, value)
state.set_initial_rates(tkn_name, value)
state.set_inv_spot_rate(tkn_name, value)
state.set_is_trading_enabled(tkn_name, value)
state.set_network_fee(tkn_name, value)
state.set_pending_withdrawals_status(tkn_name, value)
state.set_pooltoken_balance(tkn_name, value)
state.set_prev_token_amt_distributed(tkn_name, value)
state.set_program_is_active(tkn_name, value)
state.set_protocol_wallet_balance(tkn_name, value)
state.set_provider_pending_standard_rewards(tkn_name, value)
state.set_provider_reward_per_token_paid(tkn_name, value)
state.set_spot_rate(tkn_name, value)
state.set_staked_balance(tkn_name, value)
state.set_standard_program_end_time(tkn_name, value)
state.set_standard_program_is_active(tkn_name, value)
state.set_standard_remaining_rewards(tkn_name, value)
state.set_standard_rewards_last_update_time(tkn_name, value)
state.set_standard_rewards_per_token(tkn_name, value)
state.set_standard_rewards_vault_balance(tkn_name, value)
state.set_tkn_trading_liquidity(tkn_name, value)
state.set_token_amt_to_distribute(tkn_name, value)
state.set_trading_fee(tkn_name, value)
state.set_user_balance(user_name, tkn_name, value)
state.set_user_pending_standard_rewards(user_name, tkn_name, value)
state.set_user_standard_rewards_stakes(user_name, tkn_name, value)
state.set_vault_balance(tkn_name, value)
state.set_vbnt_burned(tkn_name, value)
state.set_vortex_balance(tkn_name, value)
state.set_withdrawal_fee(tkn_name, value)
Example¶
v3 = BancorDapp()
state = v3.get_state()
user_name = "Alice"
tkn_name = "bnt"
value = 100
state.set_user_balance(user_name, tkn_name, value)
Note: The operation is similar for pooltokens and vbnt tokens.
pooltoken_name = f"bn{tkn_name}"
state.set_user_balance(user_name, pooltoken_name, value)
Decrease Values¶
state.decrease_bnt_funding_amt(tkn_name, value)
state.decrease_bnt_trading_liquidity(tkn_name, value)
state.decrease_external_protection_balance(tkn_name, value)
state.decrease_pooltoken_balance(tkn_name, value)
state.decrease_protocol_wallet_balance(tkn_name, value)
state.decrease_staked_balance(tkn_name, value)
state.decrease_standard_reward_program_stakes(tkn_name, value)
state.decrease_standard_rewards_vault_balance(tkn_name, value)
state.decrease_tkn_trading_liquidity(tkn_name, value)
state.decrease_user_balance(user_name, tkn_name, value)
state.decrease_user_standard_rewards_stakes(user_name, tkn_name, value)
state.decrease_vault_balance(tkn_name, value)
state.decrease_vbnt_burned(tkn_name, value)
state.decrease_vortex_balance(tkn_name, value)
Example¶
v3 = BancorDapp()
state = v3.get_state()
user_name = "Alice"
tkn_name = "bnt"
# Amount to be subtracted from the current state
value = 100
state.decrease_user_balance(user_name, tkn_name, value)
Note: The operation is similar for pooltokens and vbnt tokens.
pooltoken_name = f"bn{tkn_name}"
state.decrease_user_balance(user_name, pooltoken_name, value)
Increase Values¶
state.increase_bnt_funding_amt(tkn_name, value)
state.increase_bnt_trading_liquidity(tkn_name, value)
state.increase_external_protection_balance(tkn_name, value)
state.increase_pooltoken_balance(tkn_name, value)
state.increase_protocol_wallet_balance(tkn_name, value)
state.increase_staked_balance(tkn_name, value)
state.increase_standard_reward_program_stakes(tkn_name, value)
state.increase_standard_rewards_vault_balance(tkn_name, value)
state.increase_tkn_trading_liquidity(tkn_name, value)
state.increase_user_balance(user_name, tkn_name, value)
state.increase_user_standard_rewards_stakes(user_name, tkn_name, value)
state.increase_vault_balance(tkn_name, value)
state.increase_vbnt_burned(tkn_name, value)
state.increase_vortex_balance(tkn_name, value)
Example¶
v3 = BancorDapp()
state = v3.get_state()
user_name = "Alice"
tkn_name = "bnt"
# Amount to be added to the current balance
value = 100
state.increase_user_balance(user_name, tkn_name, value)
Note: The operation is similar for pooltokens and vbnt tokens.
pooltoken_name = f"bn{tkn_name}"
state.increase_user_balance(user_name, pooltoken_name, value)
Network¶
The BancorDapp
class provides the top level interface through which the entire codebase is made to simulate real-world scenarios in a practical sense. An instance of this class is analogous to the Environment in common agent-oriented-programming jargon, and more practically, can be thought of like an instance of the Bancor dApp where Traders can perform trades, LPs can make deposits, withdraws, and participate in DAO votes which change the system’s tuneable fee (and other) parameters.
v3.begin_cooldown
v3.burn
v3.claim_standard_rewards
v3.create_autocompounding_program
v3.create_user
v3.dao_msig_init_pools
v3.deposit
v3.describe
v3.describe_rates
v3.distribute_autocompounding_program
v3.export
v3.export_test_scenarios
v3.get_state
v3.join_standard_rewards
v3.leave_standard_rewards
v3.next_transaction
v3.revert_state
v3.set_state
v3.set_user_balance
v3.show_history
v3.trade
v3.update_state
v3.whitelist_token
v3.withdraw
v3.set_trading_fee
v3.set_network_fee
v3.set_withdrawal_fee
v3.set_bnt_funding_limit
Example¶
v3 = BancorDapp()
tkn_name = 'wbtc'
value = .005
v3.set_trading_fee(tkn_name=tkn_name, value=value)
Simulation¶
The library currently supports a limited random walker style simulation scenario.
Parameter Sweeps (Batch Runs)¶
Parameters sweeps can be done via the mesa BatchRunner instance defined at the bottom of file batch_run.py in the simulation directory. This instance is for collecting data on parameter sweeps. It is not meant to be run with run.py, since run.py starts up a server for visualization, which isn’t necessary for the BatchRunner. To run a parameter sweep, call batch_run.py in the command line from the project directory as follows:
python bancor_simulator/v3/simulation/batch_run.py
The BatchRunner is set up to collect step by step data of the model. It does this by collecting the DataCollector object in a model_reporter (i.e. the DataCollector is collecting itself every step).
The end result of the batch run will be a CSV file created in the same directory from which Python was run. The CSV file will contain the data from every step of every run.
GUI Visualization (Single Runs)¶
To run the model interactively, run the following command from the project directory:
mesa runserver
Then open your browser to http://127.0.0.1:8521/, select the model parameters, press Reset, then Start.