Skip to content
This repository has been archived by the owner on Feb 19, 2024. It is now read-only.

Basic router docs #2

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ node_modules

rendered-ts/

.private-key*
.private-key*
.yarn
8 changes: 8 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
nodeLinker: node-modules

npmScopes:
pendle:
npmPublishRegistry: "https://registry.npmjs.org/"
npmRegistryServer: "https://registry.npmjs.org/"
npmAlwaysAuth: true
npmAuthToken: ${PENDLE_SDK_V2_NPM_AUTH_TOKEN:-Please set your access token}
210 changes: 210 additions & 0 deletions docs/BasicRouter.nnb
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
{
"cells": [
{
"language": "markdown",
"source": [
"# Pendle SDK `BasicRouter`\n\n---"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"`Router` is the main feature of Pendle SDK. It handles all the trading logic while ensuring the user will receive the optimal amount after trades. It also returns the intermediate results, allowing us to do further calculations.\n\n`BasicRouter` is a simple implementation of `Router` that doesn't support the use of aggregator (e.g KyberSwap), and doesn't support bulkSeller."
],
"outputs": []
},
{
"language": "markdown",
"source": [
"## Getting started"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"### Create a Basic Router instance"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"Suppose that we want to create a router on Mainnet(with chain id of `1`). "
],
"outputs": []
},
{
"language": "typescript",
"source": [
"const chainId = 1;"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"First, we need to have a `Signer` and/or a `Provider`. Most of the time, `Signer` can be used. But when sending transaction is not required, `Provider` is enough. "
],
"outputs": []
},
{
"language": "javascript",
"source": [
"\n\nimport { providers } from 'ethers';\nimport { BasicRouter } from '@pendle/sdk-v2';\n\nconst providerUrl = 'https://rpc.ankr.com/eth'\nconst provider = new providers.StaticJsonRpcProvider(providerUrl);\n\nconst basicRouter = BasicRouter.getBasicRouter({ chainId, provider });"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"## Example: swap from known amount of token to PT\n\nBefore doing any action, we should first have an address of a Pendle Market to interact with. [Pendle Backend][Pendle-Backend] can be used to obtain the whitelisted markets. For demonstration, we are going to use the FRAX USDC market, with the token in is USDC:\n\n<!-- TODO update docs link -->\n[Pendle-Backend]: https://api-v2.pendle.finance/core/graphql"
],
"outputs": []
},
{
"language": "typescript",
"source": [
"import { toAddress } from '@pendle/sdk-v2';\n// FRAX USDC market address\nconst marketAddress = toAddress('0x7b246b8dbc2a640bf2d8221890cee8327fc23917');\n// USDC token address\nconst tokenAddress = toAddress('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48');"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"Now suppose we want to simulate trade some USDC to the market's PT token. We can use `BasicRouter`'s `swapExactTokenForPt` method as follows:"
],
"outputs": []
},
{
"language": "typescript",
"source": [
"import { BN } from '@pendle/sdk-v2';\n// BN is the alias of ethers.BigNumber\nconst slippage = 1 / 100; // 1% slippage\nconst amount = BN.from(100000000); // 100 USDC\nconst metaMethod = await basicRouter.swapExactTokenForPt(\n marketAddress,\n tokenAddress, // token address\n amount, // token amount\n slippage,\n {\n method: 'meta-method'\n }\n);"
],
"outputs": []
},
{
"language": "typescript",
"source": [
"import { calcSlippedDownAmount, BaseRouter } from '@pendle/sdk-v2';\nconst simulateData = metaMethod.data;\nconst netPtOut = simulateData.netPtOut;\nconst minPtOut = calcSlippedDownAmount(netPtOut, slippage);\nconst guessParams = BaseRouter.guessOutApproxParams(netPtOut, slippage);\nconst tokenInputData = simulateData.input;\nconsole.log({\n 'netPtOut': netPtOut.toString(),\n 'minPtOut': minPtOut.toString(),\n 'tokenInputData': tokenInputData, // this is the input data to pass in the router contract\n 'guessParams': guessParams\n});"
],
"outputs": [
{
"items": [
{
"mime": "application/vnd.code.notebook.stdout",
"value": [
"{",
" netPtOut: '100266946016548822645',",
" minPtOut: '99264276556383334418',",
" tokenInputData: {",
" tokenIn: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',",
" netTokenIn: BigNumber { _hex: '0x05f5e100', _isBigNumber: true },",
" tokenMintSy: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',",
" kybercall: [],",
" bulk: '0x0000000000000000000000000000000000000000',",
" kyberRouter: '0x0000000000000000000000000000000000000000'",
" },",
" guessParams: {",
" guessMin: BigNumber { _hex: '0x0561918d9a755d3012', _isBigNumber: true },",
" guessMax: BigNumber { _hex: '0x05b50ebcf92724c661', _isBigNumber: true },",
" guessOffchain: BigNumber { _hex: '0x056f7bc02a3da91e75', _isBigNumber: true },",
" maxIteration: 9,",
" eps: '1000000000000000'",
" }",
"}",
""
]
}
]
}
]
},
{
"language": "markdown",
"source": [
"Now we can use those calculated values to call the router contract's `swapExactTokenForPt` method:\n```ts\nconst routerContract = /* get the router contract */\nrouterContract.connect(/* signer */).swapExactTokenForPt(\n receiver,\n marketAddress,\n minPtOut,\n guessParams,\n input\n);\n```"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"## Example: swap from known amount of PT to Token"
],
"outputs": []
},
{
"language": "typescript",
"source": [
"const exactPtIn = BN.from(10).pow(18).mul(100); // 100 PT\nconst metaMethod = await basicRouter.swapExactPtForToken(\n marketAddress,\n exactPtIn, // amount of pt in\n tokenAddress, // token address\n slippage,\n {\n method: 'meta-method'\n }\n);"
],
"outputs": []
},
{
"language": "typescript",
"source": [
"import { calcSlippedDownAmount } from '@pendle/sdk-v2';\nconst simulateData = metaMethod.data;\nconst netTokenOut = simulateData.netTokenOut;\nconst minTokenOut = calcSlippedDownAmount(netTokenOut, slippage);\nconst tokenOutputData = simulateData.output;\nconsole.log({\n 'netTokenOut': netTokenOut.toString(),\n 'minTokenOut': minTokenOut.toString(),\n 'tokenOutputData': tokenOutputData,\n});"
],
"outputs": [
{
"items": [
{
"mime": "application/vnd.code.notebook.stdout",
"value": [
"{",
" netTokenOut: '99695192',",
" minTokenOut: '98698240',",
" tokenOutputData: {",
" tokenOut: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',",
" minTokenOut: BigNumber { _hex: '0x05e20400', _isBigNumber: true },",
" tokenRedeemSy: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',",
" kybercall: [],",
" bulk: '0x0000000000000000000000000000000000000000',",
" kyberRouter: '0x0000000000000000000000000000000000000000'",
" }",
"}",
""
]
}
]
}
]
},
{
"language": "markdown",
"source": [
"Now we can use those calculated values to call the router contract's `swapExactPtForToken` method:\n```ts\nconst routerContract = /* get the router contract */\nrouterContract.connect(/* signer */).swapExactPtForToken(\n receiver,\n marketAddress,\n exactPtIn,\n output\n);\n```"
],
"outputs": []
},
{
"language": "markdown",
"source": [
"## Handling error\n\nPendle SDK is based on Ethersjs, which is a very versatile library. But while handling all the interactions with the contract, Ethersjs’ error handling process is very cryptic. Ethersjs Error does not support typing, as well as the actual error is often nested very deeply. Pendle SDK includes some utilities that helps aid the error handling process while interacting with the contracts.\n\n\nWhen error, Pendle contracts will thrown an Error message defined in [this contract](https://github.com/pendle-finance/pendle-core-v2/blob/main/contracts/core/libraries/Errors.sol). Those error will be wrapped into the `PendleContractError`. The instance of this class has two main properties:\n- `errorName` - the name of the error.\n- `args` - the arguments that passed to the error on the contract side. "
],
"outputs": []
},
{
"language": "typescript",
"source": [
"import { PendleContractError, BN } from '@pendle/sdk-v2';\ntry {\n const veryLargeAmount = BN.from(10).pow(18); // 1e12 USDC\n const metaMethod = await basicRouter.swapExactTokenForPt(\n marketAddress,\n tokenAddress, // token address\n veryLargeAmount, // token amount\n slippage,\n {\n method: 'meta-method'\n }\n );\n} catch (e) {\n if (e instanceof PendleContractError) {\n console.log(\"ErrorName: \", e.errorName);\n if (e.isType('ApproxFail')) {\n console.log('ApproxFail', e.args);\n // do something\n } else if (e.isType('MarketExpired')) {\n // do something\n } else {\n // ...\n }\n }\n}"
],
"outputs": [
{
"items": [
{
"mime": "application/vnd.code.notebook.stdout",
"value": [
"ErrorName: ApproxFail",
"ApproxFail []",
""
]
}
]
}
]
}
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "index.js",
"license": "MIT",
"dependencies": {
"@pendle/sdk-v2": "^1.0.12-mainnet",
"@pendle/sdk-v2": "1.6.2-mainnet",
"ansi-to-html": "^0.7.2",
"node-metamask": "^1.1.2"
},
Expand Down
Loading