UNPKG

@lumina-dex/contracts

Version:
582 lines (515 loc) 25.7 kB
import { FungibleToken, FungibleTokenAdmin } from "mina-fungible-token" import { AccountUpdate, Bool, Cache, Field, MerkleMap, Mina, Poseidon, PrivateKey, Provable, PublicKey, Signature, UInt8, UInt32, UInt64, VerificationKey } from "o1js" import { beforeAll, beforeEach, describe, expect, it } from "vitest" import { allRight, Multisig, MultisigInfo, MultisigSigner, Pool, PoolFactory, PoolTokenHolder, SignatureInfo, UpdateAccountInfo, updateDelegatorRight, UpdateFactoryInfo, updateFactoryRight, updateProtocolRight, UpdateSignerData, updateSignerRight } from "../dist" import { PoolFactoryUpgradeTest } from "./PoolFactoryUpgradeTest" import { PoolHolderUpgradeTest } from "./PoolHolderUpgradeTest" import { PoolUpgradeTest } from "./PoolUpgradeTest" const proofsEnabled = false const vkUpgradeTest = new VerificationKey({ data: "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", hash: Field.from(1094855669395027188090902596744887124365128625005606285591537108109825582697n) }) const vkFactoryUpgradeTest = new VerificationKey({ data: "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", hash: Field.from(120416605976836130576107291530544425238266426929407352611281136753339053096n) }) describe("Pool data", () => { let deployerAccount: Mina.TestPublicKey, deployerKey: PrivateKey, senderAccount: Mina.TestPublicKey, senderKey: PrivateKey, senderPublic: PublicKey, bobAccount: Mina.TestPublicKey, bobPublic: PublicKey, bobKey: PrivateKey, deployer2: Mina.TestPublicKey, deployer3: Mina.TestPublicKey, aliceAccount: Mina.TestPublicKey, alicePublic: PublicKey, dylanAccount: Mina.TestPublicKey, dylanPublic: PublicKey, deployerPublic: PublicKey, deployer2Public: PublicKey, deployer3Public: PublicKey, aliceKey: PrivateKey, merkle: MerkleMap, compileKey: VerificationKey, zkAppAddress: PublicKey, zkAppPrivateKey: PrivateKey, zkApp: PoolFactory, zkPoolAddress: PublicKey, zkPoolPrivateKey: PrivateKey, zkPool: Pool, zkTokenAdminAddress: PublicKey, zkTokenAdminPrivateKey: PrivateKey, zkTokenAdmin: FungibleTokenAdmin, zkTokenAddress: PublicKey, zkTokenPrivateKey: PrivateKey, zkToken: FungibleToken, tokenHolder: PoolTokenHolder beforeAll(async () => { compileKey = vkUpgradeTest const cache = Cache.FileSystem("./cache") // const compileResult = await PoolUpgradeTest.compile({ cache, }); // console.log("poolUpgradeTest", compileResult.verificationKey.data); // console.log("poolUpgradeTest hash", compileResult.verificationKey.hash.toBigInt()); if (proofsEnabled) { console.time("compile PoolData") await FungibleTokenAdmin.compile({ cache }) await FungibleToken.compile({ cache }) await PoolFactory.compile({ cache }) await Pool.compile({ cache }) await PoolTokenHolder.compile({ cache }) await PoolFactoryUpgradeTest.compile({ cache }) await PoolUpgradeTest.compile({ cache }) await PoolHolderUpgradeTest.compile({ cache }) console.timeEnd("compile PoolData") } }) async function mintToken(user: PublicKey) { // token are minted to original deployer, so just transfer it for test let txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkToken.mint(user, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey]).send() txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkToken.mint(deployerAccount, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey]).send() } beforeEach(async () => { const Local = await Mina.LocalBlockchain({ proofsEnabled }) Mina.setActiveInstance(Local) ;[deployerAccount, senderAccount, bobAccount, aliceAccount, dylanAccount, deployer2, deployer3] = Local.testAccounts deployerKey = deployerAccount.key senderKey = senderAccount.key senderPublic = senderKey.toPublicKey() dylanPublic = dylanAccount.key.toPublicKey() bobKey = bobAccount.key bobPublic = bobKey.toPublicKey() aliceKey = aliceAccount.key alicePublic = aliceKey.toPublicKey() deployerPublic = deployerKey.toPublicKey() deployer2Public = deployer2.key.toPublicKey() deployer3Public = deployer3.key.toPublicKey() merkle = new MerkleMap() merkle.set(Poseidon.hash(deployerPublic.toFields()), Poseidon.hash(allRight.toFields())) merkle.set(Poseidon.hash(deployer2Public.toFields()), Poseidon.hash(updateSignerRight.toFields())) merkle.set(Poseidon.hash(deployer3Public.toFields()), Poseidon.hash(updateSignerRight.toFields())) zkAppPrivateKey = PrivateKey.random() zkAppAddress = zkAppPrivateKey.toPublicKey() zkApp = new PoolFactory(zkAppAddress) zkPoolPrivateKey = PrivateKey.random() zkPoolAddress = zkPoolPrivateKey.toPublicKey() zkPool = new Pool(zkPoolAddress) zkTokenAdminPrivateKey = PrivateKey.random() zkTokenAdminAddress = zkTokenAdminPrivateKey.toPublicKey() zkTokenAdmin = new FungibleTokenAdmin(zkTokenAdminAddress) zkTokenPrivateKey = PrivateKey.random() zkTokenAddress = zkTokenPrivateKey.toPublicKey() zkToken = new FungibleToken(zkTokenAddress) const txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 3) await zkTokenAdmin.deploy({ adminPublicKey: deployerAccount }) await zkToken.deploy({ symbol: "LTA", src: "https://github.com/MinaFoundation/mina-fungible-token/blob/main/FungibleToken.ts", allowUpdates: false }) await zkToken.initialize( zkTokenAdminAddress, UInt8.from(9), Bool(false) ) }) await txn.prove() // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization await txn.sign([deployerKey, zkAppPrivateKey, zkTokenAdminPrivateKey, zkTokenPrivateKey]).send() }) async function deployPool() { const root = merkle.getRoot() const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateSignerData({ oldRoot: Field.empty(), newRoot: root, deadlineSlot: UInt32.from(time) }) const sign1 = Signature.create(deployerKey, info.toFields()) const sign2 = Signature.create(deployer2.key, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: root, messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const info1 = new SignatureInfo({ user: deployerPublic, witness: merkle.getWitness(Poseidon.hash(deployerPublic.toFields())), signature: sign1, right: allRight }) const info2 = new SignatureInfo({ user: deployer2Public, witness: merkle.getWitness(Poseidon.hash(deployer2Public.toFields())), signature: sign2, right: updateSignerRight }) const signatures = [info1, info2] const txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkApp.deploy({ symbol: "FAC", src: "https://luminadex.com/", protocol: aliceAccount, delegator: dylanAccount, approvedSigner: root, multisig: new Multisig({ info: multi, signatures }) }) }) await txn.prove() // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization await txn.sign([deployerKey, zkAppPrivateKey, zkTokenAdminPrivateKey, zkTokenPrivateKey]).send() const signature = Signature.create(deployerKey, zkPoolAddress.toFields()) const witness = merkle.getWitness(Poseidon.hash(deployerPublic.toFields())) const txn3 = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 4) await zkApp.createPool(zkPoolAddress, zkTokenAddress, deployerAccount, signature, witness, allRight) }) // console.log("Pool creation au", txn3.transaction.accountUpdates.length); await txn3.prove() // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization await txn3.sign([deployerKey, zkPoolPrivateKey]).send() } it("update pool proof", async () => { const right = Poseidon.hash(updateFactoryRight.toFields()) merkle.set(Poseidon.hash(bobPublic.toFields()), right) merkle.set(Poseidon.hash(alicePublic.toFields()), right) merkle.set(Poseidon.hash(dylanPublic.toFields()), right) merkle.set(Poseidon.hash(senderPublic.toFields()), right) await deployPool() await mintToken(senderPublic) const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) const txn4 = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquidities(amt, amtToken) }) await txn4.prove() await txn4.sign([senderKey]).send() const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateFactoryInfo({ newVkHash: vkFactoryUpgradeTest.hash, deadlineSlot: UInt32.from(time) }) Provable.log("info validate", info.toFields()) Provable.log("bob", bobPublic) const signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: merkle.getRoot(), messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: updateFactoryRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: updateFactoryRight }) const array = [infoBob, infoAlice] const proof = new Multisig({ info: multi, signatures: array }) const vk = await zkApp.getPoolVK() const vkTh = await zkApp.getPoolTokenHolderVK() Provable.log("vk", vk.hash) Provable.log("vk th", vk.hash) const txn = await Mina.transaction(deployerAccount, async () => { await zkApp.updateVerificationKey(proof, vkFactoryUpgradeTest) }) await txn.prove() await txn.sign([deployerKey]).send() const pool = new Pool(zkPoolAddress) const poolTH = new PoolTokenHolder(zkPoolAddress, zkToken.deriveTokenId()) Pool.FactoryContract = PoolFactoryUpgradeTest PoolTokenHolder.FactoryContract = PoolFactoryUpgradeTest let accountpool = Mina.getAccount(zkPoolAddress) let accountpoolTh = Mina.getAccount(zkPoolAddress, zkToken.deriveTokenId()) expect(vk.hash).toEqual(accountpool.zkapp?.verificationKey?.hash) expect(vkTh.hash).toEqual(accountpoolTh.zkapp?.verificationKey?.hash) const txn2 = await Mina.transaction(deployerAccount, async () => { await pool.updateVerificationKey() await poolTH.updateVerificationKey() await zkToken.approveAccountUpdate(poolTH.self) }) console.log("updateVerificationKey", txn2.toPretty()) await txn2.prove() await txn2.sign([deployerKey]).send() accountpool = Mina.getAccount(zkPoolAddress) accountpoolTh = Mina.getAccount(zkPoolAddress, zkToken.deriveTokenId()) const newVk = await new PoolFactoryUpgradeTest(zkAppAddress).getPoolVK() const newVkTh = await new PoolFactoryUpgradeTest(zkAppAddress).getPoolTokenHolderVK() Provable.log("newVk", newVk.hash) Provable.log("newVkTh", newVkTh.hash) expect(newVk.hash).not.toEqual(vk.hash) expect(newVk.hash).toEqual(accountpool.zkapp?.verificationKey?.hash) expect(newVkTh.hash).not.toEqual(vkTh.hash) expect(newVkTh.hash).toEqual(accountpoolTh.zkapp?.verificationKey?.hash) }) it("update delegator", async () => { const right = Poseidon.hash(updateDelegatorRight.toFields()) merkle.set(Poseidon.hash(bobPublic.toFields()), right) merkle.set(Poseidon.hash(alicePublic.toFields()), right) merkle.set(Poseidon.hash(dylanPublic.toFields()), right) merkle.set(Poseidon.hash(senderPublic.toFields()), right) await deployPool() const pk = PrivateKey.random() const oldAccount = await zkApp.delegator.fetch() const pkNew = PrivateKey.random() const newAccount = pkNew.toPublicKey() const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateAccountInfo({ oldUser: oldAccount!, newUser: newAccount, right: updateDelegatorRight, deadlineSlot: UInt32.from(time) }) Provable.log("info validate", info.toFields()) Provable.log("bob", bobPublic) const signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: merkle.getRoot(), messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: updateDelegatorRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: updateDelegatorRight }) const array = [infoBob, infoAlice] const proof = new Multisig({ info: multi, signatures: array }) const txn = await Mina.transaction(deployerAccount, async () => { await zkApp.setNewDelegator(proof, newAccount) }) await txn.prove() await txn.sign([deployerKey]).send() }) it("update protocol", async () => { const right = Poseidon.hash(updateProtocolRight.toFields()) merkle.set(Poseidon.hash(bobPublic.toFields()), right) merkle.set(Poseidon.hash(alicePublic.toFields()), right) merkle.set(Poseidon.hash(dylanPublic.toFields()), right) merkle.set(Poseidon.hash(senderPublic.toFields()), right) await deployPool() const pk = PrivateKey.random() const oldAccount = await zkApp.protocol.fetch() const pkNew = PrivateKey.random() const newAccount = pkNew.toPublicKey() const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateAccountInfo({ oldUser: oldAccount!, newUser: newAccount, right: updateProtocolRight, deadlineSlot: UInt32.from(time) }) Provable.log("info validate", info.toFields()) Provable.log("bob", bobPublic) const signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: merkle.getRoot(), messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: updateProtocolRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: updateProtocolRight }) const array = [infoBob, infoAlice] const proof = new Multisig({ info: multi, signatures: array }) const txn = await Mina.transaction(deployerAccount, async () => { await zkApp.setNewProtocol(proof, newAccount) }) await txn.prove() await txn.sign([deployerKey]).send() }) it("update factory", async () => { const right = Poseidon.hash(updateFactoryRight.toFields()) merkle.set(Poseidon.hash(bobPublic.toFields()), right) merkle.set(Poseidon.hash(alicePublic.toFields()), right) merkle.set(Poseidon.hash(dylanPublic.toFields()), right) merkle.set(Poseidon.hash(senderPublic.toFields()), right) await deployPool() const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateFactoryInfo({ newVkHash: vkUpgradeTest.hash, deadlineSlot: UInt32.from(time) }) Provable.log("info validate", info.toFields()) Provable.log("bob", bobPublic) const signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: merkle.getRoot(), messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: updateFactoryRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: updateFactoryRight }) const array = [infoBob, infoAlice] const proof = new Multisig({ info: multi, signatures: array }) const txn = await Mina.transaction(deployerAccount, async () => { await zkApp.updateVerificationKey(proof, vkUpgradeTest) }) await txn.prove() await txn.sign([deployerKey]).send() }) it("update signer", async () => { const right = Poseidon.hash(updateSignerRight.toFields()) merkle.set(Poseidon.hash(bobPublic.toFields()), right) merkle.set(Poseidon.hash(alicePublic.toFields()), right) merkle.set(Poseidon.hash(dylanPublic.toFields()), right) merkle.set(Poseidon.hash(senderPublic.toFields()), right) await deployPool() const newMerkle = new MerkleMap() newMerkle.set(Poseidon.hash(bobPublic.toFields()), right) newMerkle.set(Poseidon.hash(alicePublic.toFields()), right) newMerkle.set(Poseidon.hash(deployerAccount.toFields()), right) const today = new Date() today.setDate(today.getDate() + 1) const tomorrow = today.getTime() const time = getSlotFromTimestamp(tomorrow) const info = new UpdateSignerData({ oldRoot: merkle.getRoot(), newRoot: newMerkle.getRoot(), deadlineSlot: UInt32.from(time) }) Provable.log("info validate", info.toFields()) Provable.log("bob", bobPublic) const signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const deployerPublic = deployerAccount.key.toPublicKey() const newsignBob = Signature.create(bobKey, info.toFields()) const newsignDeployer = Signature.create(deployerAccount.key, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: merkle.getRoot(), messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: updateSignerRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: updateSignerRight }) const array = [infoBob, infoAlice] const newinfoBob = new SignatureInfo({ user: bobPublic, witness: newMerkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: newsignBob, right: updateSignerRight }) const newinfoDeployer = new SignatureInfo({ user: deployerPublic, witness: newMerkle.getWitness(Poseidon.hash(deployerPublic.toFields())), signature: newsignDeployer, right: updateSignerRight }) const newarray = [newinfoBob, newinfoDeployer] const proof = new MultisigSigner({ info: multi, signatures: array, newSignatures: newarray }) const txn = await Mina.transaction(deployerAccount, async () => { await zkApp.updateApprovedSigner(proof, newMerkle.getRoot()) }) await txn.prove() await txn.sign([deployerKey]).send() }) function getSlotFromTimestamp(date: number) { const { genesisTimestamp, slotTime } = Mina.activeInstance.getNetworkConstants() let slotCalculated = UInt64.from(date) slotCalculated = (slotCalculated.sub(genesisTimestamp)).div(slotTime) Provable.log("slotCalculated64", slotCalculated) return slotCalculated.toUInt32() } })