UNPKG

@lumina-dex/contracts

Version:
204 lines (176 loc) 5.31 kB
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 @state(PublicKey) pool = State<PublicKey>() @state(PublicKey) owner = State<PublicKey>() @state(UInt64) startTimestamp = State<UInt64>() @state(UInt64) endTimestamp = State<UInt64>() @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 */ @method 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 */ @method 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 */ @method 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)) } @method 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 */ @method 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 })) } }