Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to Deploy 11 #502

Merged
merged 8 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
5 changes: 5 additions & 0 deletions .changeset/fresh-hornets-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@balancer/sdk": minor
---

Update to testnet deployment 11
314 changes: 314 additions & 0 deletions examples/createAndInitPool/createAndInitPoolV3.ts
Copy link
Member

@MattPereira MattPereira Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This v3 pool creation script is still kinda messy and would benefit from Permit2helper method, but seems like decent pinch option for deploying v3 pools and could start discussion about examples that are set up to send transactions to live network

No worries if you prefer to dump it for this PR, just thought I'd offer the option for consideration

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can leave it in for now but should be tidied as part of wider example changes.

Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
/**
* Quick script to deploy partially boosted pool we need for testing
*
* Run with:
* pnpm example ./examples/createAndInitPool/createAndInitPoolV3.ts
*/

import { config } from 'dotenv';
config();

import {
// createTestClient,
http,
publicActions,
// walletActions,
zeroAddress,
parseUnits,
createWalletClient,
getContract,
PrivateKeyAccount,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import {
stablePoolFactoryAbi_V3,
CreatePoolV3StableInput,
CreatePool,
PoolType,
ChainId,
CHAINS,
InitPoolDataProvider,
InitPool,
InitPoolInput,
TokenType,
PERMIT2,
BALANCER_ROUTER,
permit2Abi,
erc20Abi,
MaxAllowanceExpiration,
PermitDetails,
Permit2Batch,
MaxSigDeadline,
AllowanceTransfer,
balancerRouterAbi,
PublicWalletClient,
} from 'src';
// import { startFork, ANVIL_NETWORKS } from 'test/anvil/anvil-global-setup';
import { findEventInReceiptLogs } from 'test/lib/utils/findEventInReceiptLogs';
// import { makeForkTx } from 'examples/lib/makeForkTx';
// import { getSlot } from 'examples/lib/getSlot';

const SWAP_FEE_PERCENTAGE_DECIMALS = 16;
const AAVE_FAUCET_USDT = {
address: '0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0' as `0x${string}`,
decimals: 6,
};
const STATA_ETH_DAI = {
address: '0xDE46e43F46ff74A23a65EBb0580cbe3dFE684a17' as `0x${string}`,
rateProvider: '0x22db61f3a8d81d3d427a157fdae8c7eb5b5fd373' as `0x${string}`,
decimals: 18,
};

async function runAgainstFork() {
// User defined inputs
// const { rpcUrl } = await startFork(ANVIL_NETWORKS.SEPOLIA);
const rpcUrl = process.env.SEPOLIA_RPC_URL;
const chainId = ChainId.SEPOLIA;

const userAccount = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`,
);

// Use this client to submit txs to live network
const client = createWalletClient({
chain: CHAINS[chainId],
transport: http(rpcUrl),
account: userAccount,
}).extend(publicActions);

// Use this client to run against a local fork
// const client = createTestClient({
// mode: 'anvil',
// chain: CHAINS[chainId],
// transport: http(rpcUrl),
// })
// .extend(publicActions)
// .extend(walletActions);

const createPoolInput: CreatePoolV3StableInput = {
name: 'USDT stataDAI partially boosted',
symbol: 'USDT-stataDAI',
poolType: PoolType.Stable,
tokens: [
{
address: AAVE_FAUCET_USDT.address,
rateProvider: zeroAddress,
tokenType: TokenType.STANDARD,
paysYieldFees: false,
},
{
address: STATA_ETH_DAI.address,
rateProvider: STATA_ETH_DAI.rateProvider,
tokenType: TokenType.TOKEN_WITH_RATE,
paysYieldFees: true,
},
],
amplificationParameter: BigInt(33),
swapFeePercentage: parseUnits('0.001', SWAP_FEE_PERCENTAGE_DECIMALS),
pauseManager: zeroAddress,
swapFeeManager: zeroAddress,
poolHooksContract: zeroAddress,
enableDonation: false,
disableUnbalancedLiquidity: false,
protocolVersion: 3,
chainId,
};
const initAmounts = [
{
address: AAVE_FAUCET_USDT.address,
rawAmount: parseUnits('10', AAVE_FAUCET_USDT.decimals),
decimals: AAVE_FAUCET_USDT.decimals,
},
{
address: STATA_ETH_DAI.address,
rawAmount: parseUnits('10', STATA_ETH_DAI.decimals),
decimals: STATA_ETH_DAI.decimals,
},
];

// Build the create pool call using the SDK
const call = await createPoolCall(createPoolInput);

// Submit the create pool tx and wait for the PoolCreated event to find pool address
const poolAddress = await createPool({ client, call, userAccount });
console.log('Created Pool Address: ', poolAddress);

// Approve permit2 contract to spend tokens used for init
for (const token of initAmounts) {
const tokenContract = getContract({
address: token.address,
abi: erc20Abi,
client,
});
await tokenContract.write.approve([PERMIT2[chainId], token.rawAmount]);
}

// Build the init pool call using the SDK
const initCall = await initPool({
chainId,
rpcUrl,
userAccount,
poolAddress,
initAmounts,
});

// Set up batch and sig for permit2
const { batch, signature } = await createPermit2({
client,
userAccount,
initAmounts,
chainId,
});

// Init the pool with permitBatchAndCall
const router = getContract({
address: BALANCER_ROUTER[chainId],
abi: balancerRouterAbi,
client,
});
const args = [[], [], batch, signature, [initCall.callData]] as const;
const hash = await router.write.permitBatchAndCall(args);
console.log('hash', hash);

// Make the tx against the local fork and print the result
// await makeForkTx(
// initCall,
// {
// rpcUrl,
// chainId,
// impersonateAccount: userAccount.address,
// forkTokens: initAmounts.map((a) => ({
// address: a.address,
// slot: getSlot(chainId, a.address),
// rawBalance: a.rawAmount,
// })),
// },
// [...initAmounts.map((a) => a.address), poolAddress],
// createPoolInput.protocolVersion,
// );
}

const createPoolCall = async (createPoolInput) => {
const createPool = new CreatePool();
const call = createPool.buildCall(createPoolInput);
return call;
};

const initPool = async ({
chainId,
rpcUrl,
userAccount,
poolAddress,
initAmounts,
}) => {
const initPool = new InitPool();
const poolType = PoolType.Stable;
const initPoolDataProvider = new InitPoolDataProvider(chainId, rpcUrl);

const initPoolInput: InitPoolInput = {
sender: userAccount,
recipient: userAccount,
amountsIn: initAmounts,
chainId,
minBptAmountOut: 0n,
};

const poolState = await initPoolDataProvider.getInitPoolData(
poolAddress,
poolType,
3,
);

const call = initPool.buildCall(initPoolInput, poolState);
console.log('init pool call', call);
return call;
};

async function createPool({ client, call, userAccount }) {
const hash = await client.sendTransaction({
to: call.to,
data: call.callData,
account: userAccount,
});
const transactionReceipt = await client.waitForTransactionReceipt({
hash,
});

const poolCreatedEvent = findEventInReceiptLogs({
receipt: transactionReceipt,
eventName: 'PoolCreated',
abi: stablePoolFactoryAbi_V3,
to: call.to,
});

const {
args: { pool: poolAddress },
} = poolCreatedEvent;
return poolAddress;
}

async function createPermit2({
client,
userAccount,
initAmounts,
chainId,
}: {
client: PublicWalletClient;
userAccount: PrivateKeyAccount;
initAmounts: {
address: `0x${string}`;
rawAmount: bigint;
decimals: number;
}[];
chainId: ChainId;
}) {
const owner = userAccount.address;
const permit2Contract = getContract({
address: PERMIT2[chainId],
abi: permit2Abi,
client,
});

const details: PermitDetails[] = await Promise.all(
initAmounts.map(async (token) => {
const [, , nonce] = await permit2Contract.read.allowance([
owner,
token.address,
BALANCER_ROUTER[chainId],
]);

return {
token: token.address,
amount: token.rawAmount,
expiration: Number(MaxAllowanceExpiration),
nonce,
};
}),
);

const batch: Permit2Batch = {
details,
spender: BALANCER_ROUTER[chainId],
sigDeadline: MaxSigDeadline,
};

const { domain, types, values } = AllowanceTransfer.getPermitData(
batch,
PERMIT2[chainId],
chainId,
);

const signature = await client.signTypedData({
account: userAccount,
message: {
...values,
},
domain,
primaryType: 'PermitBatch',
types,
});

return { batch, signature };
}

export default runAgainstFork;
3 changes: 2 additions & 1 deletion examples/swaps/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
Swap,
SwapBuildOutputExactIn,
SwapBuildOutputExactOut,
SwapInput,
} from '../../src';

const swap = async () => {
Expand Down Expand Up @@ -58,7 +59,7 @@ const swap = async () => {
swapAmount,
});

const swapInput = {
const swapInput: SwapInput = {
chainId,
paths: sorPaths,
swapKind,
Expand Down
23 changes: 23 additions & 0 deletions src/abi/balancerBatchRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export const balancerBatchRouterAbi = [
name: 'permit2',
type: 'address',
},
{
internalType: 'string',
name: 'version',
type: 'string',
},
],
stateMutability: 'nonpayable',
type: 'constructor',
Expand Down Expand Up @@ -57,6 +62,11 @@ export const balancerBatchRouterAbi = [
name: 'FailedInnerCall',
type: 'error',
},
{
inputs: [],
name: 'InputLengthMismatch',
type: 'error',
},
{
inputs: [],
name: 'InsufficientEth',
Expand Down Expand Up @@ -968,6 +978,19 @@ export const balancerBatchRouterAbi = [
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [],
name: 'version',
outputs: [
{
internalType: 'string',
name: '',
type: 'string',
},
],
stateMutability: 'view',
type: 'function',
},
{
stateMutability: 'payable',
type: 'receive',
Expand Down
Loading
Loading