Skip to content

Commit d182e45

Browse files
authored
Merge pull request #3030 from Agoric/mfig-distribute-fees
Distribute fees
2 parents 38b8dcc + 334a253 commit d182e45

22 files changed

+291
-136
lines changed

packages/treasury/bundles/install-on-chain.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import stablecoinBundle from './bundle-stablecoinMachine';
99
const SECONDS_PER_HOUR = 60n * 60n;
1010
const SECONDS_PER_DAY = 24n * SECONDS_PER_HOUR;
1111

12+
const DEFAULT_POOL_FEE = 24n;
13+
const DEFAULT_PROTOCOL_FEE = 6n;
1214
/**
1315
* @param {Object} param0
1416
* @param {ERef<NameHub>} param0.agoricNames
@@ -19,8 +21,10 @@ const SECONDS_PER_DAY = 24n * SECONDS_PER_HOUR;
1921
* @param {ERef<PriceAuthority>} param0.priceAuthority
2022
* @param {ERef<ZoeService>} param0.zoe
2123
* @param {NatValue} param0.bootstrapPaymentValue
24+
* @param {NatValue} [param0.poolFee]
25+
* @param {NatValue} [param0.protocolFee]
2226
*/
23-
export async function installOnChain({ agoricNames, board, centralName, chainTimerService, nameAdmins, priceAuthority, zoe, bootstrapPaymentValue }) {
27+
export async function installOnChain({ agoricNames, board, centralName, chainTimerService, nameAdmins, priceAuthority, zoe, bootstrapPaymentValue, poolFee = DEFAULT_POOL_FEE, protocolFee = DEFAULT_PROTOCOL_FEE }) {
2428
// Fetch the nameAdmins we need.
2529
const [brandAdmin, installAdmin, instanceAdmin, issuerAdmin, uiConfigAdmin] = await Promise.all(
2630
['brand', 'installation', 'instance', 'issuer', 'uiConfig'].map(async edge => {
@@ -45,6 +49,8 @@ export async function installOnChain({ agoricNames, board, centralName, chainTim
4549
const loanParams = {
4650
chargingPeriod: SECONDS_PER_HOUR,
4751
recordingPeriod: SECONDS_PER_DAY,
52+
poolFee,
53+
protocolFee,
4854
};
4955

5056
const terms = harden({

packages/treasury/jsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
"strictNullChecks": true,
1515
"moduleResolution": "node",
1616
},
17-
"include": ["src/**/*.js", "exported.js", "globals.d.ts"],
17+
"include": ["src/**/*.js", "test/**/*.js", "exported.js", "globals.d.ts"],
1818
}

packages/treasury/scripts/build-bundles.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async function main() {
3232
`${bundlesDir}/bundle-liquidateMinimum.js`,
3333
],
3434
[
35-
`@agoric/zoe/src/contracts/multipoolAutoswap/multipoolAutoswap`,
35+
`@agoric/zoe/src/contracts/newSwap/multipoolAutoswap`,
3636
`${__dirname}/../bundles/bundle-multipoolAutoswap.js`,
3737
],
3838
];

packages/treasury/test/swingsetTests/test-treasury.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// eslint-disable-next-line import/no-extraneous-dependencies
66
import '@agoric/install-ses';
77
// eslint-disable-next-line import/no-extraneous-dependencies
8-
import test from 'ava';
8+
import rawTest from 'ava';
99
import { buildVatController, buildKernelBundles } from '@agoric/swingset-vat';
1010
import bundleSource from '@agoric/bundle-source';
1111
import { E } from '@agoric/eventual-send';
@@ -14,6 +14,9 @@ import liquidateBundle from '../../bundles/bundle-liquidateMinimum';
1414
import autoswapBundle from '../../bundles/bundle-multipoolAutoswap';
1515
import stablecoinBundle from '../../bundles/bundle-stablecoinMachine';
1616

17+
/** @type {import('ava').TestInterface<{ data: { kernelBundles: any, config: any } }>} */
18+
const test = rawTest;
19+
1720
test.before(async t => {
1821
const kernelBundles = await buildKernelBundles();
1922

packages/treasury/test/swingsetTests/vat-alice.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ const build = async (log, zoe, brands, payments, timer) => {
1818
const loanSeat = await E(zoe).offer(
1919
E(treasury).makeLoanInvitation(),
2020
harden({
21-
give: { Collateral: amountMath.make(moolaBrand, 100) },
22-
want: { RUN: amountMath.make(runBrand, 500000) },
21+
give: { Collateral: amountMath.make(moolaBrand, 100n) },
22+
want: { RUN: amountMath.make(runBrand, 500000n) },
2323
}),
2424
harden({
2525
Collateral: moolaPayment,

packages/treasury/test/swingsetTests/vat-owner.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const build = async (
2828
const loanParams = {
2929
chargingPeriod: SECONDS_PER_DAY,
3030
recordingPeriod: SECONDS_PER_DAY,
31+
poolFee: 24n,
32+
protocolFee: 6n,
3133
};
3234

3335
const priceAuthorityKit = await E(priceAuthorityVat).makePriceAuthority();
@@ -65,7 +67,7 @@ const build = async (
6567
);
6668
const proposal = harden({
6769
give: {
68-
Collateral: amountMath.make(moolaBrand, 1000),
70+
Collateral: amountMath.make(moolaBrand, 1000n),
6971
},
7072
want: { Governance: amountMath.makeEmpty(govBrand) },
7173
});

packages/treasury/test/test-interest.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ test('reportingPeriod shorter than charging', async t => {
252252
};
253253
const afterTwoMonths = {
254254
latestInterestUpdate: ONE_MONTH,
255-
interest: amountMath.make(203, brand),
256-
newDebt: amountMath.make(100203n, brand),
255+
interest: amountMath.make(brand, 203n),
256+
newDebt: amountMath.make(brand, 100203n),
257257
};
258258
// charging period is 30 days. 2nd interest isn't charged until 60 days.
259259
t.deepEqual(calculator.calculate(debtStatus, 32n * ONE_DAY), afterTwoMonths);

packages/treasury/test/test-stablecoin.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,7 @@ test('overdeposit', async t => {
13761376
assertAmountsEqual(
13771377
t,
13781378
await E.get(E(collectFeesSeat).getCurrentAllocation()).RUN,
1379-
amountMath.make(runBrand, 300),
1379+
amountMath.make(runBrand, 300n),
13801380
);
13811381
});
13821382

@@ -1764,7 +1764,7 @@ test('coll fees from loan and AMM', async t => {
17641764
});
17651765

17661766
const amm = E(zoe).getPublicFacet(await E(stablecoinMachine).getAMM());
1767-
const swapAmount = amountMath.make(aethBrand, 60000);
1767+
const swapAmount = amountMath.make(aethBrand, 60000n);
17681768
const swapSeat = await E(zoe).offer(
17691769
E(amm).makeSwapInInvitation(),
17701770
harden({

packages/treasury/test/test-vault-interest.js

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import bundleSource from '@agoric/bundle-source';
1111

1212
import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio';
1313
import { amountMath } from '@agoric/ertp';
14+
import { assert } from '@agoric/assert';
1415
import { makeTracer } from '../src/makeTracer';
1516

1617
const vaultRoot = './vault-contract-wrapper.js';
@@ -66,6 +67,7 @@ async function launch(zoeP, sourceRoot) {
6667
const payments = harden({
6768
Collateral: collateralMint.mintPayment(collateral50),
6869
});
70+
assert(creatorInvitation);
6971
return {
7072
creatorSeat: E(zoeP).offer(creatorInvitation, proposal, payments),
7173
creatorFacet,

packages/treasury/test/test-vault.js

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import bundleSource from '@agoric/bundle-source';
1212

1313
import { makeIssuerKit, amountMath } from '@agoric/ertp';
1414

15+
import { assert } from '@agoric/assert';
1516
import { makeTracer } from '../src/makeTracer';
1617

1718
const vaultRoot = './vault-contract-wrapper.js';
@@ -64,6 +65,7 @@ async function launch(zoeP, sourceRoot) {
6465
const payments = harden({
6566
Collateral: collateralMint.mintPayment(collateral50),
6667
});
68+
assert(creatorInvitation);
6769
return {
6870
creatorSeat: E(zoeP).offer(creatorInvitation, proposal, payments),
6971
creatorFacet,

packages/vats/decentral-config.json

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
"board": {
1414
"sourceSpec": "./src/vat-board.js"
1515
},
16+
"distributeFees": {
17+
"sourceSpec": "./src/vat-distributeFees.js"
18+
},
1619
"ibc": {
1720
"sourceSpec": "./src/vat-ibc.js"
1821
},

packages/vats/jsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
"strictNullChecks": true,
1515
"moduleResolution": "node",
1616
},
17-
"include": ["src/**/*.js", "globals.d.ts"],
17+
"include": ["src/**/*.js", "test/**/*.js", "globals.d.ts"],
1818
}

packages/vats/src/bootstrap.js

+19
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,25 @@ export function buildRootObject(vatPowers, vatParameters) {
161161
E(agoricNames).lookup('instance', 'Pegasus'),
162162
]);
163163

164+
// Start the reward distributor.
165+
const epochTimerService = chainTimerService;
166+
const distributorParams = {
167+
depositsPerUpdate: 51,
168+
updateInterval: 1n, // 1 second
169+
epochInterval: 60n * 60n, // 1 hour
170+
runIssuer: centralIssuer,
171+
runBrand: centralBrand,
172+
};
173+
E(vats.distributeFees)
174+
.buildDistributor(
175+
E(vats.distributeFees).makeTreasuryFeeCollector(zoe, treasuryCreator),
176+
E(bankManager).getDepositFacet(),
177+
epochTimerService,
178+
chainTimerService,
179+
harden(distributorParams),
180+
)
181+
.catch(e => console.error('Error distributing fees', e));
182+
164183
/** @type {undefined | import('@agoric/eventual-send').EOnly<Purse>} */
165184
let centralBootstrapPurse;
166185

packages/vats/src/distributeFees.js

+23-8
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ export function buildDistributor(treasury, bank, epochTimer, timer, params) {
4747
let lastWallTimeUpdate;
4848
const timerNotifier = E(timer).makeNotifier(0n, updateInterval);
4949

50-
async function scheduleDeposits() {
50+
/**
51+
* @param {(pmt: Payment[]) => void} disposeRejectedPayments
52+
*/
53+
async function scheduleDeposits(disposeRejectedPayments) {
5154
if (!queuedPayments.length) {
5255
return;
5356
}
@@ -60,12 +63,22 @@ export function buildDistributor(treasury, bank, epochTimer, timer, params) {
6063
if (!queuedPayments.length) {
6164
return;
6265
}
63-
E(bank).depositMultiple(
64-
queuedAccounts.splice(0, depositsPerUpdate),
65-
queuedPayments.splice(0, depositsPerUpdate),
66-
);
6766

68-
scheduleDeposits();
67+
const accounts = queuedAccounts.splice(0, depositsPerUpdate);
68+
const payments = queuedPayments.splice(0, depositsPerUpdate);
69+
E(bank)
70+
.depositMultiple(runBrand, accounts, payments)
71+
.then(settledResults => {
72+
const rejectedPayments = payments.filter(
73+
(_pmt, i) =>
74+
settledResults[i] && settledResults[i].status === 'rejected',
75+
);
76+
77+
// Redeposit the payments.
78+
disposeRejectedPayments(rejectedPayments);
79+
})
80+
.catch(e => console.error(`distributeFees cannot depositMultiple`, e));
81+
scheduleDeposits(disposeRejectedPayments);
6982
}
7083

7184
async function schedulePayments() {
@@ -95,7 +108,9 @@ export function buildDistributor(treasury, bank, epochTimer, timer, params) {
95108
queuedPayments.push(...manyPayments.slice(0, manyPayments.length - 1));
96109
queuedAccounts.push(...accounts);
97110

98-
scheduleDeposits();
111+
scheduleDeposits(_pmts => {
112+
// TODO: Somehow reclaim the rejected payments.
113+
});
99114
}
100115

101116
const timeObserver = {
@@ -109,5 +124,5 @@ export function buildDistributor(treasury, bank, epochTimer, timer, params) {
109124
};
110125

111126
const epochNotifier = E(epochTimer).makeNotifier(0n, epochInterval);
112-
observeNotifier(epochNotifier, timeObserver);
127+
return observeNotifier(epochNotifier, timeObserver);
113128
}

packages/vats/src/types.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
/**
5454
* @typedef {Object} BankDepositFacet
5555
*
56-
* @property {(accounts: string[], payments: Payment[]) => void} depositMultiple
56+
* @property {(brand: Brand, accounts: string[], payments: Payment[]) => Promise<PromiseSettledResult<Amount>[]>} depositMultiple
5757
* @property {() => Notifier<string[]>} getAccountsNotifier
5858
*/
5959

@@ -84,4 +84,5 @@
8484
* batches of payments are sent to the bank for processing. The parameter
8585
* updateInterval specifies the interval at which updates are sent.
8686
* @param {DistributorParams} params
87+
* @returns {Promise<void>}
8788
*/

0 commit comments

Comments
 (0)