|
1 | 1 | // @ts-check
|
2 | 2 | /* global require, setImmediate */
|
| 3 | + |
3 | 4 | import { test } from '@agoric/zoe/tools/prepare-test-env-ava';
|
4 | 5 | import '@agoric/zoe/exported';
|
5 | 6 | import '../src/types';
|
@@ -273,12 +274,8 @@ test('first', async t => {
|
273 | 274 | 'withdrew 100 collateral',
|
274 | 275 | );
|
275 | 276 |
|
276 |
| - console.log('preDEBT ', vault.getDebtAmount()); |
277 |
| - |
278 | 277 | await E(aethVaultManager).liquidateAll();
|
279 |
| - console.log('DEBT ', vault.getDebtAmount()); |
280 | 278 | t.truthy(AmountMath.isEmpty(vault.getDebtAmount()), 'debt is paid off');
|
281 |
| - console.log('COLLATERAL ', vault.getCollateralAmount()); |
282 | 279 | t.truthy(AmountMath.isEmpty(vault.getCollateralAmount()), 'vault is cleared');
|
283 | 280 |
|
284 | 281 | t.deepEqual(stablecoinMachine.getRewardAllocation(), {
|
@@ -1618,7 +1615,6 @@ test('mutable liquidity triggers and interest', async t => {
|
1618 | 1615 | test('bad chargingPeriod', async t => {
|
1619 | 1616 | /* @type {TestContext} */
|
1620 | 1617 | const setJig = () => {};
|
1621 |
| - /* @type {TestContext} */ |
1622 | 1618 | const zoe = setUpZoeForTest(setJig);
|
1623 | 1619 |
|
1624 | 1620 | const autoswapInstall = await makeInstall(autoswapRoot, zoe);
|
@@ -1788,3 +1784,183 @@ test('coll fees from loan and AMM', async t => {
|
1788 | 1784 | .RUN;
|
1789 | 1785 | t.truthy(AmountMath.isGTE(feePayoutAmount, feePoolBalance.RUN));
|
1790 | 1786 | });
|
| 1787 | + |
| 1788 | +test('close loan', async t => { |
| 1789 | + /* @type {TestContext} */ |
| 1790 | + let testJig; |
| 1791 | + const setJig = jig => { |
| 1792 | + testJig = jig; |
| 1793 | + }; |
| 1794 | + const zoe = setUpZoeForTest(setJig); |
| 1795 | + |
| 1796 | + const autoswapInstall = await makeInstall(autoswapRoot, zoe); |
| 1797 | + const stablecoinInstall = await makeInstall(stablecoinRoot, zoe); |
| 1798 | + const liquidationInstall = await makeInstall(liquidationRoot, zoe); |
| 1799 | + |
| 1800 | + const { |
| 1801 | + aethKit: { mint: aethMint, issuer: aethIssuer, brand: aethBrand }, |
| 1802 | + } = setupAssets(); |
| 1803 | + |
| 1804 | + const priceAuthorityPromiseKit = makePromiseKit(); |
| 1805 | + const priceAuthorityPromise = priceAuthorityPromiseKit.promise; |
| 1806 | + const loanParams = { |
| 1807 | + chargingPeriod: 2n, |
| 1808 | + recordingPeriod: 6n, |
| 1809 | + poolFee: 24n, |
| 1810 | + protocolFee: 6n, |
| 1811 | + }; |
| 1812 | + const manualTimer = buildManualTimer(console.log); |
| 1813 | + const { creatorFacet: stablecoinMachine, publicFacet: lender } = await E( |
| 1814 | + zoe, |
| 1815 | + ).startInstance( |
| 1816 | + stablecoinInstall, |
| 1817 | + {}, |
| 1818 | + { |
| 1819 | + autoswapInstall, |
| 1820 | + priceAuthority: priceAuthorityPromise, |
| 1821 | + loanParams, |
| 1822 | + timerService: manualTimer, |
| 1823 | + liquidationInstall, |
| 1824 | + }, |
| 1825 | + ); |
| 1826 | + const { runIssuerRecord, govIssuerRecord } = testJig; |
| 1827 | + const { issuer: runIssuer, brand: runBrand } = runIssuerRecord; |
| 1828 | + const { brand: govBrand } = govIssuerRecord; |
| 1829 | + const quoteMint = makeIssuerKit('quote', AssetKind.SET).mint; |
| 1830 | + |
| 1831 | + const priceAuthority = makePriceAuthority( |
| 1832 | + aethBrand, |
| 1833 | + runBrand, |
| 1834 | + [15n], |
| 1835 | + null, |
| 1836 | + manualTimer, |
| 1837 | + quoteMint, |
| 1838 | + AmountMath.make(1n, aethBrand), |
| 1839 | + ); |
| 1840 | + priceAuthorityPromiseKit.resolve(priceAuthority); |
| 1841 | + |
| 1842 | + // Add a vaultManager with 900 aeth collateral at a 201 aeth/RUN rate |
| 1843 | + const capitalAmount = AmountMath.make(900n, aethBrand); |
| 1844 | + const rates = makeRates(runBrand, aethBrand); |
| 1845 | + const aethVaultManagerSeat = await E(zoe).offer( |
| 1846 | + E(stablecoinMachine).makeAddTypeInvitation(aethIssuer, 'AEth', rates), |
| 1847 | + harden({ |
| 1848 | + give: { Collateral: capitalAmount }, |
| 1849 | + want: { Governance: AmountMath.makeEmpty(govBrand) }, |
| 1850 | + }), |
| 1851 | + harden({ |
| 1852 | + Collateral: aethMint.mintPayment(capitalAmount), |
| 1853 | + }), |
| 1854 | + ); |
| 1855 | + |
| 1856 | + await E(aethVaultManagerSeat).getOfferResult(); |
| 1857 | + |
| 1858 | + // initial loan ///////////////////////////////////// |
| 1859 | + |
| 1860 | + // Create a loan for Alice for 5000 RUN with 1000 aeth collateral |
| 1861 | + const collateralAmount = AmountMath.make(1000n, aethBrand); |
| 1862 | + const aliceLoanAmount = AmountMath.make(5000n, runBrand); |
| 1863 | + const aliceLoanSeat = await E(zoe).offer( |
| 1864 | + E(lender).makeLoanInvitation(), |
| 1865 | + harden({ |
| 1866 | + give: { Collateral: collateralAmount }, |
| 1867 | + want: { RUN: aliceLoanAmount }, |
| 1868 | + }), |
| 1869 | + harden({ |
| 1870 | + Collateral: aethMint.mintPayment(collateralAmount), |
| 1871 | + }), |
| 1872 | + ); |
| 1873 | + const { |
| 1874 | + vault: aliceVault, |
| 1875 | + uiNotifier: aliceNotifier, |
| 1876 | + liquidationPayout, |
| 1877 | + } = await E(aliceLoanSeat).getOfferResult(); |
| 1878 | + |
| 1879 | + const debtAmount = await E(aliceVault).getDebtAmount(); |
| 1880 | + const fee = multiplyBy(aliceLoanAmount, rates.loanFee); |
| 1881 | + const runDebtLevel = AmountMath.add(aliceLoanAmount, fee); |
| 1882 | + |
| 1883 | + t.deepEqual(debtAmount, runDebtLevel, 'vault lent 5000 RUN + fees'); |
| 1884 | + const { RUN: lentAmount } = await E(aliceLoanSeat).getCurrentAllocation(); |
| 1885 | + const loanProceeds = await E(aliceLoanSeat).getPayouts(); |
| 1886 | + t.deepEqual(lentAmount, aliceLoanAmount, 'received 5000 RUN'); |
| 1887 | + |
| 1888 | + const runLent = await loanProceeds.RUN; |
| 1889 | + t.truthy( |
| 1890 | + AmountMath.isEqual( |
| 1891 | + await E(runIssuer).getAmountOf(runLent), |
| 1892 | + AmountMath.make(5000n, runBrand), |
| 1893 | + ), |
| 1894 | + ); |
| 1895 | + |
| 1896 | + const aliceUpdate = await aliceNotifier.getUpdateSince(); |
| 1897 | + t.deepEqual(aliceUpdate.value.debt, runDebtLevel); |
| 1898 | + const aliceCollateralization1 = aliceUpdate.value.collateralizationRatio; |
| 1899 | + t.deepEqual(aliceCollateralization1.numerator.value, 15000n); |
| 1900 | + t.deepEqual(aliceCollateralization1.denominator.value, runDebtLevel.value); |
| 1901 | + |
| 1902 | + // Create a loan for Bob for 1000 RUN with 200 aeth collateral |
| 1903 | + const bobCollateralAmount = AmountMath.make(200n, aethBrand); |
| 1904 | + const bobLoanAmount = AmountMath.make(1000n, runBrand); |
| 1905 | + const bobLoanSeat = await E(zoe).offer( |
| 1906 | + E(lender).makeLoanInvitation(), |
| 1907 | + harden({ |
| 1908 | + give: { Collateral: bobCollateralAmount }, |
| 1909 | + want: { RUN: bobLoanAmount }, |
| 1910 | + }), |
| 1911 | + harden({ |
| 1912 | + Collateral: aethMint.mintPayment(bobCollateralAmount), |
| 1913 | + }), |
| 1914 | + ); |
| 1915 | + const bobProceeds = await E(bobLoanSeat).getPayouts(); |
| 1916 | + await E(bobLoanSeat).getOfferResult(); |
| 1917 | + const bobRun = await bobProceeds.RUN; |
| 1918 | + t.truthy( |
| 1919 | + AmountMath.isEqual( |
| 1920 | + await E(runIssuer).getAmountOf(bobRun), |
| 1921 | + AmountMath.make(1000n, runBrand), |
| 1922 | + ), |
| 1923 | + ); |
| 1924 | + |
| 1925 | + // close loan, using Bob's RUN ///////////////////////////////////// |
| 1926 | + |
| 1927 | + const runRepayment = await E(runIssuer).combine([bobRun, runLent]); |
| 1928 | + |
| 1929 | + const aliceCloseSeat = await E(zoe).offer( |
| 1930 | + E(aliceVault).makeCloseInvitation(), |
| 1931 | + harden({ |
| 1932 | + give: { RUN: AmountMath.make(6000n, runBrand) }, |
| 1933 | + want: { Collateral: AmountMath.makeEmpty(aethBrand) }, |
| 1934 | + }), |
| 1935 | + harden({ RUN: runRepayment }), |
| 1936 | + ); |
| 1937 | + |
| 1938 | + const closeOfferResult = await E(aliceCloseSeat).getOfferResult(); |
| 1939 | + t.is(closeOfferResult, 'your loan is closed, thank you for your business'); |
| 1940 | + |
| 1941 | + const closeAlloc = await E(aliceCloseSeat).getCurrentAllocation(); |
| 1942 | + t.deepEqual(closeAlloc, { |
| 1943 | + RUN: AmountMath.make(750n, runBrand), |
| 1944 | + Collateral: AmountMath.make(1000n, aethBrand), |
| 1945 | + }); |
| 1946 | + const closeProceeds = await E(aliceCloseSeat).getPayouts(); |
| 1947 | + const collProceeds = await aethIssuer.getAmountOf(closeProceeds.Collateral); |
| 1948 | + const runProceeds = await E(runIssuer).getAmountOf(closeProceeds.RUN); |
| 1949 | + |
| 1950 | + t.deepEqual(runProceeds, AmountMath.make(750n, runBrand)); |
| 1951 | + t.deepEqual(collProceeds, AmountMath.make(1000n, aethBrand)); |
| 1952 | + t.deepEqual( |
| 1953 | + await E(aliceVault).getCollateralAmount(), |
| 1954 | + AmountMath.makeEmpty(aethBrand), |
| 1955 | + ); |
| 1956 | + |
| 1957 | + const liquidation = await liquidationPayout; |
| 1958 | + t.deepEqual( |
| 1959 | + await E(runIssuer).getAmountOf(liquidation.RUN), |
| 1960 | + AmountMath.makeEmpty(runBrand), |
| 1961 | + ); |
| 1962 | + t.deepEqual( |
| 1963 | + await aethIssuer.getAmountOf(liquidation.Collateral), |
| 1964 | + AmountMath.makeEmpty(aethBrand), |
| 1965 | + ); |
| 1966 | +}); |
0 commit comments