The following are examples of how you can use GEB.js to facilitate the Global Settlement process and redeem your collateral which is locked in your own Safes or directly exchange system coins with collateral.
These scripts can help you go throught the steps described on the Global Settlement page.
We first need to setup geb.js
and ethers.js
:
import { ethers } from 'ethers'import { Geb, utils } from 'geb.js'​const provider = new ethers.providers.JsonRpcProvider('http://kovan.infura.io/v3/<API KEY>')const wallet = new ethers.Wallet('0xdefiisawesome...', provider)const geb = new Geb('kovan', provider)
Before continuing, we need to make sure that Global Settlement was triggered by checking the shutdown timestamp:
const shutdownTime = await geb.contracts.globalSettlement.shutdownTime()const hasGlobalSettlementStarted = shutdownTime.gt(0)
After settlement starts, each collateral needs to be frozen (Step 2). This needs to be done only once for every collateral type.
const tx = geb.contracts.globalSettlement.freezeCollateralType(utils.ETH_A)await wallet.sendTransaction(tx)
Since a SAFE is supposed to be over-collateralized, its owner can already withdraw excess collateral. The following script assumes that the SAFE is owned by a proxy contract. It also uses the Global Settlement Proxy Actions to pack and atomically execute multiple transactions at once.
const proxy = await geb.getProxyAction(wallet.address)const wethJoinAddress = geb.contracts.joinETH_A.address// Withdraw excess collateral from the Safe with ID #3const tx = proxy.freeTokenCollateralGlobalSettlement(wethJoinAddress, 3)await wallet.sendTransaction(tx)
This fulfills step 3 and step 5 from the Global Settlement process.
This part of the process consists in determining an exchange rate between the system coins that are still in circulation and each individual collateral type accepted by the system. The system needs to account for all Safes (I), terminate all ongoing collateral auctions (II) and remove all system surplus (III).
This needs to be done only once for the whole system. These steps can be taken care of by the settlement keeper bot or by anyone who is willing to pay the gas costs associated with these transactions.
// For (I) the function `processSAFE` needs to be called for all SAFEs,// particularly for under-collateralized ones since their owners are not// incentivised to call it themselvesconst safes = [] // Gather some Safe handlerssafes.push((await geb.getSafe(2)).handler)safes.push((await geb.getSafe(3)).handler)safes.push((await geb.getSafe(4)).handler)​// Prepare the transactionsconst txs = safes.map(handler =>geb.contracts.globalSettlement.processSAFE(utils.ETH_A, handler))​// Send all transactionstxs.map(tx => await wallet.sendTransaction(tx))​// For (II) we have 2 possibilities: wait for all auctions to finishconst cooldown = await geb.contracts.globalSettlement.shutdownCooldown()const now = BigNumber.from(Date.now()).div(1000)const isCooldownPassed = now.gt(shutdownTime.add(cooldown))​// Or prematurely terminate each auctionconst auctionId = 6const tx = geb.contracts.globalSettlement.fastTrackAuction(utils.ETH_A, auctionId)await wallet.sendTransaction(tx)​// (III) We need to get rid of the system surplusconst accountingEngineAddress = geb.contracts.accountingEngine.addressconst coin = await geb.contracts.safeEngine.coinBalance(accountingEngineAddress)const debt = await geb.contracts.safeEngine.debtBalance(accountingEngineAddress)const amountToSettle = coin.gte(debt) ? debt : coinconst tx = geb.contracts.accountingEngine.settleDebt(amountToSettle)await wallet.sendTransaction(tx)​// In case there is a bug in the system's accounting that// created more surplus than debt, there is a backup function called// transferPostSettlementSurplus() which gets rid of that extra surplus// and allows GlobalSettlement.setOutstandingCoinSupply() to execute successfulyconst tx = geb.contracts.accountingEngine.transferPostSettlementSurplus()await wallet.sendTransaction(tx)
Finally, the cash price for each collateral can be set with the following steps:
const tx = geb.contracts.globalSettlement.setOutstandingCoinSupply()await wallet.sendTransaction(tx)​// To be called once for each collateral typeconst tx = geb.contracts.globalSettlement.calculateCashPrice(utils.ETH_A)await wallet.sendTransaction(tx)
At this stage, any system coin holder can exchange their coins against a fixed basket of collateral. This is a 2 step process that consists in locking and preparing system coins and then claiming a share of a specific collateral type.
// Prepare the system coinsconst systemCoinBalance = await geb.contracts.coin.balanceOf(wallet.address)const tx = proxy.prepareCoinsForRedeemingGlobalSettlement(systemCoinBalance)await wallet.sendTransaction(tx)​// Redeem any collateral type you wantconst tx = proxy.redeemTokenCollateralGlobalSettlement(wethJoinAddress, utils.ETH_A, systemCoinBalance)await wallet.sendTransaction(tx)