Skip to content

Commit

Permalink
Implement Auto params calculation (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
ngfam authored Jul 18, 2023
1 parent a3dfb55 commit faeb910
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 29 deletions.
36 changes: 23 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,34 @@ PRIVATE_KEY=...

**Note**: `ETHERSCAN_KEY` should match the block explorer key of the network you are deploying.


## Hardhat configuration

Firstly, configure your network (arbitrum/bsc/mainnet) inside `./hardhat.config.ts`.

Secondly, please also configure the `NETWORK` variable in `./scripts/configuration.ts` accordingly:

```ts
export const NETWORK = SUPPORTED_CHAINS.MAINNET;
```

## Deployment

### Contract and Parameters preparation

First step is to get your contract ready inside `./contracts/` folder as we currently have `./contracts/SwETHSY.sol`.

After that, you will have to fill in the parameters for `MarketConfiguration` in `./scripts/configuration.ts`.
After that, you will have to fill in the parameters for the following parameters corresponding to your interest bearing token:
```ts
/**
* @dev The following parameters are used to calculate the market deployment params
* @minApy and @maxApy are the minimum and maximum APY of the interest bearing asset
* @startTimestamp and @endTimestamp are the start and end time of the market
*/
const minApy = 0.01; // 1%
const maxApy = 0.05; // 5%
const startTimestamp = 1689206400;
const endTimestamp = 1750896000;

export const MarketConfiguration = {
name: 'SY swETH',
symbol: 'SY-swETH',
doCacheIndex: true,
expiry: endTimestamp,
...calculateParameters(minApy, maxApy, startTimestamp, endTimestamp),
};
```

The remaining three fields in MarketConfiguration are `name`, `symbol` (quite straight-forward) and `doCacheIndex`. For `doCacheIndex`, we usually leave it as `true` for ethereum mainnet deployment and `false` for any other chain to save gas for PT/YT related transactions.

### Run deployment script

Expand Down Expand Up @@ -70,7 +80,7 @@ export const AMOUNT_TO_SEED = toWei(0.01);
### Run script

```
yarn hardhat run scripts/seed-liquidity.ts
yarn hardhat run scripts/seed-liquidity.ts --network <YOUR_NETWORK_NAME>
```

## Final notes
Expand Down
13 changes: 12 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,18 @@ const config: HardhatUserConfig = {
},
mainnet: {
url: 'https://rpc.ankr.com/eth',
accounts: [PRIVATE_KEY]
accounts: [PRIVATE_KEY],
chainId: 1
},
arbitrum: {
url: 'https://rpc.ankr.com/arbitrum',
accounts: [PRIVATE_KEY],
chainId: 42161
},
bsc: {
url: 'https://rpc.ankr.com/bsc',
accounts: [PRIVATE_KEY],
chainId: 56
}
},
solidity: {
Expand Down
18 changes: 13 additions & 5 deletions scripts/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { ZERO_ADDRESS } from './consts';
import { toWei } from './helper';
import { SUPPORTED_CHAINS } from './types';
import { calculateParameters } from './param-helper'

export const NETWORK = SUPPORTED_CHAINS.MAINNET;
/**
* @dev The following parameters are used to calculate the market deployment params
* @minApy and @maxApy are the minimum and maximum APY of the interest bearing asset
* @startTimestamp and @endTimestamp are the start and end time of the market
*/
const minApy = 0.01; // 1%
const maxApy = 0.05; // 5%
const startTimestamp = 1689206400;
const endTimestamp = 1750896000;

export const MarketConfiguration = {
name: 'SY swETH',
symbol: 'SY-swETH',
expiry: 1750896000,
scalarRoot: toWei(112.2782),
initialRateAnchor: toWei(1.08711),
doCacheIndex: true,
expiry: endTimestamp,
...calculateParameters(minApy, maxApy, startTimestamp, endTimestamp),
};

// address(0) is native
Expand All @@ -23,4 +31,4 @@ export const UNDERLYING_TO_SEED_LIQUIDITY = ZERO_ADDRESS;

// The toWei function multiply your input with 10^18 by default
// So do consider using customized amount (BN.from(10).pow(6) for example) for other cases
export const AMOUNT_TO_SEED = toWei(0.01);
export const AMOUNT_TO_SEED = toWei(0.01);
4 changes: 2 additions & 2 deletions scripts/consts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BigNumber as BN, Contract } from 'ethers';

export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
export const INF = BN.from(2).pow(256).sub(1);
export const SAFE_WAIT_TIME = 15000;
export const SAFE_WAIT_TIME = 15000;
14 changes: 11 additions & 3 deletions scripts/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ import bnbConfiguration from '@pendle/core-v2/deployments/56-core.json';
import { PendleContracts, SUPPORTED_CHAINS } from './types';
import { IERC20, IPAllAction, PendleMarketFactory, PendleYieldContractFactory } from '../typechain-types';
import { INF } from './consts';
import { NETWORK } from './configuration';

export function getNetwork() {
return {
[1]: SUPPORTED_CHAINS.MAINNET,
[56]: SUPPORTED_CHAINS.BSC,
[42161]: SUPPORTED_CHAINS.ARBITRUM,
}[hre.network.config.chainId!]!;
}

export function toWei(num: number): BN {
return BN.from(Math.floor(10 ** 9 * num)).mul(10 ** 9);
Expand Down Expand Up @@ -61,7 +68,7 @@ export async function getPendleContracts(): Promise<PendleContracts> {
[SUPPORTED_CHAINS.MAINNET]: ethereumConfiguration,
[SUPPORTED_CHAINS.ARBITRUM]: arbitrumConfiguration,
[SUPPORTED_CHAINS.BSC]: bnbConfiguration,
}[NETWORK];
}[getNetwork()];

return {
router: await getContractAt<IPAllAction>('IPAllAction', config.router),
Expand All @@ -84,4 +91,5 @@ export async function safeApproveInf(deployer: SignerWithAddress, token: string,
const contract = await getContractAt<IERC20>('IERC20', token);
const allowance = await contract.allowance(deployer.address, to);
if (allowance.lt(INF.div(2))) await contract.connect(deployer).approve(to, INF);
}
}

43 changes: 43 additions & 0 deletions scripts/param-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { toWei } from "./helper";

/**
* Validates the given start and end timestamps.
* @param {number} startTimestamp - The Unix timestamp (in seconds) for the start time.
* @param {number} endTimestamp - The Unix timestamp (in seconds) for the end time.
* @throws {Error} Will throw an error if the start timestamp is after or equal to the end timestamp, or if the end timestamp does not correspond to a Thursday at 12 AM UTC.
*/
function validateTimestamps(startTimestamp: number, endTimestamp: number) {
if (startTimestamp >= endTimestamp) throw Error('Start timestamp must be before end timestamp');
const endDate = new Date(endTimestamp * 1000); // convert Unix timestamp to JavaScript Date
const isValidEndDate =
endDate.getUTCDay() === 4 &&
endDate.getUTCHours() === 0 &&
endDate.getUTCMinutes() === 0 &&
endDate.getUTCSeconds() === 0;
if (!isValidEndDate) throw Error('Maturity must be at Thursday 12 AM');
}

/**
* Calculates the parameters scalarRoot and rateAnchor.
* @param {number} rateMin - The minimum rate (e.g. 1% APY = 0.01).
* @param {number} rateMax - The maximum rate (e.g. 5% APY = 0.05).
* @param {number} startTimestamp - The Unix timestamp (in seconds) for the start time.
* @param {number} endTimestamp - The Unix timestamp (in seconds) for the end time.
* @return {Object} An object containing the scalarRoot and rateAnchor values.
* @throws {Error} Will throw an error if the start timestamp is after or equal to the end timestamp, or if the end timestamp does not correspond to a Thursday at 12 AM UTC.
*/
export function calculateParameters(
rateMin: number,
rateMax: number,
startTimestamp: number,
endTimestamp: number
): { scalarRoot: BN; initialRateAnchor: BN } {
validateTimestamps(startTimestamp, endTimestamp);
const yearsToExpiry = (endTimestamp - startTimestamp) / 31536000;
const rateMinScaled = Math.pow(rateMin + 1, yearsToExpiry);
const rateMaxScaled = Math.pow(rateMax + 1, yearsToExpiry);
const initialRateAnchor = (rateMinScaled + rateMaxScaled) / 2;
const rateDiff = Math.max(Math.abs(rateMaxScaled - initialRateAnchor), Math.abs(initialRateAnchor - rateMinScaled));
const scalarRoot = (Math.log(9) * yearsToExpiry) / rateDiff;
return { scalarRoot: toWei(scalarRoot), initialRateAnchor: toWei(initialRateAnchor) };
}
8 changes: 3 additions & 5 deletions scripts/seed-liquidity.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ethers } from 'hardhat';
import {delay,getContractAt,getPendleContracts, safeApproveInf } from './helper';
import { delay, getContractAt, getPendleContracts, safeApproveInf } from './helper';
import { SUPPORTED_CHAINS } from './types';
import { INF, SAFE_WAIT_TIME, ZERO_ADDRESS } from './consts';
import { AMOUNT_TO_SEED, UNDERLYING_TO_SEED_LIQUIDITY } from './configuration';
import marketAddresses from '../deployments/SY-swETH.json'
import marketAddresses from '../deployments/SY-swETH.json';
import { IERC20, IStandardizedYield } from '../typechain-types';

async function main() {
Expand All @@ -21,7 +21,6 @@ async function main() {
await delay(SAFE_WAIT_TIME, 'after approve underlying');
}


const SY = await getContractAt<IStandardizedYield>('IStandardizedYield', marketAddresses.SY);
const PT = await getContractAt<IERC20>('IERC20', marketAddresses.PT);
const YT = await getContractAt<IERC20>('IERC20', marketAddresses.YT);
Expand Down Expand Up @@ -53,11 +52,10 @@ async function main() {
needScale: false,
},
},
{...overrides}
{ ...overrides }
);
await delay(SAFE_WAIT_TIME, 'after mintSyFromToken');


await SY.approve(pendleContracts.router.address, INF);

await delay(SAFE_WAIT_TIME, 'Before minting PY...');
Expand Down

0 comments on commit faeb910

Please sign in to comment.