UNPKG

@agoric/zoe

Version:

Zoe: the Smart Contract Framework for Offer Enforcement

88 lines (78 loc) 2.7 kB
/// <reference path="./types-ambient.js" /> import { E } from '@endo/eventual-send'; import { AmountMath } from '@agoric/ertp'; import { getAmountOut, ceilMultiplyBy, atomicTransfer, } from '../../contractSupport/index.js'; import { Position } from './position.js'; import { calculateShares } from './calculateShares.js'; /** * makePayoffHandler returns an object with methods that are useful for * callSpread contracts. * * @param {ZCF<Record<string, any>>} zcf * @param {Record<PositionKind,PromiseRecord<ZCFSeat>>} seatPromiseKits * @param {ZCFSeat} collateralSeat * @returns {PayoffHandler} */ function makePayoffHandler(zcf, seatPromiseKits, collateralSeat) { const terms = zcf.getTerms(); const { brands: { Strike: strikeBrand, Collateral: collateralBrand }, } = terms; let seatsExited = 0; /** @type {MakeOptionInvitation} */ function makeOptionInvitation(position) { return zcf.makeInvitation( // All we do at the time of exercise is resolve the promise. seat => seatPromiseKits[position].resolve(seat), `collect ${position} payout`, { position, }, ); } function reallocateToSeat(seatPromise, seatPortion) { void E.when(seatPromise, seat => { atomicTransfer(zcf, collateralSeat, seat, { Collateral: seatPortion }); seat.exit(); seatsExited += 1; const remainder = collateralSeat.getAmountAllocated('Collateral'); if (AmountMath.isEmpty(remainder, collateralBrand) && seatsExited === 2) { zcf.shutdown('contract has been settled'); } }); } function payoffOptions(quoteAmount) { const strike1 = terms.strikePrice1; const strike2 = terms.strikePrice2; const { longShare } = calculateShares( collateralBrand, quoteAmount, strike1, strike2, ); const totalCollateral = terms.settlementAmount; // round in favor of the long position const longPortion = ceilMultiplyBy(totalCollateral, longShare); const shortPortion = AmountMath.subtract(totalCollateral, longPortion); // either offer might be exercised late, so we pay the two seats separately. reallocateToSeat(seatPromiseKits[Position.LONG].promise, longPortion); reallocateToSeat(seatPromiseKits[Position.SHORT].promise, shortPortion); } function schedulePayoffs() { E(terms.priceAuthority) .quoteAtTime(terms.expiration, terms.underlyingAmount, strikeBrand) .then(priceQuote => payoffOptions(getAmountOut(priceQuote))); } /** @type {PayoffHandler} */ const handler = harden({ schedulePayoffs, makeOptionInvitation, }); return handler; } harden(makePayoffHandler); export { makePayoffHandler };