Skip to content

Commit

Permalink
Merge pull request #238 from balancer-labs/develop
Browse files Browse the repository at this point in the history
Release 0.1.39
  • Loading branch information
johngrantuk authored Dec 7, 2022
2 parents b202076 + 9dee7bf commit bf8f67c
Show file tree
Hide file tree
Showing 101 changed files with 11,221 additions and 2,063 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/balancer-js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,6 @@ env:
INFURA: ${{ secrets.INFURA }}
ALCHEMY_URL: ${{ secrets.ALCHEMY_URL }}
ALCHEMY_URL_GOERLI: ${{ secrets.ALCHEMY_URL_GOERLI }}
TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }}
TENDERLY_PROJECT: ${{ secrets.TENDERLY_PROJECT }}
TENDERLY_USER: ${{ secrets.TENDERLY_USER }}
51 changes: 51 additions & 0 deletions .github/workflows/beta-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Beta release

on:
pull_request:
types:
- closed
branches:
- develop

defaults:
run:
working-directory: balancer-js

jobs:
build_and_release:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: develop
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: actions/cache@v2
id: cache
with:
path: "**/node_modules"
key: yarn-v1-${{ hashFiles('**/yarn.lock') }}
- run: yarn --immutable
if: steps.cache.outputs.cache-hit != 'true'
- env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
run: |
echo -n "$SIGNING_KEY" | base64 --decode | gpg --import
git config --global user.name "gmbronco"
git config --global user.email "[email protected]"
git config user.signingkey A33ABD316E6629F6
git config gpg.program /usr/bin/gpg
yarn version --prerelease --no-git-tag-version
export NEW_VERSION=$(jq -r '.version' package.json)
git commit -S -am "chore: version bump v$NEW_VERSION"
git tag "v$NEW_VERSION"
yarn build
yarn publish --non-interactive --tag beta
git push
env:
CI: true
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1 change: 1 addition & 0 deletions balancer-js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ yarn-error.log
dist/
src/subgraph/generated/
cache/
balancer-js.iml
Binary file added balancer-js/IL-class.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
161 changes: 157 additions & 4 deletions balancer-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ A JavaScript SDK which provides commonly used utilties for interacting with Bala
4. Create a .env file in the balancer-js folder
5. In the .env file you will need to define and initialize the following variables

We have defined both Alchemy and Infura, because some of the examples use Infura, others use Alchemy. However, feel free to modify accordingly and use your favourite one.
ALCHEMY_URL=[ALCHEMY HTTPS ENDPOINT]
INFURA=[Infura API KEY]
TRADER_KEY=[MetaMask PRIVATE KEY]
We have defined both Alchemy and Infura, because some of the examples use Infura, others use Alchemy. However, feel free to modify accordingly and use your favourite one.
Some examples also require the following Tenderly config parameters to be defined:
TENDERLY_ACCESS_KEY=[TENDERLY API ACCESS KEY]
TENDERLY_PROJECT=[TENDERLY PROJECT NAME]
TENDERLY_USER=[TENDERLY USERNAME]

6. Run 'npm run node', this runs a local Hardhat Network
7. Open a new terminal
Expand Down Expand Up @@ -285,17 +289,19 @@ async getSpotPrice(

[Example](./examples/spotPrice.ts)

## Join Pool
## Joining Pools

Exposes Join functionality allowing user to join pools.
### Joining with pool tokens

Exposes Join functionality allowing user to join pools with its pool tokens.

```js
const balancer = new BalancerSDK(sdkConfig);
const pool = await balancer.pools.find(poolId);
const { to, functionName, attributes, data } = pool.buildJoin(params);
```

### #buildJoin
#### #buildJoin

Builds a join transaction.

Expand All @@ -317,6 +323,51 @@ buildJoin: (

[Example](./examples/join.ts)

### Joining nested pools

Exposes Join functionality allowing user to join a pool that has pool tokens that are BPTs of other pools, e.g.:

```
CS0
/ \
CS1 CS2
/ \ / \
DAI USDC USDT FRAX
Can join with tokens: DAI, USDC, USDT, FRAX, CS1_BPT, CS2_BPT
```

```js
/**
* Builds generalised join transaction
*
* @param poolId Pool id
* @param tokens Token addresses
* @param amounts Token amounts in EVM scale
* @param userAddress User address
* @param wrapMainTokens Indicates whether main tokens should be wrapped before being used
* @param slippage Maximum slippage tolerance in bps i.e. 50 = 0.5%.
* @param authorisation Optional auhtorisation call to be added to the chained transaction
* @returns transaction data ready to be sent to the network along with min and expected BPT amounts out.
*/
async generalisedJoin(
poolId: string,
tokens: string[],
amounts: string[],
userAddress: string,
wrapMainTokens: boolean,
slippage: string,
authorisation?: string
): Promise<{
to: string;
callData: string;
minOut: string;
expectedOut: string;
}>
```

[Example](./examples/joinGeneralised.ts)

## Exit Pool

Exposes Exit functionality allowing user to exit pools.
Expand Down Expand Up @@ -371,6 +422,48 @@ Builds an exit transaction with exact tokens out and maximum BPT in based on sli

[Example](./examples/exitExactTokensOut.ts)

### Exiting nested pools

Exposes Exit functionality allowing user to exit a pool that has pool tokens that are BPTs of other pools, e.g.:

```
CS0
/ \
CS1 CS2
/ \ / \
DAI USDC USDT FRAX
Can exit with CS0_BPT proportionally to: DAI, USDC, USDT and FRAX
```

```js
/**
* Builds generalised exit transaction
*
* @param poolId Pool id
* @param amount Token amount in EVM scale
* @param userAddress User address
* @param slippage Maximum slippage tolerance in bps i.e. 50 = 0.5%.
* @param authorisation Optional auhtorisation call to be added to the chained transaction
* @returns transaction data ready to be sent to the network along with tokens, min and expected amounts out.
*/
async generalisedExit(
poolId: string,
amount: string,
userAddress: string,
slippage: string,
authorisation?: string
): Promise<{
to: string;
callData: string;
tokensOut: string[];
expectedAmountsOut: string[];
minAmountsOut: string[];
}>
```

[Example](./examples/exitGeneralised.ts)

## RelayerService

Relayers are (user opt-in, audited) contracts that can make calls to the vault (with the transaction “sender” being any arbitrary address) and use the sender’s ERC20 vault allowance, internal balance or BPTs on their behalf.
Expand Down Expand Up @@ -476,6 +569,66 @@ async relayer.exitPoolAndBatchSwap(

[Example](./examples/relayerExitPoolAndBatchSwap.ts)

### Pools Impermanent Loss

> DRAFT
>
> impermanent loss (IL) describes the percentage by which a pool is worth less than what one would have if they had instead just held the tokens outside the pool

#### Service

![class-diagram](IL-class.png)

#### Algorithm

Using the variation delta formula:

![img.png](img.png)

where **𝚫P<sup>i</sup>** represents the difference between the price for a single token at the date of joining the pool and the current price.

```javascript

// retrieves pool's tokens
tokens = pool.tokens;
// get weights for tokens
weights = tokens.map((token) => token.weight);
// retrieves current price for tokens
exitPrices = tokens.map((token) => tokenPrices.find(token.address));
// retrieves historical price for tokens
entryPrices = tokens.map((token) => tokenPrices.findBy('timestamp', { address: token.address, timestamp: timestamp}));
// retrieves list of pool's assets with prices delta and weights
assets = tokens.map((token) => ({
priceDelta: this.getDelta(entryPrices[token.address], exitPrices[token.address]),
weight: weights[i],
}));

poolValueDelta = assets.reduce((result, asset) => result * Math.pow(Math.abs(asset.priceDelta + 1), asset.weight), 1);
holdValueDelta = assets.reduce((result, asset) => result + (Math.abs(asset.priceDelta + 1) * asset.weight), 0);

const IL = poolValueDelta/holdValueDelta - 1;
```

#### Usage

```javascript
async impermanentLoss(
timestamp: number, // the UNIX timestamp from which the IL is desired
pool: Pool // the pool on which the IL must be calculated
): Promise<number>
```

```javascript
const pool = await sdk.pools.find(poolId);
const joins = (await sdk.data.findByUser(userAddress)).filter((it) => it.type === "Join" && it.poolId === poolId);
const join = joins[0];
const IL = await pools.impermanentLoss(join.timestamp, pool);
```

[Example](./examples/pools/impermanentLoss.ts)


## Licensing

[GNU General Public License Version 3 (GPL v3)](../../LICENSE).
61 changes: 61 additions & 0 deletions balancer-js/examples/data/pool-joinExit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { BalancerSDK, Network } from '../../src';
import { InvestType } from '../../src/modules/subgraph/generated/balancer-subgraph-types';
import { PoolJoinExit } from '../../src/modules/data/pool-joinExit';

// Balancer subgraph : https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2

// npm run examples:run -- ./examples/data/pool-joinExit.ts

const sdk = new BalancerSDK({
network: Network.POLYGON,
rpcUrl: '',
});
const { poolJoinExits } = sdk.data;

const format = (result: PoolJoinExit[]): string => {
return result
.map(
(it) =>
`${it.poolId}\t${it.type}\t${new Date(
it.timestamp * 1000
).toLocaleString()}`
)
.join('\n');
};

(async function () {
const USER_ADDR = '0xdfe6e354ce787944e67cc04ad4404a43f3112a10';
const POOL_ID =
'0x36128d5436d2d70cab39c9af9cce146c38554ff0000100000000000000000008';
let result;

result = await poolJoinExits.findByPool(POOL_ID, 5);
if (result.length) {
const item = result[0];
console.log(
`Pool JoinExit by Pool Id:\n${item.type}\t${new Date(
item.timestamp * 1000
).toLocaleString()}\t${item.tokens}`
);
}

result = await poolJoinExits.findByUser(USER_ADDR, 5);
console.log(`Pool JoinExit by User:\n${format(result)}`);

const poolId = result[0].poolId;

result = await poolJoinExits.query({
where: { pool: poolId, sender: USER_ADDR },
});
console.log(`Pool JoinExit Query by PoolId and User:\n${format(result)}`);

result = await poolJoinExits.findJoins(USER_ADDR, poolId);
console.log(
`Pool JoinExit Query by PoolId and User and Type Join:\n${format(result)}`
);

result = await poolJoinExits.findExits(USER_ADDR, poolId);
console.log(
`Pool JoinExit Query by PoolId and User and Type Exit:\n${format(result)}`
);
})();
20 changes: 20 additions & 0 deletions balancer-js/examples/data/token-prices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Display APRs for pool ids hardcoded under `const ids`
* Run command: yarn examples:run ./examples/data/token-prices.ts
*/
import { BalancerSDK } from '@/.';

const sdk = new BalancerSDK({ network: 1, rpcUrl: '' });
const { data } = sdk;
const dai = '0x6b175474e89094c44da98b954eedeac495271d0f';
const eth = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
const matic = '0x0000000000000000000000000000000000001010';
const tetuBal = '0x7fc9e0aa043787bfad28e29632ada302c790ce33';

(async () => {
// It will be just one request to coingecko
const ps = [eth, dai, tetuBal, matic, eth, dai, tetuBal, matic].map((t) => data.tokenPrices.find(t));
const price = await Promise.all(ps);

console.log(price);
})();
14 changes: 12 additions & 2 deletions balancer-js/examples/data/token-yields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ import { yieldTokens } from '../../src/modules/data/token-yields/tokens/aave';
const sdk = new BalancerSDK({ network: 1, rpcUrl: '' });
const { data } = sdk;

const tokens = [
yieldTokens[1].waDAI,
'0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', // stMatic
'0xae7ab96520de3a18e5e111b5eaab095312d7fe84' // stETH
]

const main = async () => {
const tokenYield = await data.tokenYields.find(yieldTokens.waDAI);
const yields = await Promise.all(
tokens.map((token) => data.tokenYields.find(token))
)

console.log(yieldTokens.waDAI, tokenYield);
tokens.forEach((token, id) => {
console.log(token, yields[id])
})
};

main();
Loading

0 comments on commit bf8f67c

Please sign in to comment.