Skip to content

Commit

Permalink
Merge pull request #347 from balancer-labs/develop
Browse files Browse the repository at this point in the history
Release 1.0.0
  • Loading branch information
johngrantuk authored Feb 22, 2023
2 parents ecccc08 + 920a6b0 commit fac5e6f
Show file tree
Hide file tree
Showing 143 changed files with 13,356 additions and 4,274 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/balancer-js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ jobs:
run: npx hardhat --tsconfig tsconfig.testing.json node --hostname 127.0.0.1 --fork ${{ secrets.ALCHEMY_URL }} &
- name: Run goerli node in background for integration tests
run: npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.goerli.ts node --hostname 127.0.0.1 --fork ${{ secrets.ALCHEMY_URL_GOERLI }} --port 8000 &
- name: Run Polygon node in background for integration tests
run: npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.polygon.ts node --hostname 127.0.0.1 --fork ${{ secrets.ALCHEMY_URL_POLYGON }} --port 8137 &
- name: Test
run: yarn test

Expand All @@ -90,6 +92,7 @@ env:
INFURA: ${{ secrets.INFURA }}
ALCHEMY_URL: ${{ secrets.ALCHEMY_URL }}
ALCHEMY_URL_GOERLI: ${{ secrets.ALCHEMY_URL_GOERLI }}
ALCHEMY_URL_POLYGON: ${{ secrets.ALCHEMY_URL_POLYGON }}
TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }}
TENDERLY_PROJECT: ${{ secrets.TENDERLY_PROJECT }}
TENDERLY_USER: ${{ secrets.TENDERLY_USER }}
4 changes: 2 additions & 2 deletions .github/workflows/beta-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ jobs:
run: |
echo -n "$SIGNING_KEY" | base64 --decode | gpg --import
git config --global user.name "johngrantuk"
git config --global user.email "johngrantuk+bot@users.noreply.github.com"
git config user.signingkey AFFC8986D78B522F2999BAE053C748C476381000
git config --global user.email "4797222+johngrantuk@users.noreply.github.com"
git config user.signingkey 0B86E3F46D321811DC4330D1376AF1CD2A15D127
git config gpg.program /usr/bin/gpg
yarn version --prerelease --preid beta --no-git-tag-version
export NEW_VERSION=$(jq -r '.version' package.json)
Expand Down
1 change: 0 additions & 1 deletion balancer-js/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
node_modules
dist
**/examples
**/generated
1 change: 1 addition & 0 deletions balancer-js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dist/
src/subgraph/generated/
cache/
balancer-js.iml
temp/
124 changes: 111 additions & 13 deletions balancer-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@ buildJoin: (
[Example](./examples/join.ts)

### #buildInitJoin (Weighted Pool)

Builds a init join transaction for weighted pool.

```js
/***
* @param params
Expand All @@ -398,9 +400,11 @@ Builds a init join transaction for weighted pool.
poolId,
tokensIn,
amountsIn,
}) => InitJoinPoolAttributes
}) => InitJoinPoolAttributes
```
[Example](./examples/pools/weighted/init-join.ts)
Available pool types:
- Weighted

### Joining nested pools

Expand All @@ -426,6 +430,8 @@ Can join with tokens: DAI, USDC, USDT, FRAX, CS1_BPT, CS2_BPT
* @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 signer JsonRpcSigner that will sign the staticCall transaction if Static simulation chosen
* @param simulationType Simulation type (VaultModel, Tenderly or Static)
* @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.
*/
Expand All @@ -436,12 +442,15 @@ Can join with tokens: DAI, USDC, USDT, FRAX, CS1_BPT, CS2_BPT
userAddress: string,
wrapMainTokens: boolean,
slippage: string,
signer: JsonRpcSigner,
simulationType: SimulationType,
authorisation?: string
): Promise<{
to: string;
callData: string;
encodedCall: string;
minOut: string;
expectedOut: string;
priceImpact: string;
}>
```

Expand Down Expand Up @@ -501,7 +510,13 @@ export interface ExitExactBPTInAttributes extends ExitPoolAttributes {
}
```

[Example](./examples/exitExactBPTIn.ts)
[Example](./examples/exitExactBPTIn.ts)<br/><br/>
Available pool types:
- Weighted [Example](./examples/exitExactBPTIn.ts)
- Composable Stable [Example](./examples/pools/composable-stable/exit.ts)
- OBS: **Only ComposableStable >V2 supports proportional exits**
- Meta Stable
- Stable

### #buildExitExactTokensOut

Expand Down Expand Up @@ -546,7 +561,12 @@ export interface ExitExactTokensOutAttributes extends ExitPoolAttributes {
```

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

<br/><br/>
Available pool types:
- Weighted [Example](./examples/exitExactTokensOut.ts)
- Composable Stable
- Meta Stable
- Stable
### Exiting nested pools

Exposes Exit functionality allowing user to exit a pool that has pool tokens that are BPTs of other pools, e.g.:
Expand All @@ -565,25 +585,30 @@ Can exit with CS0_BPT proportionally to: DAI, USDC, USDT and FRAX
/**
* 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
* @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 signer JsonRpcSigner that will sign the staticCall transaction if Static simulation chosen
* @param simulationType Simulation type (VaultModel, Tenderly or Static)
* @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,
signer: JsonRpcSigner,
simulationType: SimulationType,
authorisation?: string
): Promise<{
to: string;
callData: string;
encodedCall: string;
tokensOut: string[];
expectedAmountsOut: string[];
minAmountsOut: string[];
priceImpact: string;
}>
```

Expand Down Expand Up @@ -764,10 +789,8 @@ async relayer.exitPoolAndBatchSwap(

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

### Pools Impermanent Loss
## 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
Expand Down Expand Up @@ -838,6 +861,81 @@ const IL = await pools.impermanentLoss(join.timestamp, pool);

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

## Claim Tokens

### Service

![classes](./claim-incentives-class.png)

### Claim Tokens for a veBAL Holders

#### Pseudocode

* **Get Claimable Rewards**

```javascript
const defaultClaimableTokens = [
'0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2', // bb-a-USD v1
'0xA13a9247ea42D743238089903570127DdA72fE44', // bb-a-USD v2
'0xba100000625a3754423978a60c9317c58a424e3D', // BAL
]

const claimableTokens: string[] = userDefinedClaimableTokens ?? defaultClaimableTokens;

const balances = await ClaimService.getClaimableVeBalTokens(userAddress, claimableTokens) {
return await this.feeDistributor.callStatic.claimTokens(userAddress,claimableTokens);
}

const txData = await getClaimableVeBalTokens.buildClaimVeBalTokensRequest(userAddress, claimableTokens) {
data = feeDistributorContract.claimBalances(userAddress, claimableTokens);
to = feeDistributorContract.encodeFunctionData('claimTokens', [userAddress, claimableTokens])
}

//on client
signer.request(txData).then(() => { ... });

```
### Claim Pools Incentives
#### Pseudocode
* **Get Claimable Rewards**
```javascript
gauges = LiquidityGaugesRepository.fetch();
claimableTokensPerGauge = LiquidityGaugesMulticallRepository.getClaimableTokens(gauges, accountAddress) {
if (MAINNET) {
claimableTokens = this.multicall.aggregate('claimable_tokens', gauges, accountAddress);
claimableReward = gauge.rewardData.forEach(this.multicall.aggregate('claimable_reward', gauges, accountAddress, rewardToken);
return aggregate(claimableReward, claimableTokens);
} else {
return gauge.rewardData.forEach(this.multicall.aggregate('claimable_reward', gauges, accountAddress, rewardToken);
}
};

```
* **Claim Rewards**
it returns encoded callable data to be fed to a signer and then to send to the gauge contract.
```javascript

if (MAINNET) {
const callData = balancerMinterInterface.encodeFunctionData(
'mintMany',
[gaugeAddresses]
);
return { to: balancerMinterAddress, data: callData }
} else {
const callData = gaugeClaimHelperInterface.encodeFunctionData(
'claimRewardsFromGauges',
[gaugeAddresses, userAddress]
);
return { to: gaugeClaimHelperAddress, data: callData }
}

```
## Licensing
[GNU General Public License Version 3 (GPL v3)](../../LICENSE).
Binary file added balancer-js/claim-incentives-class.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions balancer-js/claim-incentives-class.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@startuml
'https://plantuml.com/class-diagram

class BalancerSDK

class ClaimService {
}

interface IClaimService {
+getClaimableRewardTokens(userAddress):LiquidityGauge[]
+buildClaimRewardTokensRequest(gaugeAddresses, userAddress):TransactionData
+getClaimableVeBalTokens(userAddress): TokenBalance[]
+buildClaimVeBalTokensRequest(userAddress): TransactionData
}

interface BaseFeeDistributor {
multicallData: (ts: number) => Promise<FeeDistributorData>;
getClaimableBalances(userAddress: string, claimableTokens: string[]): Promise<TokenBalance>;
claimBalances(userAddress: string, claimableTokens: string[]): string;
}
class FeeDistributorRepository {
}

class FeeDistributor <<Contract>> {
+claimTokens(userAddress, tokens): TokenBalance
}

class TokenBalance {
[key:string]:BigNumber
}

interface TransactionData {
+to: string
+from: string
+functionName: string
+args: any[]
+data: string
}

interface LiquidityGauge {
id: string;
address: string;
name: string;
poolId?: Maybe<string>;
poolAddress: string;
totalSupply: number;
workingSupply: number;
relativeWeight: number;
}

BalancerSDK -l-> ClaimService

ClaimService .up.|> IClaimService
ClaimService -l-> FeeDistributorRepository

ClaimService .down. "produces" TransactionData
ClaimService .down. "update" LiquidityGauge

LiquidityGauge --> "*" TokenBalance: claimableTokens

FeeDistributorRepository .up.|> BaseFeeDistributor
FeeDistributorRepository -left-> FeeDistributor
@enduml
54 changes: 54 additions & 0 deletions balancer-js/examples/claimPoolsRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {Network} from "@/lib/constants";
import {BalancerSDK} from "@/modules/sdk.module";
import {forkSetup} from "@/test/lib/utils";
import hardhat from "hardhat";

const userAddress = '0x549c660ce2B988F588769d6AD87BE801695b2be3';

const rpcUrl = 'http://127.0.0.1:8545';
const blockNumber = 16361617;
const { ethers } = hardhat;
const provider = new ethers.providers.JsonRpcProvider(rpcUrl, 1);
const signer = provider.getSigner();
const jsonRpcUrl = 'https://rpc.ankr.com/eth';
const sdk = new BalancerSDK(
{
network: Network.MAINNET,
rpcUrl: rpcUrl
});
const { claimService } = sdk;

(async function () {

await forkSetup(signer, [], [], [], jsonRpcUrl as string, blockNumber);

if (!claimService) throw new Error("ClaimService not defined");
const balanceGauges = await claimService.getClaimableRewardTokens(userAddress);
console.table(balanceGauges.map((it) => it.claimableTokens));
const gauges = balanceGauges.map((it) => it.address);
let data = await claimService.buildClaimRewardTokensRequest(gauges.slice(0,1), userAddress);
console.log(`\nSingle Gauge Claim ( gauge: ${gauges.slice(0,1)})
to: ${data.to} - BalancerMinter Address ${sdk.networkConfig.addresses.contracts.balancerMinterAddress}
from: ${data.from} - User Address ${userAddress}
tokensOut: ${data.tokensOut}
expectedTokensValue: ${data.expectedTokensValue}
functionName: ${data.functionName}
callData: ${data.callData.slice(0, 10)}...${data.callData.slice(-5)}
`)
data = await claimService.buildClaimRewardTokensRequest(gauges, userAddress);
console.log(`\nMultiple Gauges Claim
to: ${data.to} - BalancerMinter Address ${sdk.networkConfig.addresses.contracts.balancerMinterAddress}
from: ${data.from} - User Address ${userAddress}
tokensOut: ${data.tokensOut}
expectedTokensValue: ${data.expectedTokensValue}
functionName: ${data.functionName}
callData: ${data.callData.slice(0, 10)}...${data.callData.slice(-5)}
`)

console.log(`\n\nfinally:
const tx = { to: data.to', data: callData };
const receipt = await (await signer.sendTransaction(tx)).wait();
`)

})();
Loading

0 comments on commit fac5e6f

Please sign in to comment.