Skip to content

Commit

Permalink
Merge pull request #45 from invariant-labs/mint-saga
Browse files Browse the repository at this point in the history
publish sdk and add mint saga
  • Loading branch information
zielvna authored Aug 22, 2024
2 parents 3e3a279 + b6dfe54 commit 9731b92
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 25 deletions.
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"dependencies": {
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@invariant-labs/eclipse-link-sdk": "^0.1.3",
"@invariant-labs/eclipse-link-sdk": "^0.1.4",
"@invariant-labs/sdk-eclipse": "^0.0.17",
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
Expand Down
14 changes: 9 additions & 5 deletions frontend/src/components/Liquidity/Liquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface ILiquidity {
tokens: SwapToken[]
midPrice: any
setMidPrice: (mid: any) => void
addLiquidityHandler: (xAmount: number, yAmount: number) => void
addLiquidityHandler: (tokenXDeposit: BN, tokenYDeposit: BN) => void
removeLiquidityHandler: (xAmount: number, yAmount: FormatNumberThreshold) => void
onChangePositionTokens: (
tokenAIndex: number | null,
Expand Down Expand Up @@ -80,7 +80,7 @@ export const Liquidity: React.FC<ILiquidity> = ({
initialTab,
tokens,
// setMidPrice,
// addLiquidityHandler,
addLiquidityHandler,
// removeLiquidityHandler,
onChangePositionTokens,
calcAmount,
Expand Down Expand Up @@ -260,10 +260,9 @@ export const Liquidity: React.FC<ILiquidity> = ({
tokenBIndex !== null &&
tokenADeposit !== null &&
tokenBDeposit !== null &&
!sqrtPrice.v.eq(new BN(0)) &&
tokenAIndex !== tokenBIndex
) {
console.log('sqrt price', sqrtPrice.v.toString(), tickSpacing, getMaxTick(tickSpacing))

const maxLiquidity = getMaxLiquidity(
{ v: printBNtoBN(tokenADeposit, xDecimal) },
{ v: printBNtoBN(tokenBDeposit, yDecimal) },
Expand Down Expand Up @@ -416,7 +415,12 @@ export const Liquidity: React.FC<ILiquidity> = ({
<AddLiquidity
tokens={tokens}
onAddLiquidity={() => {
//TODO
if (tokenAIndex !== null && tokenBIndex !== null) {
addLiquidityHandler(
printBNtoBN(tokenADeposit, tokens[tokenAIndex].decimals),
printBNtoBN(tokenBDeposit, tokens[tokenBIndex].decimals)
)
}
}}
tokenAInputState={{
value: tokenADeposit,
Expand Down
19 changes: 17 additions & 2 deletions frontend/src/containers/LiquidityWrapper/LiquidityWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Liquidity } from '@components/Liquidity/Liquidity'
import { BN } from '@project-serum/anchor'
import { PublicKey } from '@solana/web3.js'
import { ALL_FEE_TIERS_DATA, bestTiers, commonTokensForNetworks } from '@store/consts/static'
import { actions as poolsActions } from '@store/reducers/pools'
import { actions, actions as poolsActions } from '@store/reducers/pools'
import { actions as snackbarsActions } from '@store/reducers/snackbars'
import { Status, actions as walletActions } from '@store/reducers/wallet'
import { network } from '@store/selectors/connection'
Expand Down Expand Up @@ -236,7 +236,22 @@ export const LiquidityWrapper: React.FC<IProps> = ({
tokens={tokens}
midPrice={10}
setMidPrice={() => {}}
addLiquidityHandler={() => {}}
addLiquidityHandler={(tokenXDeposit: BN, tokenYDeposit: BN) => {
if (tokenAIndex !== null && tokenBIndex !== null) {
dispatch(
actions.mint({
pair: new Pair(
tokens[tokenAIndex].address,
tokens[tokenBIndex].address,
FEE_TIERS[feeIndex]
),
tokenXDeposit,
tokenYDeposit,
lpPoolExists: lpPoolIndex !== null
})
)
}
}}
removeLiquidityHandler={() => {}}
onChangePositionTokens={(tokenA, tokenB, feeTierIndex) => {
setTokenAIndex(tokenA)
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/store/reducers/pools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LpPoolStructure } from '@invariant-labs/eclipse-link-sdk/dist/types'
import { Pair } from '@invariant-labs/sdk-eclipse'
import { PoolStructure } from '@invariant-labs/sdk-eclipse/lib/market'
import { BN } from '@project-serum/anchor'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { PublicKey } from '@solana/web3.js'
import { Token } from '@store/consts/static'
Expand Down Expand Up @@ -90,6 +91,13 @@ export interface ListPoolsResponse {
listType: ListType
}

export interface MintData {
pair: Pair
tokenXDeposit: BN
tokenYDeposit: BN
lpPoolExists: boolean
}

export const poolsSliceName = 'pools'
const poolsSlice = createSlice({
name: poolsSliceName,
Expand Down Expand Up @@ -140,6 +148,9 @@ const poolsSlice = createSlice({
state.lpPools = R.merge(state.lpPools, newData)
state.isLoadingLatestPoolsForTransaction = false
return state
},
mint(state, _action: PayloadAction<MintData>) {
return state
}
}
})
Expand Down
129 changes: 126 additions & 3 deletions frontend/src/store/sagas/pools.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { actions, PairTokens, PoolWithAddress } from '@store/reducers/pools'
import { actions, MintData, PairTokens, PoolWithAddress } from '@store/reducers/pools'
import { network, rpcAddress } from '@store/selectors/connection'
import { all, call, put, select, spawn, takeLatest } from 'typed-redux-saga'
import { PayloadAction } from '@reduxjs/toolkit'
import { getMarketProgram } from '@web3/programs/amm'
import { getPools } from '@store/consts/utils'
import { Pair } from '@invariant-labs/sdk-eclipse'
import { FEE_TIERS } from '@invariant-labs/sdk-eclipse/lib/utils'
import { FEE_TIERS, getMaxTick, getMinTick } from '@invariant-labs/sdk-eclipse/lib/utils'
import { getProtocolProgram } from '@web3/programs/protocol'
import { getWallet } from './wallet'
import { AnchorProvider, BN } from '@project-serum/anchor'
import { getAssociatedTokenAddress } from '@solana/spl-token'
import { getConnection } from './connection'
import { BlockheightBasedTransactionConfirmationStrategy, Transaction } from '@solana/web3.js'

export interface iTick {
index: iTick[]
Expand Down Expand Up @@ -70,6 +75,116 @@ export function* fetchLpPoolData(action: PayloadAction<Pair>) {
}
}

export function* handleMint(action: PayloadAction<MintData>) {
const { pair, lpPoolExists } = action.payload

const networkType = yield* select(network)
const rpc = yield* select(rpcAddress)
const wallet = yield* call(getWallet)
const connection = yield* call(getConnection)

const protocolProgram = yield* call(getProtocolProgram, networkType, rpc)
const marketProgram = yield* call(getMarketProgram, networkType, rpc)

const tx = new Transaction()

if (lpPoolExists) {
const initLpPoolIx = yield* call([protocolProgram, protocolProgram.initLpPoolIx], {
pair
})
tx.add(initLpPoolIx)

const lowerTickIndex = getMinTick(pair.feeTier.tickSpacing ?? 0)
try {
yield* call([marketProgram, marketProgram.getTick], pair, lowerTickIndex)
} catch (e) {
const createLowerTickIx = yield* call([marketProgram, marketProgram.createTickInstruction], {
pair,
index: getMinTick(pair.feeTier.tickSpacing ?? 0)
})
tx.add(createLowerTickIx)
}

const upperTickIndex = getMaxTick(pair.feeTier.tickSpacing ?? 0)
try {
yield* call([marketProgram, marketProgram.getTick], pair, upperTickIndex)
} catch (e) {
const createLowerTickIx = yield* call([marketProgram, marketProgram.createTickInstruction], {
pair,
index: getMinTick(pair.feeTier.tickSpacing ?? 0)
})
tx.add(createLowerTickIx)
}
}

const { address: stateAddress } = yield* call([marketProgram, marketProgram.getStateAddress])
const { positionListAddress } = yield* call(
[marketProgram, marketProgram.getPositionListAddress],
protocolProgram.programAuthority
)
const { positionAddress } = yield* call(
[marketProgram, marketProgram.getPositionAddress],
protocolProgram.programAuthority,
0
)
const { positionAddress: lastPositionAddress } = yield* call(
[marketProgram, marketProgram.getPositionAddress],
protocolProgram.programAuthority,
0
)
const { tickAddress: lowerTickAddress } = yield* call(
[marketProgram, marketProgram.getTickAddress],
pair,
getMinTick(pair.feeTier.tickSpacing ?? 0)
)
const { tickAddress: upperTickAddress } = yield* call(
[marketProgram, marketProgram.getTickAddress],
pair,
getMaxTick(pair.feeTier.tickSpacing ?? 0)
)
const pool = yield* call([marketProgram, marketProgram.getPool], pair)
const accountXAddress = yield* call(getAssociatedTokenAddress, pool.tokenX, wallet.publicKey)
const accountYAddress = yield* call(getAssociatedTokenAddress, pool.tokenY, wallet.publicKey)
const { programAuthority } = yield* call([marketProgram, marketProgram.getProgramAuthority])

const mintIx = yield* call([protocolProgram, protocolProgram.mintLpTokenIx], {
pair,
index: 0,
liquidityDelta: new BN(10000),
invProgram: marketProgram.program.programId,
invState: stateAddress,
position: positionAddress,
lastPosition: lastPositionAddress,
positionList: positionListAddress,
lowerTick: lowerTickAddress,
upperTick: upperTickAddress,
tickmap: pool.tickmap,
accountX: accountXAddress,
accountY: accountYAddress,
invReserveX: pool.tokenXReserve,
invReserveY: pool.tokenYReserve,
invProgramAuthority: programAuthority
})
tx.add(mintIx)

const blockhash = yield* call([connection, connection.getLatestBlockhash])
tx.recentBlockhash = blockhash.blockhash
tx.feePayer = wallet.publicKey
const signedTx = yield* call([wallet, wallet.signTransaction], tx)
const signature = yield* call(
[connection, connection.sendRawTransaction],
signedTx.serialize(),
AnchorProvider.defaultOptions()
)

const confirmStrategy: BlockheightBasedTransactionConfirmationStrategy = {
blockhash: blockhash.blockhash,
lastValidBlockHeight: blockhash.lastValidBlockHeight,
signature
}
yield* call([connection, connection.confirmTransaction], confirmStrategy)
}

export function* getPoolDataHandler(): Generator {
yield* takeLatest(actions.getPoolData, fetchPoolData)
}
Expand All @@ -82,6 +197,14 @@ export function* getLpPoolDataHandler(): Generator {
yield* takeLatest(actions.getLpPoolData, fetchLpPoolData)
}

export function* mintHandler(): Generator {
yield* takeLatest(actions.mint, handleMint)
}

export function* poolsSaga(): Generator {
yield all([getPoolDataHandler, getAllPoolsForPairDataHandler, getLpPoolDataHandler].map(spawn))
yield all(
[getPoolDataHandler, getAllPoolsForPairDataHandler, getLpPoolDataHandler, mintHandler].map(
spawn
)
)
}
2 changes: 1 addition & 1 deletion frontend/src/store/sagas/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export function* getCollateralTokenAirdrop(
tx.feePayer = wallet.publicKey
tx.recentBlockhash = blockhash

const signedTx = yield* call([wallet, wallet.signTransaction], tx)
const signedTx = (yield* call([wallet, wallet.signTransaction], tx)) as Transaction
signedTx.partialSign(airdropAdmin)

yield* call([connection, connection.sendRawTransaction], signedTx.serialize(), {
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/utils/web3/adapters/standard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PublicKey, Transaction } from '@solana/web3.js'
import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'
import { WalletAdapter } from './types'
import { nightlyConnectAdapter } from '@utils/web3/selector'

Expand All @@ -11,15 +11,17 @@ export class StandardAdapter implements WalletAdapter {
return nightlyConnectAdapter.connected
}

async signAllTransactions(transactions: Transaction[]): Promise<Transaction[]> {
async signAllTransactions<T extends Transaction | VersionedTransaction>(
transactions: T[]
): Promise<T[]> {
return await nightlyConnectAdapter.signAllTransactions(transactions)
}

get publicKey() {
return nightlyConnectAdapter.publicKey ?? new PublicKey('')
}

async signTransaction(transaction: Transaction) {
async signTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T> {
return await nightlyConnectAdapter.signTransaction(transaction)
}

Expand Down
6 changes: 3 additions & 3 deletions frontend/src/utils/web3/adapters/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PublicKey, Transaction } from '@solana/web3.js'
import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'

export interface WalletAdapter {
publicKey: PublicKey
connected: boolean
signTransaction: (transaction: Transaction) => Promise<Transaction>
signAllTransactions: (transaction: Transaction[]) => Promise<Transaction[]>
signTransaction<T extends Transaction | VersionedTransaction>(tx: T): Promise<T>
signAllTransactions<T extends Transaction | VersionedTransaction>(txs: T[]): Promise<T[]>
connect: () => any
disconnect: () => any
}
4 changes: 2 additions & 2 deletions protocol/sdk/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion protocol/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@invariant-labs/eclipse-link-sdk",
"version": "0.1.3",
"version": "0.1.4",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
Expand Down

0 comments on commit 9731b92

Please sign in to comment.