UNPKG

@lumina-dex/contracts

Version:
643 lines (552 loc) 25.6 kB
import { fetchAccount, Field, MerkleMap, Poseidon, Provable, PublicKey, Signature, UInt32 } from "o1js" import { AccountUpdate, Bool, Mina, PrivateKey, UInt8, UInt64 } from "o1js" import { beforeAll, beforeEach, describe, expect, it } from "vitest" import { allRight, deployPoolRight, FungibleToken, FungibleTokenAdmin, mulDiv, Multisig, MultisigInfo, Pool, PoolFactory, PoolTokenHolder, SignatureInfo, UpdateSignerData, updateSignerRight } from "../dist" import { getAmountLiquidityOutUint } from "../src" const proofsEnabled = false describe("Pool Factory Token", () => { let deployerAccount: Mina.TestPublicKey, deployerKey: PrivateKey, senderAccount: Mina.TestPublicKey, senderKey: PrivateKey, bobAccount: Mina.TestPublicKey, bobKey: PrivateKey, merkle: MerkleMap, aliceAccount: Mina.TestPublicKey, aliceKey: PrivateKey, dylanAccount: Mina.TestPublicKey, senderPublic: PublicKey, dylanPublic: PublicKey, deployerPublic: PublicKey, bobPublic: PublicKey, alicePublic: PublicKey, zkAppAddress: PublicKey, zkAppPrivateKey: PrivateKey, zkApp: PoolFactory, zkPoolAddress: PublicKey, zkPoolPrivateKey: PrivateKey, zkPool: Pool, zkTokenAdminAddress: PublicKey, zkTokenAdminPrivateKey: PrivateKey, zkTokenAdmin: FungibleTokenAdmin, zkTokenAddress0: PublicKey, zkTokenPrivateKey0: PrivateKey, zkToken0: FungibleToken, zkTokenAddress1: PublicKey, zkTokenPrivateKey1: PrivateKey, zkToken1: FungibleToken, tokenHolder: PoolTokenHolder beforeAll(async () => { const analyze = await Pool.analyzeMethods() getGates(analyze) if (proofsEnabled) { console.time("compile pool") await FungibleTokenAdmin.compile() await FungibleToken.compile() await PoolFactory.compile() await Pool.compile() await PoolTokenHolder.compile() console.timeEnd("compile pool") } function getGates(analyze: any) { for (const key in analyze) { if (Object.prototype.hasOwnProperty.call(analyze, key)) { const element = analyze[key] console.log(key, element?.gates.length) } } } }) beforeEach(async () => { // no transaction limits on zeko const Local = await Mina.LocalBlockchain({ proofsEnabled, enforceTransactionLimits: false }) Mina.setActiveInstance(Local) ;[deployerAccount, senderAccount, bobAccount, aliceAccount, dylanAccount] = Local.testAccounts deployerKey = deployerAccount.key senderKey = senderAccount.key bobKey = bobAccount.key aliceKey = aliceAccount.key senderPublic = senderKey.toPublicKey() bobPublic = bobKey.toPublicKey() alicePublic = aliceKey.toPublicKey() deployerPublic = deployerKey.toPublicKey() dylanPublic = dylanAccount.key.toPublicKey() 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) const keyTokenX = PrivateKey.random() const keyTokenY = PrivateKey.random() // order token to create pool const xIsLower = keyTokenX.toPublicKey().x.lessThan(keyTokenY.toPublicKey().x) zkTokenPrivateKey0 = xIsLower.toBoolean() ? keyTokenX : keyTokenY zkTokenAddress0 = zkTokenPrivateKey0.toPublicKey() zkToken0 = new FungibleToken(zkTokenAddress0) zkTokenPrivateKey1 = xIsLower.toBoolean() ? keyTokenY : keyTokenX zkTokenAddress1 = zkTokenPrivateKey1.toPublicKey() zkToken1 = new FungibleToken(zkTokenAddress1) tokenHolder = new PoolTokenHolder(zkPoolAddress, zkToken0.deriveTokenId()) merkle = new MerkleMap() const allRightHash = Poseidon.hash(allRight.toFields()) merkle = new MerkleMap() merkle.set(Poseidon.hash(bobPublic.toFields()), allRightHash) merkle.set(Poseidon.hash(alicePublic.toFields()), allRightHash) merkle.set(Poseidon.hash(senderPublic.toFields()), Poseidon.hash(updateSignerRight.toFields())) merkle.set(Poseidon.hash(deployerPublic.toFields()), Poseidon.hash(deployPoolRight.toFields())) merkle.set(Poseidon.hash(dylanPublic.toFields()), allRightHash) 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 signBob = Signature.create(bobKey, info.toFields()) const signAlice = Signature.create(aliceKey, info.toFields()) const multi = new MultisigInfo({ approvedUpgrader: root, messageHash: info.hash(), deadlineSlot: UInt32.from(time) }) const infoBob = new SignatureInfo({ user: bobPublic, witness: merkle.getWitness(Poseidon.hash(bobPublic.toFields())), signature: signBob, right: allRight }) const infoAlice = new SignatureInfo({ user: alicePublic, witness: merkle.getWitness(Poseidon.hash(alicePublic.toFields())), signature: signAlice, right: allRight }) const array = [infoBob, infoAlice] const txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 4) await zkApp.deploy({ symbol: "FAC", src: "https://luminadex.com/", protocol: aliceAccount, delegator: dylanAccount, approvedSigner: root, multisig: new Multisig({ info: multi, signatures: array }) }) await zkTokenAdmin.deploy({ adminPublicKey: deployerAccount }) await zkToken0.deploy({ symbol: "LTA", src: "https://github.com/MinaFoundation/mina-fungible-token/blob/main/FungibleToken.ts", allowUpdates: false }) await zkToken0.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, zkTokenPrivateKey0]).send() // deploy token 2 const txn2 = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 2) await zkToken1.deploy({ symbol: "LTB", src: "https://github.com/MinaFoundation/mina-fungible-token/blob/main/FungibleToken.ts", allowUpdates: false }) await zkToken1.initialize( zkTokenAdminAddress, UInt8.from(9), Bool(false) ) }) await txn2.prove() // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization await txn2.sign([deployerKey, zkAppPrivateKey, zkTokenAdminPrivateKey, zkTokenPrivateKey1]).send() const signature = Signature.create(bobKey, zkPoolAddress.toFields()) const witness = merkle.getWitness(Poseidon.hash(bobPublic.toFields())) const txn3 = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 5) await zkApp.createPoolToken( zkPoolAddress, zkTokenAddress0, zkTokenAddress1, bobAccount, signature, witness, allRight ) }) // console.log("Pool creation", txn3.toPretty()); 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() // mint token to user await mintToken(senderAccount) }) it("add first liquidity", async () => { const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) const txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) console.log("supplyFirstLiquidities", txn.toPretty()) console.log("supplyFirstLiquidities au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() /* const liquidityUser = Mina.getBalance(senderAccount, zkPool.deriveTokenId()); const expected = amt.value.add(amtToken.value).sub(PoolMina.minimunLiquidity.value); console.log("liquidity user", liquidityUser.toString()); expect(liquidityUser.value).toEqual(expected);*/ const balanceToken = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) expect(balanceToken.value).toEqual(amt.value) const balanceMina = Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) expect(balanceMina.value).toEqual(amtToken.value) }) it("generate different key", async () => { const newKey = PrivateKey.randomKeypair() const fields = zkTokenAddress0.toFields().concat(zkTokenAddress1.toFields()) const hash = Poseidon.hashToGroup(fields) const publicKey = PublicKey.fromGroup(hash) console.log("publickey", publicKey.toBase58()) const fields2 = zkTokenAddress0.toFields().concat(newKey.publicKey.toFields()) const hash2 = Poseidon.hashToGroup(fields2) const publicKey2 = PublicKey.fromGroup(hash2) console.log("publicKey2", publicKey2.toBase58()) const fields3 = newKey.publicKey.toFields().concat(zkTokenAddress1.toFields()) const hash3 = Poseidon.hashToGroup(fields3) const publicKey3 = PublicKey.fromGroup(hash3) console.log("publicKey3", publicKey3.toBase58()) expect(publicKey.toBase58()).not.toEqual(publicKey2) expect(publicKey2.toBase58()).not.toEqual(publicKey3) }) it("Transfer liquidity", async () => { const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) // console.log("supplyFirstLiquidities", txn.toPretty()); console.log("supplyFirstLiquidities au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() const liquidityUser = Mina.getBalance(senderAccount, zkPool.deriveTokenId()) const expected = amt.value.add(amtToken.value).sub(Pool.minimumLiquidity.value) expect(liquidityUser.value).toEqual(expected) txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.transfer(senderAccount, bobAccount, UInt64.from(1000)) }) // console.log("supplyFirstLiquidities", txn.toPretty()); console.log("supplyFirstLiquidities au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() const liquidityBob = Mina.getBalance(bobAccount, zkPool.deriveTokenId()) expect(liquidityBob.value).toEqual(UInt64.from(1000).value) }) it("withdraw liquidity", async () => { const minaUser = Mina.getBalance(senderAccount) console.log("mina before", minaUser.toBigInt()) const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) console.log("supplyFirstLiquidities", txn.toPretty()) await txn.prove() await txn.sign([senderKey]).send() const minaUserAfterDeposit = Mina.getBalance(senderAccount) const expectedMina = minaUser.sub(amt) // expect(minaUserAfterDeposit.value).toEqual(expectedMina.value); console.log("mina after deposit", minaUserAfterDeposit.toBigInt()) const liquidityUser = Mina.getBalance(senderAccount, zkPool.deriveTokenId()) // const expected = amt.value.add(amtToken.value).sub(MINIMUM_LIQUIDITY.value); const supply = await Mina.getBalance(zkPoolAddress, zkPool.deriveTokenId()) const balPool0 = await Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) console.log("bal pool 0", balPool0.toBigInt()) const liquityOut = UInt64.from(1 * 10 ** 9) const amountMinaOut = mulDiv(liquityOut, amt, supply) const amountTokenOut = mulDiv(liquityOut, amtToken, supply) txn = await Mina.transaction(senderAccount, async () => { await tokenHolder.withdrawLiquidityToken(liquityOut, amountMinaOut, amountTokenOut, amt, amtToken, supply) await zkToken0.approveAccountUpdate(tokenHolder.self) // await zkToken1.approveAccountUpdate(tokenHolder.self); }) console.log("Withdraw liquidity", txn.toPretty()) console.log("Withdraw liquidity au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() const minaUserAfter = Mina.getBalance(senderAccount) console.log("mina after", minaUserAfter.toBigInt()) }) it("withdraw liquidity after swap", async () => { let amt = UInt64.from(50 * 10 ** 9) let amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) await txn.prove() await txn.sign([senderKey]).send() const reserveIn = Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) const reserveOut = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) let amountIn = UInt64.from(5 * 10 ** 9) const balanceMin = reserveOut.sub(reserveOut.div(100)) const balanceMax = reserveIn.add(reserveIn.div(100)) const protocol = await zkApp.getProtocol() const txn2 = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await tokenHolder.swapFromTokenToToken(protocol, UInt64.from(5), amountIn, UInt64.from(1), balanceMax, balanceMin) await zkToken0.approveAccountUpdate(tokenHolder.self) }) await txn2.prove() await txn2.sign([senderKey]).send() const supply = await Mina.getBalance(zkPoolAddress, zkPool.deriveTokenId()) const balPool0 = await Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) const balPool1 = await Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) const liquityOut = UInt64.from(1 * 10 ** 9) const amountMinaOut = mulDiv(liquityOut, balPool0, supply) const amountTokenOut = mulDiv(liquityOut, balPool1, supply) await fetchAccount({ publicKey: senderAccount }) await fetchAccount({ publicKey: senderAccount }) txn = await Mina.transaction(senderAccount, async () => { await tokenHolder.withdrawLiquidityToken(liquityOut, amountMinaOut, amountTokenOut, balPool0, balPool1, supply) await zkToken0.approveAccountUpdate(tokenHolder.self) }) await txn.prove() await txn.sign([senderKey]).send() }) it("withdraw liquidity after swap token 1", async () => { let amt = UInt64.from(50 * 10 ** 9) let amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) await txn.prove() await txn.sign([senderKey]).send() const reserveIn = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) const reserveOut = Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) let amountIn = UInt64.from(5 * 10 ** 9) const balanceMin = reserveOut.sub(reserveOut.div(100)) const balanceMax = reserveIn.add(reserveIn.div(100)) const protocol = await zkApp.getProtocol() const tokenHolder2 = new PoolTokenHolder(zkPoolAddress, zkToken1.deriveTokenId()) const txn2 = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await tokenHolder2.swapFromTokenToToken( protocol, UInt64.from(5), amountIn, UInt64.from(1), balanceMax, balanceMin ) await zkToken1.approveAccountUpdate(tokenHolder2.self) }) await txn2.prove() await txn2.sign([senderKey]).send() const supply = await Mina.getBalance(zkPoolAddress, zkPool.deriveTokenId()) const balPool0 = await Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) const balPool1 = await Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) const liquityOut = UInt64.from(1 * 10 ** 9) const amountMinaOut = mulDiv(liquityOut, balPool0, supply) const amountTokenOut = mulDiv(liquityOut, balPool1, supply) txn = await Mina.transaction(senderAccount, async () => { await tokenHolder.withdrawLiquidityToken(liquityOut, amountMinaOut, amountTokenOut, balPool0, balPool1, supply) await zkToken0.approveAccountUpdate(tokenHolder.self) }) await txn.prove() await txn.sign([senderKey]).send() }) it("add second liquidity", async () => { const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) console.log("createPool au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() let liquidityUser = Mina.getBalance(senderAccount, zkPool.deriveTokenId()) const expected = amt.value.add(amtToken.value).sub(Pool.minimumLiquidity.value) const totalLiquidity = Mina.getBalance(zkPoolAddress, zkPool.deriveTokenId()) console.log("liquidity user", liquidityUser.toString()) expect(liquidityUser.value).toEqual(expected) const amtMina = UInt64.from(1 * 10 ** 9) const amtToken2 = UInt64.from(5 * 10 ** 9) txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkPool.supplyLiquidityToken(amtMina, amtToken2, amt, amtToken, totalLiquidity) }) console.log("add liquidity from mina", txn.toPretty()) console.log("add liquidity from mina au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([deployerKey]).send() const liquidityOut = mulDiv(amtMina, totalLiquidity, amt) liquidityUser = Mina.getBalance(deployerAccount, zkPool.deriveTokenId()) expect(liquidityUser.value).toEqual(liquidityOut.value) console.log("liquidity deployer", liquidityUser.toString()) }) it("add second liquidity slippage", async () => { const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) let txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) console.log("createPool au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([senderKey]).send() let liquidityUser = Mina.getBalance(senderAccount, zkPool.deriveTokenId()) const expected = amt.value.add(amtToken.value).sub(Pool.minimumLiquidity.value) const totalLiquidity = Mina.getBalance(zkPoolAddress, zkPool.deriveTokenId()) console.log("liquidity user", liquidityUser.toString()) expect(liquidityUser.value).toEqual(expected) const amtToken0 = UInt64.from(1 * 10 ** 9) const reserve = await getReserves(zkPoolAddress) const out = getAmountLiquidityOutUint( amtToken0, reserve.amountMina, reserve.amountToken, reserve.liquidity, UInt64.one ) txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkPool.supplyLiquidityToken(out.amountAIn, out.amountBIn, out.balanceAMax, out.balanceBMax, out.supplyMin) }) console.log("add liquidity from mina", txn.toPretty()) console.log("add liquidity from mina au", txn.transaction.accountUpdates.length) await txn.prove() await txn.sign([deployerKey]).send() liquidityUser = Mina.getBalance(deployerAccount, zkPool.deriveTokenId()) expect(liquidityUser.value).toEqual(out.liquidity.value) console.log("liquidity deployer", liquidityUser.toString()) }) async function getReserves(poolAddress: PublicKey) { const acc = await fetchAccount({ publicKey: poolAddress }) const zkPool = new Pool(poolAddress) const token0 = await zkPool.token0.fetch() const token = await zkPool.token1.fetch() const zkToken0 = new FungibleToken(token0!) const zkToken = new FungibleToken(token!) const accToken = await fetchAccount({ publicKey: poolAddress, tokenId: zkToken.deriveTokenId() }) const accLiquidity = await fetchAccount({ publicKey: poolAddress, tokenId: zkPool.deriveTokenId() }) return { amountToken: Mina.getBalance(poolAddress, zkToken.deriveTokenId()), amountMina: Mina.getBalance(poolAddress, zkToken0.deriveTokenId()), liquidity: Mina.getBalance(poolAddress, zkPool.deriveTokenId()) } } it("swap from token", async () => { const amt = UInt64.from(10 * 10 ** 9) const amtToken = UInt64.from(50 * 10 ** 9) const txn = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await zkPool.supplyFirstLiquiditiesToken(amt, amtToken) }) await txn.prove() await txn.sign([senderKey]).send() const reserveIn = Mina.getBalance(zkPoolAddress, zkToken1.deriveTokenId()) const reserveOut = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()) const amountIn = UInt64.from(1.3 * 10 ** 9) console.log("current bal in", reserveIn.toBigInt()) const balanceMin = reserveOut.sub(reserveOut.div(100)) const balanceMax = reserveIn.add(reserveIn.div(100)) const expectedOut = mulDiv(balanceMin, amountIn, balanceMax.add(amountIn)) const optimalOut = mulDiv(reserveOut, amountIn, reserveIn.add(amountIn)) const minOut = optimalOut.sub(optimalOut.div(50)) // 2 % dif const balBefore = Mina.getBalance(senderAccount, zkToken0.deriveTokenId()) const userMinaBalBefore = Mina.getBalance(senderAccount) const protocol = await zkApp.getProtocol() const txn2 = await Mina.transaction(senderAccount, async () => { AccountUpdate.fundNewAccount(senderAccount, 1) await tokenHolder.swapFromTokenToToken( protocol, UInt64.from(5), amountIn, UInt64.from(1), balanceMax, balanceMin ) await zkToken0.approveAccountUpdate(tokenHolder.self) }) console.log("swap from token", txn2.toPretty()) console.log("swap from token au", txn2.transaction.accountUpdates.length) await txn2.prove() await txn2.sign([senderKey]).send() /* const userMinaBalAfter = Mina.getBalance(senderAccount); console.log('optimal out', optimalOut.toBigInt()); console.log('minimal out', minOut.toBigInt()); console.log('expected out', expectedOut.toBigInt()); console.log('received', userMinaBalAfter.sub(userMinaBalBefore).toBigInt());*/ // const resIN = reserveIn.add(amountIn); // const resOut = reserveOut.sub(expectedOut); // const reserveIn2 = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()); // const reserveOut2 = Mina.getBalance(zkPoolAddress, zkToken0.deriveTokenId()); // expect(reserveIn2.value).toEqual(resIN.value); // expect(reserveOut2.value).toEqual(resOut.value); // const balAfter = Mina.getBalance(senderAccount, zkToken0.deriveTokenId()); // expect(balAfter.value).toEqual(balBefore.sub(amountIn).value); }) 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 zkToken0.mint(user, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey0]).send() txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkToken0.mint(deployerAccount, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey0]).send() txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkToken1.mint(user, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey1]).send() txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount, 1) await zkToken1.mint(deployerAccount, UInt64.from(1000 * 10 ** 9)) }) await txn.prove() await txn.sign([deployerKey, zkTokenPrivateKey1]).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() } })