Skip to content

Commit

Permalink
Merge pull request #98 from invariant-labs/init-invariant-class
Browse files Browse the repository at this point in the history
Init invariant class
  • Loading branch information
Sniezka1927 authored Jul 12, 2024
2 parents 84cbd1b + 712723b commit bae81f5
Show file tree
Hide file tree
Showing 3 changed files with 368 additions and 0 deletions.
331 changes: 331 additions & 0 deletions src/invariant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
import {
AddFeeTier,
ChangeFeeReceiver,
ChangeProtocolFee,
ClaimFee,
CLAMM,
CreatePool,
CreatePosition,
Invariant as InvariantFactory,
InvariantInstance,
RemoveFeeTier,
RemovePosition,
Reserve,
Swap,
TransferPosition,
WithdrawProtocolFee
} from '../artifacts/ts'
import { FeeTier, Pool, PoolKey, Position, QuoteResult, Tick } from '../artifacts/ts/types'
import { calculateTick } from './math'
import { Network } from './network'
import { getReserveAddress } from './testUtils'
import {
balanceOf,
decodeFeeTiers,
decodePool,
decodePosition,
decodeTick,
deployCLAMM,
deployReserve,
MAP_ENTRY_DEPOSIT,
waitTxConfirmed
} from './utils'
import { Address, DUST_AMOUNT, SignerProvider, ZERO_ADDRESS } from '@alephium/web3'

export class Invariant {
instance: InvariantInstance
network: Network
address: Address

private constructor(address: Address, network: Network) {
this.address = address
this.instance = InvariantFactory.at(address)
this.network = network
}

static async deploy(
signer: SignerProvider,
network: Network,
protocolFee: bigint = 0n
): Promise<Invariant> {
const account = await signer.getSelectedAccount()
const clamm = await deployCLAMM(signer)
const reserve = await deployReserve(signer)

const deployResult = await waitTxConfirmed(
InvariantFactory.deploy(signer, {
initialFields: {
config: { admin: account.address, protocolFee },
reserveTemplateId: reserve.contractId,
lastReserveId: reserve.contractId,
clamm: clamm.contractId,
feeTierCount: 0n,
poolKeyCount: 0n
}
})
)

return new Invariant(deployResult.contractInstance.address, network)
}

static async load(address: Address, network: Network): Promise<Invariant> {
return new Invariant(address, network)
}

async addFeeTier(signer: SignerProvider, feeTier: FeeTier): Promise<string> {
const { txId } = await waitTxConfirmed(
AddFeeTier.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
feeTier
},
attoAlphAmount: MAP_ENTRY_DEPOSIT
})
)
return txId
}

async removeFeeTier(signer: SignerProvider, feeTier: FeeTier): Promise<string> {
const { txId } = await waitTxConfirmed(
RemoveFeeTier.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
feeTier
}
})
)
return txId
}

async createPool(
signer: SignerProvider,
token0Id: string,
token1Id: string,
feeTier: FeeTier,
initSqrtPrice: bigint
): Promise<string> {
const initTick = await calculateTick(initSqrtPrice, feeTier.tickSpacing)

const { txId } = await waitTxConfirmed(
CreatePool.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
token0: token0Id,
token1: token1Id,
feeTier,
initSqrtPrice,
initTick
},
attoAlphAmount: MAP_ENTRY_DEPOSIT * 5n
})
)
return txId
}

async withdrawProtocolFee(signer: SignerProvider, poolKey: PoolKey): Promise<string> {
const { txId } = await waitTxConfirmed(
WithdrawProtocolFee.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
poolKey
}
})
)
return txId
}
async changeFeeReceiver(
signer: SignerProvider,
poolKey: PoolKey,
newFeeReceiver: Address
): Promise<string> {
const { txId } = await waitTxConfirmed(
ChangeFeeReceiver.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
poolKey,
newFeeReceiver
}
})
)
return txId
}
async changeProtocolFee(signer: SignerProvider, fee: bigint): Promise<string> {
const { txId } = await waitTxConfirmed(
ChangeProtocolFee.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
newFee: fee
}
})
)
return txId
}

async createPosition(
signer: SignerProvider,
poolKey: PoolKey,
lowerTick: bigint,
upperTick: bigint,
liquidityDelta: bigint,
approvedTokensX: bigint,
approvedTokensY: bigint,
slippageLimitLower: bigint,
slippageLimitUpper: bigint
): Promise<string> {
const { txId } = await waitTxConfirmed(
CreatePosition.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
poolKey,
lowerTick,
upperTick,
liquidityDelta,
approvedTokensX,
approvedTokensY,
slippageLimitLower,
slippageLimitUpper
},
tokens: [
{ id: poolKey.tokenX, amount: approvedTokensX },
{ id: poolKey.tokenY, amount: approvedTokensY }
],
attoAlphAmount: MAP_ENTRY_DEPOSIT * 6n + DUST_AMOUNT * 2n
})
)

return txId
}
async removePosition(signer: SignerProvider, index: bigint): Promise<string> {
const { txId } = await waitTxConfirmed(
RemovePosition.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
index
}
})
)
return txId
}
async claimFee(signer: SignerProvider, index: bigint): Promise<string> {
const { txId } = await waitTxConfirmed(
ClaimFee.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
index
},
attoAlphAmount: DUST_AMOUNT
})
)
return txId
}
async transferPosition(
signer: SignerProvider,
index: bigint,
recipient: Address
): Promise<string> {
const { txId } = await waitTxConfirmed(
TransferPosition.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
index,
recipient
},
attoAlphAmount: 2n * MAP_ENTRY_DEPOSIT
})
)
return txId
}
async swap(
signer: SignerProvider,
poolKey: PoolKey,
xToY: boolean,
amount: bigint,
byAmountIn: boolean,
sqrtPriceLimit: bigint,
approvedAmount = amount
): Promise<string> {
const tokenId = xToY ? poolKey.tokenX : poolKey.tokenY
const { txId } = await waitTxConfirmed(
Swap.execute(signer, {
initialFields: {
invariant: this.instance.contractId,
poolKey,
xToY,
amount,
byAmountIn,
sqrtPriceLimit,
approvedAmount
},
tokens: [{ id: tokenId, amount: approvedAmount }],
attoAlphAmount: DUST_AMOUNT * 2n
})
)
return txId
}

async feeTierExist(feeTier: FeeTier): Promise<boolean> {
return (await this.instance.view.feeTierExist({ args: { feeTier } })).returns
}

async getFeeTiers(): Promise<FeeTier[]> {
return decodeFeeTiers((await this.instance.view.getAllFeeTiers()).returns)
}

async getPool(poolKey: PoolKey): Promise<Pool> {
return decodePool((await this.instance.view.getPool({ args: { poolKey } })).returns)
}

async getPosition(owner: Address, index: bigint): Promise<Position> {
return decodePosition(
(await this.instance.view.getPosition({ args: { owner, index } })).returns
)
}

async quote(
poolKey: PoolKey,
xToY: boolean,
amount: bigint,
byAmountIn: boolean,
sqrtPriceLimit: bigint
): Promise<QuoteResult> {
return (
await this.instance.view.quote({
args: { poolKey, xToY, amount, byAmountIn, sqrtPriceLimit }
})
).returns
}

async getTick(poolKey: PoolKey, index: bigint): Promise<Tick> {
return decodeTick((await this.instance.view.getTick({ args: { poolKey, index } })).returns)
}

async isTickInitialized(poolKey: PoolKey, index: bigint): Promise<boolean> {
return (await this.instance.view.isTickInitialized({ args: { poolKey, index } })).returns
}

async getReserveBalances(poolKey: PoolKey): Promise<{ x: bigint; y: bigint }> {
const pool = await this.getPool(poolKey)
const [reserveX, reserveY] = getReserveAddress(pool)
const x = await balanceOf(poolKey.tokenX, reserveX)
const y = await balanceOf(poolKey.tokenY, reserveY)
return { x, y }
}

async getProtocolFee(): Promise<bigint> {
return (await this.instance.view.getProtocolFee()).returns
}

// async getPositions() {}
// async getAllPositions() {}
// async getPoolKeys() {}
// async getAllPoolKeys() {}
// async swapWithSlippage() {}
// async getPositionTicks() {}
// async getRawTickmap() {}
// async getFullTickmap() {}
// async getLiquidityTicks() {}
// async getAllLiquidityTicks() {}
// async getUserPositionAmount() {}
// async getLiquidityTicksAmount() {}
// async getAllPoolsForPair() {}
}
6 changes: 6 additions & 0 deletions src/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum Network {
Local = 'Local',
Devnet = 'Devnet',
Testnet = 'Testnet',
Mainnet = 'Mainnet'
}
31 changes: 31 additions & 0 deletions test/invariant.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ONE_ALPH, web3 } from '@alephium/web3'
import { getSigner } from '@alephium/web3-test'
import { PrivateKeyWallet } from '@alephium/web3-wallet'
import { InvariantError, PercentageScale } from '../src/consts'
import { expectError, feeTierExists, getFeeTiers, initFeeTier } from '../src/testUtils'
import { deployInvariant, newFeeTier } from '../src/utils'
import { FeeTier } from '../artifacts/ts/types'
import { Invariant } from '../src/invariant'
import { Network } from '../src/network'
import { AddFeeTier } from '../artifacts/ts'

web3.setCurrentNodeProvider('http://127.0.0.1:22973')

describe('init invariant test', () => {
test('deploy invariant works', async () => {
const initialFee = 0n
const deployer = await getSigner(ONE_ALPH * 1000n, 0)
const invariant = await Invariant.deploy(deployer, Network.Local, initialFee)
const protocolFee = await invariant.getProtocolFee()
expect(protocolFee).toBe(0n)
})
test('load invariant from address', async () => {
const initialFee = 0n
const deployer = await getSigner(ONE_ALPH * 1000n, 0)
const invariant = await Invariant.deploy(deployer, Network.Local, initialFee)

const loadedInvariant = await Invariant.load(invariant.address, Network.Local)
const protocolFee = await loadedInvariant.getProtocolFee()
expect(protocolFee).toBe(0n)
})
})

0 comments on commit bae81f5

Please sign in to comment.