@lumina-dex/contracts
Version:
Contracts for Lumina DEX.
204 lines (176 loc) • 5.31 kB
text/typescript
import {
AccountUpdate,
AccountUpdateForest,
Bool,
DeployArgs,
method,
Mina,
Permissions,
PublicKey,
State,
state,
Struct,
TokenContract,
UInt64,
VerificationKey
} from "o1js"
import { UpdateVerificationKeyEvent } from "../indexfactory.js"
import { Pool } from "../indexpool.js"
export class FarmingInfo extends Struct({
startTimestamp: UInt64,
endTimestamp: UInt64
}) {
constructor(value: {
startTimestamp: UInt64
endTimestamp: UInt64
}) {
super(value)
}
}
export class FarmingEvent extends Struct({
sender: PublicKey,
amount: UInt64
}) {
constructor(value: {
sender: PublicKey
amount: UInt64
}) {
super(value)
}
}
export class BurnEvent extends Struct({
sender: PublicKey,
amount: UInt64
}) {
constructor(value: {
sender: PublicKey
amount: UInt64
}) {
super(value)
}
}
export class UpdateInitEvent extends Struct({
owner: PublicKey
}) {
constructor(value: {
owner: PublicKey
}) {
super(value)
}
}
export interface FarmingDeployProps extends Exclude<DeployArgs, undefined> {
pool: PublicKey
owner: PublicKey
startSlot: UInt64
endSlot: UInt64
}
/**
* we can't upgrade the contract before 1 day
*/
export const minTimeUnlockFarm = UInt64.from(86_400_000)
/**
* Farm contract
*/
export class Farm extends TokenContract {
// Farming for one pool
pool = State<PublicKey>()
owner = State<PublicKey>()
startTimestamp = State<UInt64>()
endTimestamp = State<UInt64>()
timeUnlock = State<UInt64>()
events = {
upgrade: UpdateVerificationKeyEvent,
upgradeInited: UpdateInitEvent,
deposit: FarmingEvent,
burn: BurnEvent
}
async deploy(args: FarmingDeployProps) {
this.account.isNew.requireEquals(Bool(true))
await super.deploy(args)
args.pool.isEmpty().assertFalse("Pool empty")
args.owner.isEmpty().assertFalse("Owner empty")
// calculate start and end base on slot
const { genesisTimestamp, slotTime } = Mina.getNetworkConstants()
const startTimestamp = UInt64.from(args.startSlot).mul(slotTime).add(genesisTimestamp)
const endTimestamp = UInt64.from(args.endSlot).mul(slotTime).add(genesisTimestamp)
startTimestamp.lessThan(endTimestamp)
// check starttimestamp greater than current timestamp
this.network.timestamp.requireBetween(UInt64.zero, startTimestamp)
this.pool.set(args.pool)
this.owner.set(args.owner)
this.startTimestamp.set(startTimestamp)
this.endTimestamp.set(endTimestamp)
const permissions = Permissions.default()
permissions.access = Permissions.proof()
permissions.send = Permissions.proof()
permissions.setPermissions = Permissions.impossible()
permissions.setVerificationKey = Permissions.VerificationKey.proofDuringCurrentVersion()
this.account.permissions.set(permissions)
}
/**
* Transfer is locked only depositor can withdraw his token
*/
async approveBase(updates: AccountUpdateForest): Promise<void> {
updates.isEmpty().assertTrue("You can't manage the token")
}
/**
* Init Upgrade to a new version
* @param vk new verification key
*/
async initUpdate(startTime: UInt64) {
const owner = await this.owner.getAndRequireEquals()
// only owner can init a update
AccountUpdate.createSigned(owner)
this.network.timestamp.requireBetween(UInt64.zero, startTime)
// owner need to wait minimum 1 day before update this contract
const timeUnlock = startTime.add(minTimeUnlockFarm)
this.timeUnlock.set(timeUnlock)
this.emitEvent("upgradeInited", new UpdateInitEvent({ owner }))
}
/**
* Upgrade to a new version
* @param vk new verification key
*/
async updateVerificationKey(vk: VerificationKey) {
const timeUnlock = this.timeUnlock.getAndRequireEquals()
timeUnlock.assertGreaterThan(UInt64.zero, "Time unlock is not defined")
this.network.timestamp.requireBetween(timeUnlock, UInt64.MAXINT())
const owner = await this.owner.getAndRequireEquals()
// only owner can update a pool
AccountUpdate.createSigned(owner)
this.account.verificationKey.set(vk)
this.emitEvent("upgrade", new UpdateVerificationKeyEvent(vk.hash))
}
async deposit(amount: UInt64) {
const startTimestamp = this.startTimestamp.getAndRequireEquals()
const endTimestamp = this.endTimestamp.getAndRequireEquals()
// user can deposit only during this period
this.network.timestamp.requireBetween(startTimestamp, endTimestamp)
const poolAddress = this.pool.getAndRequireEquals()
const pool = new Pool(poolAddress)
const sender = this.sender.getUnconstrained()
// transfer amount to this account
await pool.transfer(sender, this.address, amount)
this.internal.mint({ address: sender, amount })
this.emitEvent("deposit", new FarmingEvent({ sender, amount }))
}
/**
* Don't call this method directly
*/
async burnLiquidity(sender: PublicKey, amount: UInt64) {
const caller = this.sender.getAndRequireSignature()
caller.assertEquals(sender)
this.internal.burn({ address: sender, amount })
this.emitEvent("burn", new BurnEvent({ sender, amount }))
}
}