Public
Edited
Dec 8, 2022
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
let _pool;
let _adapter;
let _adapterAddress;
let _maturity;
let _seriesObj;
for (let [adapter, pools] of Object.entries(poolData)) {
for (let [maturity, pool] of Object.entries(pools)) {
if (pool.poolID === selectedPoolID) {
_pool = pool;
_adapterAddress = adapter;
_adapter = adapterData[adapter];
_maturity = maturity;
_seriesObj = seriesData[adapter][maturity];
break;
}
}
}

const [spaceAddress] = await balancerVault.getPool(selectedPoolID);

const space = new ethers.Contract(
spaceAddress,
SPACE_ABI,
provider
);

const adapter = new ethers.Contract(
_adapterAddress,
["function scale() external view returns (uint256)"],
provider
);
let blockNumber = entryBlock;

let targetReserve;
let targetReserveVal;
let ptReserve;

const pti = await space.pti();

const tsInYears = new Bignumber(1)
.div(
new Bignumber((await space.ts()).toString()).div(
new Bignumber(10).pow(18)
)
)
.div(SECONDS_IN_A_YEAR);

const scalePre = new Bignumber(await adapter.scale({ blockTag: blockNumber }).then(t => t.toString())).div("1e18");
const totalSupplyPre = await space.totalSupply({ blockTag:blockNumber });
const { tokens, balances: balancesPre } = await balancerVault.getPoolTokens(selectedPoolID, { blockTag:blockNumber });
if (ethers.utils.getAddress(tokens[0]) === ethers.utils.getAddress(_adapter.targetAddress)) {
targetReserve = balancesPre[0].toString();
targetReserveVal = new Bignumber(targetReserve).times(scalePre);
ptReserve = balancesPre[1].toString();
} else {
targetReserve = balancesPre[1].toString();
targetReserveVal = new Bignumber(targetReserve).times(scalePre);
ptReserve = balancesPre[0].toString();
}

const ptPricePre = await calculatePTPrice(balancesPre, _seriesObj, totalSupplyPre.toString(), tsInYears, pti, space, blockNumber);
const targetBalPre = new Bignumber(targetReserveVal).div(totalSupplyPre.toString()).toString();
const targetValPre = new Bignumber(targetReserveVal).div(totalSupplyPre.toString()).toString();
const ptBalPre = new Bignumber(ptReserve).div(totalSupplyPre.toString()).toString();
const ytBal = ptBalPre;
const valPre = new Bignumber(targetValPre).plus(new Bignumber(ptBalPre).times(ptPricePre).times(scalePre)).plus(new Bignumber(ytBal).times(new Bignumber(1).minus(new Bignumber(ptPricePre).times(scalePre))));

const toBlock = _seriesObj.settled ? _seriesObj.settlementBlock : CURRENT_BLOCK;
const { balances: balancesCurrent } = await balancerVault.getPoolTokens(selectedPoolID, { blockTag:toBlock });
const totalSupplyCurrent = await space.totalSupply({ blockTag:toBlock });
const scaleCurrent = new Bignumber(await adapter.scale({ blockTag:toBlock }).then(t => t.toString())).div("1e18");

if (ethers.utils.getAddress(tokens[0]) === ethers.utils.getAddress(_adapter.targetAddress)) {
targetReserve = balancesCurrent[0].toString();
targetReserveVal = new Bignumber(targetReserve).times(scaleCurrent);
ptReserve = balancesCurrent[1].toString();
} else {
targetReserve = balancesCurrent[1].toString();
targetReserveVal = new Bignumber(targetReserve).times(scaleCurrent);
ptReserve = balancesCurrent[0].toString();
}

const ptPriceCurrent = await calculatePTPrice(balancesCurrent, _seriesObj, totalSupplyCurrent.toString(), tsInYears, pti, space, toBlock);

const targetBalCurrent = new Bignumber(targetReserve).div(totalSupplyCurrent.toString()).toString();
const targetValCurrent = new Bignumber(targetReserveVal).div(totalSupplyCurrent.toString()).toString();
const ptBalCurrent = new Bignumber(ptReserve).div(totalSupplyCurrent.toString()).toString();
const ytValCurrent = new Bignumber(ytBal).times(new Bignumber(1).minus(new Bignumber(ptPriceCurrent).times(scaleCurrent)));
const targetAccrued = scaleCurrent.minus(scalePre).times(ytBal).div(scalePre);

const valCurrent = new Bignumber(targetValCurrent).plus(new Bignumber(ptBalCurrent).times(ptPriceCurrent).times(scaleCurrent)).plus(ytValCurrent).plus(targetAccrued);

const { timestamp: startingBlockTS } = await provider.getBlock(blockNumber);

// Comment this block out to view the raw intermediate values
return `1 LP Share minted at block ${blockNumber} (${dayjs(startingBlockTS * 1000)})
* corresponded to ${new Bignumber(targetBalPre).toFormat(12)} ${_seriesObj.targetSymbol} ${new Bignumber(ptBalPre).toFormat(12)} PTs and ${new Bignumber(ytBal).toFormat(12)} YTs with scale ${new Bignumber(scalePre).toFormat(12)}
* and was worth ${valPre.toFormat(12)} underlying initially
* That position ${_seriesObj.settled ? `was worth ${valCurrent.toFormat(12)} underlying at maturity (${dayjs(_maturity * 1000)})`: `is worth ${valCurrent.toFormat(12)} underlying now`} with scale ${new Bignumber(scaleCurrent).toFormat(12)}
* and corresponds to ${new Bignumber(targetBalCurrent).toFormat(12)} ${_seriesObj.targetSymbol} ${new Bignumber(ptBalCurrent).toFormat(12)} PTs ${new Bignumber(ytBal).toFormat(12)} YTs and ${targetAccrued.toFormat(12)} accrued Target
* Scale diff: ${new Bignumber(scaleCurrent).div(scalePre).toFormat(12)}
* LP Share value diff: ${new Bignumber(valCurrent).div(valPre).toFormat(12)}`

return {
ytValCurrent: ytValCurrent.toString(),
ptPricePre: new Bignumber(ptPricePre).times(scalePre).toString(), ptPriceCurrent: new Bignumber(ptPriceCurrent).times(scaleCurrent).toString(), targetAccrued: targetAccrued.toString(),
targetBalPre: targetBalPre.toString(), ptBalPre, scalePre: scalePre.toString(), targetBalCurrent: targetBalCurrent.toString(), ptBalCurrent, scaleCurrent: scaleCurrent.toString(), ytBal
};
}
Insert cell
async function calculatePTPrice(balances, seriesObj, totalSupply, tsInYears, pti, space, blockNumber) {
let ir;
let ir2;
const iscale = new Bignumber(seriesObj.iscale.toHexString()).div(
ethers.utils.parseEther("1").toString()
);

if (pti.eq(1)) {
ir = new Bignumber(balances[1].toHexString())
.plus(totalSupply)
.div(new Bignumber(balances[0].toHexString()).times(iscale))
.minus(1);

ir2 = new Bignumber(
ir.plus(1).toNumber() ** (1 / tsInYears.toNumber())
).minus(1);
} else {
ir = new Bignumber(balances[0].toHexString())
.plus(totalSupply)
.div(new Bignumber(balances[1].toHexString()).times(iscale))
.minus(1);

ir2 = new Bignumber(
ir.plus(1).toNumber() ** (1 / tsInYears.toNumber())
).minus(1);
}
// Call price function directly on the space pool
const ptPricePerTargetFromIr = await space.getPriceFromImpliedRate(
ir.times(ethers.utils.parseEther("1").toString())
.decimalPlaces(0)
.toFixed(),
{ blockTag: blockNumber }
);


return new Bignumber(
ptPricePerTargetFromIr.toHexString()
)
.div(ethers.utils.parseEther("1").toString())
.toString();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
poolData = {
const _poolData = {};
const spaceFactory = new ethers.Contract(
addresses.SpaceFactory,
["function pools(address, uint256) external view returns (address)"],
provider
);

// for each space: price, implied rate, assets, reserves, num swaps?
// fix TVL

for (let [adapterAddress, seriesObjs] of Object.entries(seriesData)) {
for (let [maturity, seriesObj] of Object.entries(seriesObjs)) {
const spaceAddress = await spaceFactory.pools(adapterAddress, maturity);
const _adapterData = adapterData[adapterAddress];

const space = new ethers.Contract(
spaceAddress,
SPACE_ABI,
provider
);

const endBufferIndex = await space
.getTotalSamples()
.then((t) => t.sub(1).toNumber());

const sample = await space.getSample(endBufferIndex);
const oracleReady = sample.timestamp.gt(0);

const poolID = await space.getPoolId();
const timeShift = await space
.ts()
.then((t) => new Bignumber(t.toString()).toString());

const tsInYears = new Bignumber(1)
.div(
new Bignumber((await space.ts()).toString()).div(
new Bignumber(10).pow(18)
)
)
.div(SECONDS_IN_A_YEAR);

const { tokens, balances } = await balancerVault.getPoolTokens(poolID);

const token0Decimals = await new ethers.Contract(
tokens[0],
["function decimals() external view returns (uint256)"],
provider
)
.decimals()
.then((t) => t.toNumber());

const balance0 = new Bignumber(balances[0].toString())
.div(new Bignumber(10).pow(token0Decimals))
.toString();

const token1Decimals = await new ethers.Contract(
tokens[1],
["function decimals() external view returns (uint256)"],
provider
)
.decimals()
.then((t) => t.toNumber());

const balance1 = new Bignumber(balances[1].toString())
.div(new Bignumber(10).pow(token1Decimals))
.toString();

const pti = await space.pti();
const totalSupply = new Bignumber(
await space.totalSupply().then((ts) => ts.toString())
).div(ethers.utils.parseEther("1").toString());

let ir = 0;
let ir2 = 0;
let ptPricePerTargetFromIr = 0;
if (balance0 !== "0" && balance1 !== "0") {
const iscale = new Bignumber(seriesObj.iscale.toString()).div(
ethers.utils.parseEther("1").toString()
);
if (pti.eq(1)) {
ir = new Bignumber(balance1)
.plus(totalSupply)
.div(new Bignumber(balance0).times(iscale))
.minus(1);

ir2 = new Bignumber(
ir.plus(1).toNumber() ** (1 / tsInYears.toNumber())
).minus(1);
} else {
ir = new Bignumber(balance0)
.plus(totalSupply)
.div(new Bignumber(balance1).times(iscale))
.minus(1);

ir2 = new Bignumber(
ir.plus(1).toNumber() ** (1 / tsInYears.toNumber())
).minus(1);
}

ptPricePerTargetFromIr = await space.getPriceFromImpliedRate(
ir
.times(ethers.utils.parseEther("1").toString())
.decimalPlaces(0)
.toString()
);
}

// pt price from pseudo swap

_poolData[adapterAddress] = {
[maturity]: {
spaceAddress,
poolID,
token0: tokens[0],
token1: tokens[1],
balance0,
balance1,
timeShift,
oracleReady,
ir: ir.toString(),
ir2: ir2.toString(),
ptPricePerTargetFromIr: new Bignumber(
ptPricePerTargetFromIr.toString()
)
.div(ethers.utils.parseEther("1").toString())
.toString(),
ptPricePerUnderlyingFromIr: new Bignumber(
ptPricePerTargetFromIr.toString()
)
.div(ethers.utils.parseEther("1").toString())
.times(
new Bignumber(_adapterData.scale.toString()).div(
ethers.utils.parseEther("1").toString()
)
)
.toString()
},
..._poolData[adapterAddress]
};
}
}
return _poolData;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
CURRENT_BLOCK = provider.getBlockNumber()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function getLatestPrices(tokenAddresses) {
if (tokenAddresses.length === 0) return {};
const uniqueTokenAddresses = [...new Set(tokenAddresses)];

const { coins } = await fetch(
`${DEFI_LLAMA_LATEST_PRCE_ENDPOINT}${uniqueTokenAddresses.map((t) => `ethereum:${t},`)}`
).then(r => r.json());

const coinsObjs = Object.values(coins);
const prices = coinsObjs.reduce((acc, c) => {
acc[c.symbol] = c.price;
return acc;
}, {});

return prices;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more