Recently, there’s been a lot of buzz in the ICON community regarding rebalancing of loan positions on Balanced. A rebalance happens when ICX collateral is sold for bnUSD to pay off a portion of a loan – this process can also be referred to as “retirement of bnUSD”. It’s important to note that rebalancing has nothing to do with how close your loan is to the reward threshold. Instead, rebalancing is used to keep bnUSD pegged to 1 USD as close as possible, and it occurs when there is an economic incentive to do so (e.g. the difference between 1 bnUSD and 1 USD crosses a risk threshold).

I won’t get into the economics of rebalancing too much, as this post is focused on how to perform a rebalance. If you’re interested in learning more about the topic, check out this post from the Balanced team. In short, here are a few things to keep in mind when it comes to rebalancing on Balanced:

  • Rebalancing is used to peg 1 bnUSD to 1 USD. Without rebalancing, Balanced wouldn’t be very appealing because a stablecoin that isn’t a stablecoin, isn’t a stablecoin.
  • Rebalancing is not related to your loan ratio. In other words, the size of your loan doesn’t have an impact on how often your loan is rebalanced.
  • Rebalancing tends to occur when market conditions cause bnUSD to drift from its peg. Since there is a fee to retire bnUSD, rebalances are profitable when the peg falls below a certain threshold that justifies taking action – this threshold is not set in stone, and depends on the risk profile of the party performing the retirement.

At this time, the Balanced team is working on adding bnUSD retirement into the Balanced UI. For now, the only way to rebalance loans and retire bnUSD is to interact directly with the Balanced smart contracts. In this tutorial, I’ll show you the various components that are needed to build a rebalancing bot.

Disclaimer: This post is for educational purposes only, and should not be interpreted as financial advice. I am not responsible if you build a bot and lose money. Remember to always DYOR.

Step 1 – Set Up Call and Call Transaction Functions

Before we dive into how to rebalance loans, let’s first set up a few functions that can be used to make calls and call transactions to the ICON network. If you are not familiar with ICON call and transaction builders, check out the documentations for the various SDKs here.

# Function for making a call.

def call(to, method, params):
	call = CallBuilder()\
		.to(to)\
		.method(method)\
		.params(params)\
		.build()
	result = icon_service.call(call)
	return result
	
# Function for making a call transaction.

def call_tx(to, method, params):
	transaction = CallTransactionBuilder()\
		.from_(balanced_bot_address)\
		.to(to)\
		.value(0)\
		.nid(1)\
		.method(method)\
		.params(params)\
		.build()
	estimate_step = icon_service.estimate_step(transaction)
	step_limit = estimate_step + 100000
	signed_transaction = SignedTransaction(transaction, wallet, step_limit)
	tx_hash = icon_service.send_transaction(signed_transaction)
	return tx_hash

Step 2 – Calculate bnUSD Price in USD

The next step is to calculate the price of bnUSD in USD – this is important because it determines whether rebalancing makes sense. Unfortunately, there is no direct bnUSD/USD market to quote from, so the calculate has to be done a different way. What we do have access to is price data for ICX/USD and sICX/bnUSD. Since 1 sICX can always be redeemed for 1 ICX, we can use this relationship to calculate the bnUSD/USD price.

If you enjoy this post, consider voting for RHIZOME. Unlike many unproductive teams, we actually do stuff. Subscribe to our newsletter, listen to our podcast, download our MetrICX app, and stay up to date on our projects (icon-cli, Coda, and more) by following us on Twitter.

To get the ICX/USD price, we can query the Band oracle contract – this is the method that Balanced uses to get the market price of ICX.

def query_icx_usd_price():
	result = call(
		"cx087b4164a87fdfb7b714f3bafe9dfb050fd6b132",
		"get_ref_data",
		{"_symbol": "ICX"}
	)
	return int(result["rate"], 16) / 1000000000

After that, the sICX/bnUSD price can be queried directly from the Balanced DEX contract.

def query_sicx_bnusd_price():
	result = call(
		"cxa0af3165c08318e988cb30993b3048335b94af6c",
		"getPrice",
		{"_id": 2}
	)
	return int(result, 16) / 10 ** 18

To calculate the bnUSD/USD price, divide the ICX/USD price by the sICX/bnUSD price.

def calculate_bnusd_price():
	return query_sicx_bnusd_price() / query_icx_usd_price()

Step 3 – Query the Max Retire Amount

Next, we’ll need to find the maximum amount of bnUSD that can be retired. This can be done by querying the getMaxRetireAmount method in the Balanced Loans contract.

def query_max_retire_amount():
	result = call(
		balanced_loans_address,
		"getMaxRetireAmount",
		{"_symbol": "bnUSD"}
	)
	return int(result, 16) / 10 ** 18

Step 4 – Send the Retirement Transaction

Finally, we can send the retirement transaction with value being the amount (less than or equal to the max retire amount) of bnUSD we want to retire.

def retire_bnusd(value):
	result = call_tx(
		balanced_loans_address,
		"returnAsset",
		{
			"_symbol": "bnUSD",
			"_value": value * 10 ** 18
		}
	)
	return result

Summary

That’s it! With these building blocks, you can develop a bot to take advantage of loan rebalancing and bnUSD retirement opportunities. Even though this feature will be added to the Balanced UI in the near future, I believe an automated solution is the best way to retire bnUSD. With a bot, you can scan market conditions and rebalance loans based on predefined conditions. Best of all, you won’t have to sit in front of a screen all day.