diff --git a/packages/dai-plugin-liquidations/src/LiquidationService.js b/packages/dai-plugin-liquidations/src/LiquidationService.js index f05f2d569..aaba7dcc0 100644 --- a/packages/dai-plugin-liquidations/src/LiquidationService.js +++ b/packages/dai-plugin-liquidations/src/LiquidationService.js @@ -16,7 +16,7 @@ export const RAY = new BigNumber('1e27'); export const nullBytes = '0x'; -const stringToBytes = str => { +export const stringToBytes = str => { assert(!!str, 'argument is falsy'); assert(typeof str === 'string', 'argument is not a string'); return '0x' + Buffer.from(str).toString('hex'); @@ -288,6 +288,7 @@ export default class LiquidationService extends PublicService { .toFixed(); return await this._joinDaiAdapter().join(address, amt, { promise }); } + @tracksTransactions async exitDaiFromAdapter(amount, { promise }) { const address = this.get('web3').currentAddress(); @@ -297,6 +298,15 @@ export default class LiquidationService extends PublicService { return await this._joinDaiAdapter().exit(address, amt, { promise }); } + @tracksTransactions + async exitGemFromAdapter(ilk, amount, { promise }) { + const address = this.get('web3').currentAddress(); + const amt = BigNumber(amount) + .times(WAD) + .toFixed(); + return await this._joinGemAdapter(ilk).exit(address, amt, { promise }); + } + @tracksTransactions async bark(ilk, urn, { promise }) { try { @@ -335,4 +345,9 @@ export default class LiquidationService extends PublicService { _joinDaiAdapter() { return this.get('smartContract').getContractByName('MCD_JOIN_DAI'); } + + _joinGemAdapter(ilk) { + const suffix = ilk.replace('-', '_'); + return this.get('smartContract').getContractByName(`MCD_JOIN_${suffix}`); + } } diff --git a/packages/dai-plugin-liquidations/test/LiquidationService.test.js b/packages/dai-plugin-liquidations/test/LiquidationService.test.js index 52b8b137d..100b4964b 100644 --- a/packages/dai-plugin-liquidations/test/LiquidationService.test.js +++ b/packages/dai-plugin-liquidations/test/LiquidationService.test.js @@ -1,8 +1,12 @@ import Maker from '@makerdao/dai'; -import McdPlugin from '@makerdao/dai-plugin-mcd'; +import McdPlugin, { LINK } from '@makerdao/dai-plugin-mcd'; import BigNumber from 'bignumber.js'; import liquidationPlugin from '../src'; -import LiquidationService, { RAD, WAD } from '../src/LiquidationService'; +import LiquidationService, { + RAD, + WAD, + stringToBytes +} from '../src/LiquidationService'; import { createVaults, setLiquidationsApprovals } from './utils'; // const MCD_CLIP_LINK_A = '0x1eB71cC879960606F8ab0E02b3668EEf92CE6D98'; // kovan @@ -11,6 +15,9 @@ import { createVaults, setLiquidationsApprovals } from './utils'; // const MCD_CLIP_LINK_A = '0xc84b50Ea1cB3f964eFE51961140057f7E69b09c1'; //testchain // const MCD_JOIN_DAI = '0xe53793CA0F1a3991D6bfBc5929f89A9eDe65da44'; //testchain +const me = '0x16fb96a5fa0427af0c8f7cf1eb4870231c8154b6'; +const ilk = 'LINK-A'; + const kovanConfig = { plugins: [[liquidationPlugin], [McdPlugin, { network }]], accounts: { @@ -64,7 +71,7 @@ test('can bark an unsafe urn', async () => { ); const vaultUrnAddr = await cdpManager.getUrn(vaultId); - const id = await service.bark('LINK-A', vaultUrnAddr); + const id = await service.bark(ilk, vaultUrnAddr); expect(id).toEqual(1); }); @@ -119,9 +126,6 @@ test('can exit DAI from the vat', async () => { }); test('can successfully bid on an auction', async () => { - const me = '0x16fb96a5fa0427af0c8f7cf1eb4870231c8154b6'; - const ilk = '0x4c494e4b2d41'; // LINK-A - // We know the vault ID is 1 each time we run this test const id = 1; const amt = '1'; @@ -130,7 +134,7 @@ test('can successfully bid on an auction', async () => { const usrVatGemBal2 = await maker .service('smartContract') .getContract('MCD_VAT') - .gem(ilk, me); + .gem(stringToBytes(ilk), me); // The user's vat gem balance before bidding should be 0 expect(usrVatGemBal2.toString()).toEqual('0'); @@ -140,7 +144,7 @@ test('can successfully bid on an auction', async () => { const usrVatGemBal3 = await maker .service('smartContract') .getContract('MCD_VAT') - .gem(ilk, me); + .gem(stringToBytes(ilk), me); // The balance after winning the bid is the amount bid. expect(usrVatGemBal3.toString()).toEqual( @@ -148,6 +152,43 @@ test('can successfully bid on an auction', async () => { ); }); +test('can claim collateral after winning an auction', async () => { + const amt = 1; + + const linkToken = await maker.getToken(LINK); + + const linkBalanceBefore = (await linkToken.balanceOf(me)).toNumber(); + + // Starting balance of 1000, minus the 25 we locked in the vault + const startingBalance = 9975; + expect(linkBalanceBefore).toEqual(startingBalance); + + const usrVatGemBal1 = await maker + .service('smartContract') + .getContract('MCD_VAT') + .gem(stringToBytes(ilk), me); + + // The balance before exit should be the amount we won with 'take'. + expect(usrVatGemBal1.toString()).toEqual( + new BigNumber(amt).times(WAD).toString() + ); + + await service.exitGemFromAdapter(ilk, amt); + + const usrVatGemBal2 = await maker + .service('smartContract') + .getContract('MCD_VAT') + .gem(stringToBytes(ilk), me); + + // The user's vat gem balance after exit should be 0 + expect(usrVatGemBal2.toString()).toEqual('0'); + + const linkBalanceAfter = (await linkToken.balanceOf(me)).toNumber(); + + // Link balanced increased by the claim amount + expect(linkBalanceAfter).toEqual(startingBalance + amt); +}); + test('get unsafe LINK-A vaults', async () => { const urns = await service.getUnsafeVaults('LINK-A'); console.log('urns', urns); diff --git a/packages/dai-plugin-liquidations/test/utils.js b/packages/dai-plugin-liquidations/test/utils.js index fa12ca0c6..9e6c19d22 100644 --- a/packages/dai-plugin-liquidations/test/utils.js +++ b/packages/dai-plugin-liquidations/test/utils.js @@ -1,4 +1,4 @@ -import { LINK, DAI, ServiceRoles } from '@makerdao/dai-plugin-mcd'; +import { LINK, DAI } from '@makerdao/dai-plugin-mcd'; import { mineBlocks } from '../../test-helpers/src'; import BigNumber from 'bignumber.js'; @@ -38,13 +38,6 @@ export async function setLiquidationsApprovals(maker) { } } -async function getPrice(maker) { - const cdpType = maker - .service(ServiceRoles.CDP_TYPE) - .getCdpType(null, 'LINK-A'); - console.log('LINK PRICE:', cdpType.price._amount); -} - async function setProxyAndAllowances(maker) { const kprAddress = maker.currentAddress(); const linkToken = await maker.getToken(LINK); @@ -96,16 +89,10 @@ async function drawDai(manager, managedVault, vaultId) { // MAIN export async function createVaults(maker, network = 'testchain') { BigNumber.config({ ROUNDING_MODE: 1 }); //rounds down - const me = maker.currentAddress(); const manager = maker.service('mcd:cdpManager'); const jug = maker.service('smartContract').getContract('MCD_JUG'); const linkAmt = network === 'testchain' ? '25' : '5'; - await getPrice(maker); - - const linkToken = await maker.getToken(LINK); - console.log('Link Balance:', (await linkToken.balanceOf(me)).toString()); - // Initial Setup if (network === 'testchain') await setProxyAndAllowances(maker); //not needed for kovan @@ -114,8 +101,6 @@ export async function createVaults(maker, network = 'testchain') { const vaultId = vault.id; let managedVault = await manager.getCdp(vaultId); - const vaultUrnAddr = await manager.getUrn(vaultId); - console.log('Urn address', vaultUrnAddr); await resetVaultStats(managedVault);