-
Notifications
You must be signed in to change notification settings - Fork 212
/
scriptedPriceAuthority.js
95 lines (83 loc) · 2.46 KB
/
scriptedPriceAuthority.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// @ts-check
import { AmountMath, makeIssuerKit, AssetKind } from '@agoric/ertp';
import { E } from '@endo/eventual-send';
import { Far } from '@endo/marshal';
import { observeNotifier } from '@agoric/notifier';
import {
natSafeMath,
makeOnewayPriceAuthorityKit,
} from '../src/contractSupport/index.js';
export function makeScriptedPriceAuthority(options) {
const {
actualBrandIn,
actualBrandOut,
priceList,
timer,
unitAmountIn = AmountMath.make(actualBrandIn, 1n),
quoteInterval = 1n,
quoteIssuerKit = makeIssuerKit('quote', AssetKind.SET),
} = options;
const { brand, issuer: quoteIssuer, mint: quoteMint } = quoteIssuerKit;
let currentPrice = priceList[0];
/** @param {PriceQuoteValue} quote */
const authenticateQuote = quote => {
const quoteAmount = AmountMath.make(brand, harden(quote));
const quotePayment = quoteMint.mintPayment(quoteAmount);
return harden({ quoteAmount, quotePayment });
};
const calcAmountOut = amountIn => {
AmountMath.coerce(actualBrandIn, amountIn);
return AmountMath.make(
actualBrandOut,
natSafeMath.floorDivide(
natSafeMath.multiply(currentPrice, amountIn.value),
unitAmountIn.value,
),
);
};
const calcAmountIn = amountOut => {
AmountMath.coerce(actualBrandOut, amountOut);
return AmountMath.make(
actualBrandOut,
natSafeMath.floorDivide(
natSafeMath.multiply(unitAmountIn.value, amountOut.value),
currentPrice,
),
);
};
function createQuote(priceQuery) {
const quote = priceQuery(calcAmountOut, calcAmountIn);
if (!quote) {
return undefined;
}
const { amountIn, amountOut } = quote;
return E(timer)
.getCurrentTimestamp()
.then(now =>
authenticateQuote([{ amountIn, amountOut, timer, timestamp: now }]),
);
}
/** @type {ERef<Notifier<Timestamp>>} */
const notifier = E(timer).makeNotifier(0n, quoteInterval);
const priceAuthorityOptions = harden({
timer,
createQuote,
actualBrandIn,
actualBrandOut,
quoteIssuer,
notifier,
});
const {
priceAuthority,
adminFacet: { fireTriggers },
} = makeOnewayPriceAuthorityKit(priceAuthorityOptions);
const priceObserver = Far('priceObserver', {
updateState: t => {
currentPrice =
priceList[Number(Number(t / quoteInterval) % priceList.length)];
fireTriggers(createQuote);
},
});
observeNotifier(notifier, priceObserver);
return priceAuthority;
}