diff --git a/config.json b/config.json index 036f635..e856985 100644 --- a/config.json +++ b/config.json @@ -77,6 +77,13 @@ "feepayerKeyPath": "/home/huyminh/.cache/zkapp-cli/keys/myaccount.json", "feepayerAlias": "myaccount", "fee": "0.1" + }, + "randomaccount": { + "url": "https://proxy.berkeley.minaexplorer.com/graphql", + "keyPath": "keys/randomaccount.json", + "feepayerKeyPath": "/home/huyminh/.cache/zkapp-cli/keys/myaccount.json", + "feepayerAlias": "myaccount", + "fee": "0.1" } } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 28ba8a3..ae3f8a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "@auxo-dev/platform", - "version": "0.1.1", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@auxo-dev/platform", - "version": "0.1.1", + "version": "0.1.3", "license": "Apache-2.0", "dependencies": { "@auxo-dev/auxo-libs": "0.3.5", - "@auxo-dev/dkg": "0.2.9", + "@auxo-dev/dkg": "0.2.12", "o1js": "0.15.1" }, "devDependencies": { @@ -61,11 +61,12 @@ } }, "node_modules/@auxo-dev/dkg": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@auxo-dev/dkg/-/dkg-0.2.9.tgz", - "integrity": "sha512-xy7i5Bfg9qbCnCvrM+GFA3K8uwqDo29/FKILZ7OR1qeTx1nMsc2IOziUgwQS0xD3Nh7eZp7ja3cvle/gLsdgmQ==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@auxo-dev/dkg/-/dkg-0.2.12.tgz", + "integrity": "sha512-xzVoU+pV8+VwCJoFGwjyj3fJGduuRNmrkDcwRz0fzW9HaNyjfRGCtb+mfdJMiPNWd5EBT9mkSVZNfb5AB8w4kA==", "dependencies": { "@auxo-dev/auxo-libs": "^0.3.5", + "axios": "^1.6.5", "o1js": "0.15.1" } }, @@ -3355,8 +3356,30 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/babel-jest": { "version": "27.5.1", @@ -3940,7 +3963,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4261,7 +4283,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -4964,6 +4985,25 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -7873,7 +7913,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7882,7 +7921,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8588,6 +8626,11 @@ "node": ">= 6" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/package.json b/package.json index b543539..f7ca991 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@auxo-dev/platform", - "version": "0.1.3", + "version": "0.1.4", "description": "Auxo's On-chain Funding platform on Mina blockchain", "author": "", "license": "Apache-2.0", @@ -64,7 +64,7 @@ "zkapp-cli": "^0.15.0" }, "dependencies": { - "@auxo-dev/dkg": "0.2.9", + "@auxo-dev/dkg": "0.2.12", "@auxo-dev/auxo-libs": "0.3.5", "o1js": "0.15.1" } diff --git a/src/contracts/Treasury.ts b/src/contracts/Treasury.ts index dd5f197..b367178 100644 --- a/src/contracts/Treasury.ts +++ b/src/contracts/Treasury.ts @@ -34,7 +34,7 @@ import { ZkApp } from '@auxo-dev/dkg'; import { INSTANCE_LIMITS, ZkAppEnum } from '../constants.js'; -import { Level1CWitness as indexWitness } from './ParticipationStorage.js'; +import { Level1CWitness as IndexWitness } from './ParticipationStorage.js'; const DefaultLevel1Root = EMPTY_LEVEL_1_TREE().getRoot(); @@ -60,12 +60,11 @@ export class ClaimFundInput extends Struct({ projectId: Field, requestId: Field, // TODO: Funding check requestId payeeAddress: PublicKey, // TODO: Project check address - M: ZkApp.Request.RequestVector, - D: ZkApp.Request.RequestVector, - DWitness: MerkleMapWitness, + M: ZkApp.Request.RequestVector, // check Funding + D: ZkApp.Request.RequestVector, // check at request + DWitness: MerkleMapWitness, // TODO check request contract investVector: InvestVector, - participationIndex: Field, - indexWitness: indexWitness, + participationIndexWitness: IndexWitness, claimedIndex: Level1CWitness, participationRef: ZkAppRef, }) { @@ -113,7 +112,7 @@ export const ClaimFund = ZkProgram({ }); }, }, - createTreasury: { + nextStep: { privateInputs: [ SelfProof, TreasuryAction, @@ -238,17 +237,9 @@ export class TreasuryContract extends SmartContract { // const participationContract = new ParticipationContract( // input.participationRef.address // ); + // check index in contract participant - // participationContract - // .checkParticipationIndex( - // new checkParticipationIndexInput({ - // campaignId: input.campaignId, - // projectId: input.projectId, - // participationIndex: input.participationIndex, - // indexWitness: input.indexWitness, - // }) - // ) - // .assertEquals(Bool(true)); + let participationIndex = input.participationIndexWitness.calculateIndex(); // check if claimed this.checkIfNotClaimed( @@ -260,7 +251,7 @@ export class TreasuryContract extends SmartContract { ).assertEquals(Bool(true)); let claimAmount = input.investVector.get( - input.participationIndex.sub(Field(1)) // since index start from 1 + participationIndex.sub(Field(1)) // since index start from 1 ); // send invest amount diff --git a/src/libs/utils.ts b/src/libs/utils.ts index 83e81d3..8f6f0cf 100644 --- a/src/libs/utils.ts +++ b/src/libs/utils.ts @@ -16,7 +16,7 @@ export function updateOutOfSnark(state: Field, action: Field[][]) { return AccountUpdate.Actions.updateSequenceState(state, actionsHash); } -const DEFAULT_WAIT_TIME = 7 * 60 * 1000; // 7m +const DEFAULT_WAIT_TIME = 10 * 60 * 1000; // 7m export async function wait(time?: number): Promise { let waitTime = time || DEFAULT_WAIT_TIME; diff --git a/src/scripts/Funding.test.ts b/src/scripts/Funding.test.ts index f540426..77a6281 100644 --- a/src/scripts/Funding.test.ts +++ b/src/scripts/Funding.test.ts @@ -289,6 +289,8 @@ describe('Funding', () => { let fundingContract = contracts[Contract.FUNDING] .contract as FundingContract; console.log('RollUp funding...'); + let balance = Number(Account(fundingContract.address).balance.get()); + console.log('Contract balance: ', balance); await fetchAllContract(contracts, [Contract.REQUEST]); @@ -335,6 +337,10 @@ describe('Funding', () => { ) ); }); + + balance = Number(Account(fundingContract.address).balance.get()); await proveAndSend(tx, [feePayerKey], Contract.FUNDING, ''); + + console.log('Contract balance after: ', balance); }); -}); +}) diff --git a/src/scripts/Platform.ts b/src/scripts/Platform.ts index 36d07f8..7cd93b7 100644 --- a/src/scripts/Platform.ts +++ b/src/scripts/Platform.ts @@ -12,6 +12,10 @@ import { Poseidon, Account, AccountUpdate, + Group, + MerkleMap, + MerkleMapWitness, + Bool, } from 'o1js'; import fs from 'fs/promises'; import { Config, Key } from './helper/config.js'; @@ -80,6 +84,8 @@ import { TreasuryContract, ClaimFund, TreasuryAction, + ClaimFundInput, + InvestVector, } from '../contracts/Treasury.js'; import { ClaimedStorage } from '../contracts/TreasuryStorage.js'; import { @@ -91,7 +97,6 @@ import { wait, } from '../libs/utils.js'; import { CustomScalarArray, ZkApp } from '@auxo-dev/dkg'; -import { RequestStorage } from '@auxo-dev/dkg/build/esm/src/contracts/storages.js'; // const isCompile = false; @@ -99,8 +104,8 @@ const isDeploy = false; const isProject = false; const isCampaign = false; const isParticipation = false; -const isFunding = true; -const isTreasury = false; +const isFunding = false; +const isTreasury = true; async function main() { console.time('runTime'); @@ -266,6 +271,7 @@ async function main() { let tx; if (isDeploy) { + console.log('Deploying'); // // Deploy ProjectContract // await deploy( // contracts[Contract.PROJECT], @@ -294,44 +300,62 @@ async function main() { // ); // Deploy FundingContract - await deploy( - contracts[Contract.FUNDING], - [['zkApps', fundingAddressStorage.addresses.getRoot()]], - feePayerKey, - fee, - ++feePayerNonce - ); + // await deploy( + // contracts[Contract.FUNDING], + // [['zkApps', fundingAddressStorage.addresses.getRoot()]], + // feePayerKey, + // fee, + // ++feePayerNonce + // ); + + // tx = await Mina.transaction( + // { sender: feePayerKey.publicKey, fee, nonce: ++feePayerNonce }, + // () => { + // let feePayerAccount = AccountUpdate.createSigned(feePayerKey.publicKey); + // feePayerAccount.send({ + // to: contracts[Contract.FUNDING].contract, + // amount: 5 * 10 ** 9, + // }); // 5 Mina to send request - which cost 1 + // } + // ); + // await tx.sign([feePayerKey.privateKey]).send(); + + // Deploy RequestConctract + // await deploy( + // contracts[Contract.REQUEST], + // [], + // feePayerKey, + // fee, + // ++feePayerNonce + // ); + // Deploy TreasuryContract + let treasuryContract = contracts[Contract.TREASURY] + .contract as TreasuryContract; tx = await Mina.transaction( { sender: feePayerKey.publicKey, fee, nonce: ++feePayerNonce }, () => { - let feePayerAccount = AccountUpdate.createSigned(feePayerKey.publicKey); + let feePayerAccount = AccountUpdate.fundNewAccount( + feePayerKey.publicKey, + 1 + ); + treasuryContract.deploy(); + treasuryContract.zkApps.set(treasuryAddressStorage.addresses.getRoot()); feePayerAccount.send({ - to: contracts[Contract.FUNDING].contract, - amount: 5 * 10 ** 9, - }); // 5 Mina to send request - which cost 1 + to: contracts[Contract.TREASURY].contract, + amount: 1 * 10 ** 9, + }); // Mina for investor to claim } ); - await tx.sign([feePayerKey.privateKey]).send(); - - // Deploy TreasuryContract - await deploy( - contracts[Contract.TREASURY], - [['zkApps', treasuryAddressStorage.addresses.getRoot()]], - feePayerKey, - fee, - ++feePayerNonce - ); - - // Deploy RequestConctract - await deploy( - contracts[Contract.REQUEST], - [], - feePayerKey, - fee, - ++feePayerNonce - ); - + await tx.prove(); + await tx + .sign([ + feePayerKey.privateKey, + contracts[Contract.TREASURY].key.privateKey, + ]) + .send(); + + console.log('Deploy done all'); // if (isProject) await wait(); await wait(); } @@ -910,6 +934,172 @@ async function main() { } if (isTreasury) { + let treasuryContract = contracts[Contract.TREASURY] + .contract as TreasuryContract; + + await fetchAllContract(contracts, [Contract.TREASURY]); + + let acc1: { privateKey: string; publicKey: string } = JSON.parse( + await fs.readFile('keys/acc1.json', 'utf8') + ); + let acc2: { privateKey: string; publicKey: string } = JSON.parse( + await fs.readFile('keys/acc2.json', 'utf8') + ); + + let projects: Key[] = [ + { + privateKey: PrivateKey.fromBase58(acc1.privateKey), + publicKey: PublicKey.fromBase58(acc1.publicKey), + }, + { + privateKey: PrivateKey.fromBase58(acc2.privateKey), + publicKey: PublicKey.fromBase58(acc2.publicKey), + }, + ]; + + let randomPrivateKey = PrivateKey.fromBase58( + 'EKE3xkv6TyhxSzBPeiiAppDfKsJVp7gXS7iuS2RNj8TGJvvhG6FM' + ); + let randomPublickey = randomPrivateKey.toPublicKey(); + // mock sumD value + let sumD = ZkApp.Request.RequestVector.from([ + randomPublickey.toGroup(), + randomPublickey.toGroup(), + randomPublickey.toGroup(), + randomPublickey.toGroup(), + ]); + + // earn each 0.01 total 0.02 + let investVectors = InvestVector.from([ + Field(1e7), + Field(0), + Field(1e7), + Field(0), + ]); + + let tempSumM = []; + + for (let i = 0; i < Number(investVectors.length); i++) { + let temp = Group.generator.scale( + Scalar.from(investVectors.get(Field(i)).toBigInt()) + ); + tempSumM.push(temp.add(sumD.get(Field(i)))); + } + + let sumM = ZkApp.Request.RequestVector.from(tempSumM); + + // contract request storage: + let DStorage = new MerkleMap(); + + let claimFundInput = [ + new ClaimFundInput({ + campaignId: Field(1), + projectId: Field(1), + requestId: Field(6969), + payeeAddress: projects[0].publicKey, + M: sumM, + D: sumD, + DWitness: DStorage.getWitness(Field(6969)), + investVector: investVectors, + participationIndexWitness: indexStorage.getLevel1Witness(Field(1)), + claimedIndex: claimedStorage.getLevel1Witness( + claimedStorage.calculateLevel1Index({ + campaignId: Field(1), + projectId: Field(1), + }) + ), + participationRef: getZkAppRef( + treasuryAddressStorage.addresses, + ZkAppEnum.PARTICIPATION, + contracts[Contract.PARTICIPATION].contract.address + ), + }), + new ClaimFundInput({ + campaignId: Field(1), + projectId: Field(2), + requestId: Field(6969), + payeeAddress: projects[1].publicKey, + M: sumM, + D: sumD, + DWitness: DStorage.getWitness(Field(6969)), + investVector: investVectors, + participationIndexWitness: indexStorage.getLevel1Witness(Field(3)), + claimedIndex: claimedStorage.getLevel1Witness( + claimedStorage.calculateLevel1Index({ + campaignId: Field(1), + projectId: Field(2), + }) + ), + participationRef: getZkAppRef( + treasuryAddressStorage.addresses, + ZkAppEnum.PARTICIPATION, + contracts[Contract.PARTICIPATION].contract.address + ), + }), + ]; + + for (let i = 0; i < projects.length; i++) { + await fetchAccount({ publicKey: projects[i].publicKey }); + let balanceBefore = Number(Account(projects[i].publicKey).balance.get()); + // tx = await Mina.transaction( + // { sender: projects[i].publicKey, fee }, + // () => { + // treasuryContract.claimFund(claimFundInput[i]); + // } + // ); + // await proveAndSend(tx, [projects[i]], Contract.TREASURY, 'claimFund'); + let balanceAfter = Number(Account(projects[i].publicKey).balance.get()); + console.log('Balance change: ', balanceBefore - balanceAfter); + + treasuryAction.push( + new TreasuryAction({ + campaignId: claimFundInput[i].campaignId, + projectId: claimFundInput[i].projectId, + }) + ); + } + + // await wait(); + await fetchAllContract(contracts, [Contract.TREASURY]); + + console.log('First step: '); + let reduceFundingProof = await ClaimFund.firstStep( + treasuryContract.claimedTreeRoot.get(), + Reducer.initialActionState + ); + + console.log('Next step: '); + + for (let i = projects.length - 1; i >= 0; i--) { + console.log('Step', i); + reduceFundingProof = await ClaimFund.nextStep( + reduceFundingProof, + treasuryAction[i], + claimedStorage.getWitness( + claimedStorage.calculateLevel1Index({ + campaignId: treasuryAction[i].campaignId, + projectId: treasuryAction[i].projectId, + }) + ) + ); + + // update storage: + claimedStorage.updateLeaf( + claimedStorage.calculateLeaf(Bool(true)), + claimedStorage.calculateLevel1Index({ + campaignId: treasuryAction[i].campaignId, + projectId: treasuryAction[i].projectId, + }) + ); + } + + tx = await Mina.transaction( + { sender: feePayerKey.publicKey, fee, nonce: ++feePayerNonce }, + () => { + treasuryContract.rollup(reduceFundingProof); + } + ); + await proveAndSend(tx, [feePayerKey], Contract.TREASURY, 'rollup'); } console.log('done all'); diff --git a/src/scripts/Treasury.test.ts b/src/scripts/Treasury.test.ts index 897a433..e5f46d8 100644 --- a/src/scripts/Treasury.test.ts +++ b/src/scripts/Treasury.test.ts @@ -1,398 +1,334 @@ -// import { -// Field, -// Reducer, -// Mina, -// PrivateKey, -// PublicKey, -// AccountUpdate, -// Poseidon, -// MerkleMap, -// MerkleTree, -// MerkleWitness, -// Proof, -// Void, -// Cache, -// SmartContract, -// Scalar, -// Account, -// Provable, -// } from 'o1js'; - -// import fs from 'fs/promises'; -// import { getProfiler } from './helper/profiler.js'; -// import randomAccounts from './helper/randomAccounts.js'; -// import { -// FundingContract, -// CreateReduceProof, -// CreateRollupProof, -// FundingInput, -// } from '../contracts/Funding.js'; -// import { ValueStorage } from '../contracts/FundingStorage.js'; -// import { Key, Config } from './helper/config.js'; -// import { -// AddressStorage, -// EMPTY_ADDRESS_MT, -// ReduceStorage, -// getZkAppRef, -// ActionStatus, -// } from '../contracts/SharedStorage.js'; -// import { Contract, ZkAppEnum } from '../constants.js'; -// import { -// ContractList, -// deploy, -// proveAndSend, -// fetchAllContract, -// } from '../libs/utils.js'; -// import { CustomScalar } from '@auxo-dev/auxo-libs'; -// import { CustomScalarArray, ZkApp } from '@auxo-dev/dkg'; -// import { -// TreasuryContract, -// ClaimFund, -// TreasuryAction, -// ClaimFundInput, -// } from '../contracts/Treasury.js'; -// import { ClaimedStorage } from '../contracts/TreasuryStorage.js'; -// import { ParticipationContract } from '../contracts/Participation.js'; - -// describe('Funding', () => { -// const doProofs = false; -// const cache = Cache.FileSystem('./caches'); - -// let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs }); -// Mina.setActiveInstance(Local); - -// let feePayerKey: Key = Local.testAccounts[0]; -// let contracts: ContractList = {}; -// let addressMerkleTree = EMPTY_ADDRESS_MT(); -// let tx; -// // Funding storage -// let claimedStorage = new ClaimedStorage(); -// let allAddressStorage = new AddressStorage(addressMerkleTree); -// let treasuryAction: ClaimedStorage[] = []; -// let claimFundInput: ClaimFundInput[]; -// let fundingInput: FundingInput[]; -// let index: number; -// let treasuryActionStates: Field[]; -// let sumD: CustomScalarArray[] = [ -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(50n)), -// CustomScalar.fromScalar(Scalar.from(0n)), -// ]), -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(0n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// ]), -// ]; -// let secretVectors: CustomScalarArray[] = [ -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(50n)), -// CustomScalar.fromScalar(Scalar.from(0n)), -// ]), -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// CustomScalar.fromScalar(Scalar.from(0n)), -// CustomScalar.fromScalar(Scalar.from(10n)), -// ]), -// ]; - -// let randomsVectors: CustomScalarArray[] = [ -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(100n)), -// CustomScalar.fromScalar(Scalar.from(200n)), -// CustomScalar.fromScalar(Scalar.from(300n)), -// CustomScalar.fromScalar(Scalar.from(400n)), -// ]), -// new CustomScalarArray([ -// CustomScalar.fromScalar(Scalar.from(500n)), -// CustomScalar.fromScalar(Scalar.from(600n)), -// CustomScalar.fromScalar(Scalar.from(700n)), -// CustomScalar.fromScalar(Scalar.from(800n)), -// ]), -// ]; - -// let projects: Key[] = [ -// { -// privateKey: Local.testAccounts[1].privateKey, -// publicKey: Local.testAccounts[1].publicKey, -// }, -// { -// privateKey: Local.testAccounts[2].privateKey, -// publicKey: Local.testAccounts[2].publicKey, -// }, -// ]; - -// beforeAll(async () => { -// let configJson: Config = JSON.parse( -// await fs.readFile('config.json', 'utf8') -// ); -// await Promise.all( -// Object.keys(Contract) -// .filter((item) => isNaN(Number(item))) -// .map(async (e) => { -// let config = configJson.deployAliases[e.toLowerCase()]; -// // console.log(config); -// let keyBase58: { privateKey: string; publicKey: string } = JSON.parse( -// await fs.readFile(config.keyPath, 'utf8') -// ); -// let key = { -// privateKey: PrivateKey.fromBase58(keyBase58.privateKey), -// publicKey: PublicKey.fromBase58(keyBase58.publicKey), -// }; -// let contract = (() => { -// switch (e.toLowerCase()) { -// case Contract.FUNDING: -// return new FundingContract(key.publicKey); -// case Contract.TREASURY: -// return new TreasuryContract(key.publicKey); -// case Contract.PARTICIPATION: -// return new ParticipationContract(key.publicKey); -// case Contract.REQUEST: -// return new ZkApp.Request.RequestContract(key.publicKey); -// default: -// return new SmartContract(key.publicKey); -// } -// })(); - -// addressMerkleTree.setLeaf( -// AddressStorage.calculateIndex(ZkAppEnum[e]).toBigInt(), -// AddressStorage.calculateLeaf(key.publicKey) -// ); - -// contracts[e.toLowerCase()] = { -// name: e.toLowerCase(), -// key: key, -// contract: contract, -// actionStates: [Reducer.initialActionState], -// }; -// }) -// ); - -// allAddressStorage = new AddressStorage(addressMerkleTree); -// }); - -// // beforeEach(() => {}); - -// it('compile proof', async () => { -// console.log('ClaimFund.compile...'); -// await ClaimFund.compile(); -// if (doProofs) { -// console.log('TreasuryContract.compile...'); -// await TreasuryContract.compile(); -// } else { -// console.log('FundingContract.analyzeMethods...'); -// TreasuryContract.analyzeMethods(); -// } -// }); - -// it('Deploy and funding', async () => { -// await deploy( -// contracts[Contract.TREASURY], -// [['zkApps', allAddressStorage.addresses.getRoot()]], -// feePayerKey -// ); - -// tx = await Mina.transaction(feePayerKey.publicKey, () => { -// let feePayerAccount = AccountUpdate.createSigned(feePayerKey.publicKey); -// feePayerAccount.send({ -// to: contracts[Contract.FUNDING].contract, -// amount: 100 * 10 ** 9, -// }); // 100 Mina to claim fund -// }); -// await tx.sign([feePayerKey.privateKey]).send(); - -// console.log('Claim Fund...'); - -// let treasuryContract = contracts[Contract.TREASURY] -// .contract as TreasuryContract; - -// fundingInput = [ -// new FundingInput({ -// campaignId: Field(1), -// committeePublicKey: contracts[Contract.COMMITTEE].key.publicKey, -// secretVector: secretVectors[0], -// random: randomsVectors[0], -// treasuryContract: getZkAppRef( -// allAddressStorage.addresses, -// ZkAppEnum.TREASURY, -// contracts[Contract.TREASURY].contract.address -// ), -// }), -// new FundingInput({ -// campaignId: Field(1), -// committeePublicKey: contracts[Contract.COMMITTEE].key.publicKey, -// secretVector: secretVectors[1], -// random: randomsVectors[1], -// treasuryContract: getZkAppRef( -// allAddressStorage.addresses, -// ZkAppEnum.TREASURY, -// contracts[Contract.TREASURY].contract.address -// ), -// }), -// ]; - -// claimFundInput = [ -// new ClaimFundInput({ -// campaignId: Field(1), -// projectId: Field(1), -// committeeId: Field(1), -// keyId: Field(1), -// payeeAddress: projects[0].publicKey, -// R: ZkApp.Request.RequestVector, -// M: ZkApp.Request.RequestVector, -// D: ZkApp.Request.RequestVector, -// DWitness: MerkleMapWitness, -// investVector: InvestVector, -// participationIndex: Field, -// indexWitness: indexWitness, -// claimedIndex: Level1CWitness, -// participationRef: getZkAppRef( -// allAddressStorage.addresses, -// ZkAppEnum.PARTICIPATION, -// contracts[Contract.PARTICIPATION].contract.address -// ), -// }), -// new ClaimFundInput({ -// campaignId: Field(1), -// committeePublicKey: contracts[Contract.COMMITTEE].key.publicKey, -// secretVector: secretVectors[1], -// random: randomsVectors[1], -// treasuryContract: getZkAppRef( -// allAddressStorage.addresses, -// ZkAppEnum.TREASURY, -// contracts[Contract.TREASURY].contract.address -// ), -// }), -// ]; - -// let result: { -// R: ZkApp.Request.RequestVector; -// M: ZkApp.Request.RequestVector; -// }; - -// for (let i = 0; i < investors.length; i++) { -// let balanceBefore = Number(Account(investors[i].publicKey).balance.get()); -// tx = await Mina.transaction(investors[i].publicKey, () => { -// result = treasuryContract.fund(claimFundInput[i]); -// }); -// await proveAndSend(tx, [investors[i]], Contract.FUNDING, 'fund'); -// let balanceAfter = Number(Account(investors[i].publicKey).balance.get()); -// console.log('Balance change: ', balanceBefore - balanceAfter); - -// let { R, M } = result!; - -// treasuryAction.push( -// new TreasuryAction({ -// campaignId: claimFundInput[i].campaignId, -// R, -// M, -// }) -// ); -// } -// }); - -// it('Reduce', async () => { -// await fetchAllContract(contracts, [Contract.FUNDING]); - -// let treasuryContract = contracts[Contract.FUNDING] -// .contract as FundingContract; -// let lastActionState = treasuryContract.actionState.get(); -// treasuryActionStates = contracts[Contract.FUNDING].actionStates; -// index = treasuryActionStates.findIndex((obj) => -// Boolean(obj.equals(lastActionState)) -// ); -// Provable.log('lastActionStates: ', lastActionState); -// Provable.log('Funding action states: ', treasuryActionStates); -// Provable.log('Index: ', index); - -// console.log('Reduce funding...'); - -// console.log('First step: '); -// let reduceFundingProof = await CreateReduceProof.firstStep( -// treasuryContract.actionState.get(), -// treasuryContract.actionStatus.get() -// ); - -// console.log('Next step: '); - -// for (let i = 0; i < investors.length; i++) { -// console.log('Step', i); -// reduceFundingProof = await CreateReduceProof.nextStep( -// reduceFundingProof, -// treasuryAction[i], -// fundingReduceStorage.getWitness(treasuryActionStates[index + 1 + i]) -// ); - -// // update storage: -// fundingReduceStorage.updateLeaf( -// fundingReduceStorage.calculateIndex( -// treasuryActionStates[index + 1 + i] -// ), -// fundingReduceStorage.calculateLeaf(ActionStatus.REDUCED) -// ); -// } - -// tx = await Mina.transaction(feePayerKey.publicKey, () => { -// treasuryContract.reduce(reduceFundingProof); -// }); -// await proveAndSend(tx, [feePayerKey], Contract.FUNDING, 'reduce'); -// }); - -// it('RollUp', async () => { -// let treasuryContract = contracts[Contract.FUNDING] -// .contract as FundingContract; -// console.log('RollUp funding...'); - -// await fetchAllContract(contracts, [Contract.REQUEST]); - -// let rollUpFundingProof = await CreateRollupProof.firstStep( -// treasuryAction[0].campaignId, -// secretVectors[0].length, -// treasuryContract.actionStatus.get() -// ); - -// for (let i = 0; i < investors.length; i++) { -// console.log('Step', i); -// rollUpFundingProof = await CreateRollupProof.nextStep( -// rollUpFundingProof, -// treasuryAction[i], -// treasuryActionStates[index + i], -// fundingReduceStorage.getWitness(treasuryActionStates[index + 1 + i]) -// ); - -// // update storage: -// fundingReduceStorage.updateLeaf( -// fundingReduceStorage.calculateIndex( -// treasuryActionStates[index + 1 + i] -// ), -// fundingReduceStorage.calculateLeaf(ActionStatus.ROLL_UPED) -// ); -// } - -// tx = await Mina.transaction(feePayerKey.publicKey, () => { -// treasuryContract.rollupRequest( -// rollUpFundingProof, -// Field(2), -// Field(2), -// sumRStorage.getLevel1Witness( -// sumRStorage.calculateLevel1Index(treasuryAction[0].campaignId) -// ), -// sumMStorage.getLevel1Witness( -// sumMStorage.calculateLevel1Index(treasuryAction[0].campaignId) -// ), -// getZkAppRef( -// allAddressStorage.addresses, -// ZkAppEnum.REQUEST, -// contracts[Contract.REQUEST].contract.address -// ) -// ); -// }); -// await proveAndSend(tx, [feePayerKey], Contract.FUNDING, ''); -// }); -// }); +import { + Field, + Reducer, + Mina, + PrivateKey, + PublicKey, + AccountUpdate, + Poseidon, + MerkleMap, + MerkleTree, + MerkleWitness, + Proof, + Void, + Cache, + SmartContract, + Scalar, + Account, + Provable, + Group, + Bool, +} from 'o1js'; + +import fs from 'fs/promises'; +import { getProfiler } from './helper/profiler.js'; +import randomAccounts from './helper/randomAccounts.js'; +import { + FundingContract, + CreateReduceProof, + CreateRollupProof, + FundingInput, +} from '../contracts/Funding.js'; +import { ValueStorage } from '../contracts/FundingStorage.js'; +import { Key, Config } from './helper/config.js'; +import { + AddressStorage, + EMPTY_ADDRESS_MT, + ReduceStorage, + getZkAppRef, + ActionStatus, +} from '../contracts/SharedStorage.js'; +import { Contract, ZkAppEnum } from '../constants.js'; +import { + ContractList, + deploy, + proveAndSend, + fetchAllContract, +} from '../libs/utils.js'; +import { CustomScalar } from '@auxo-dev/auxo-libs'; +import { CustomScalarArray, ZkApp } from '@auxo-dev/dkg'; +import { + TreasuryContract, + ClaimFund, + TreasuryAction, + ClaimFundInput, + InvestVector, +} from '../contracts/Treasury.js'; +import { ClaimedStorage } from '../contracts/TreasuryStorage.js'; +import { ParticipationContract } from '../contracts/Participation.js'; +import { + Level1CWitness as IndexWitness, + IndexStorage, +} from '../contracts/ParticipationStorage.js'; + +describe('Funding', () => { + const doProofs = true; + const cache = Cache.FileSystem('./caches'); + + let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs }); + Mina.setActiveInstance(Local); + + let feePayerKey: Key = Local.testAccounts[0]; + let contracts: ContractList = {}; + let addressMerkleTree = EMPTY_ADDRESS_MT(); + let tx; + // contract storage + let claimedStorage = new ClaimedStorage(); + let participantIndexStorage = new IndexStorage(); + let allAddressStorage = new AddressStorage(addressMerkleTree); + + let treasuryAction: TreasuryAction[] = []; + let claimFundInput: ClaimFundInput[]; + let index: number; + let treasuryActionStates: Field[]; + let randomPrivateKey = PrivateKey.fromBase58( + 'EKE3xkv6TyhxSzBPeiiAppDfKsJVp7gXS7iuS2RNj8TGJvvhG6FM' + ); + let randomPublickey = randomPrivateKey.toPublicKey(); + // mock sumD value + let sumD = ZkApp.Request.RequestVector.from([ + randomPublickey.toGroup(), + randomPublickey.toGroup(), + randomPublickey.toGroup(), + randomPublickey.toGroup(), + ]); + + // contract request storage: + let DStorage = new MerkleMap(); + + // earn 0.01 + let investVectors = InvestVector.from([ + Field(1e7), + Field(0), + Field(1e7), + Field(0), + ]); + + let tempSumM = []; + + for (let i = 0; i < Number(investVectors.length); i++) { + let temp = Group.generator.scale( + Scalar.from(investVectors.get(Field(i)).toBigInt()) + ); + tempSumM.push(temp.add(sumD.get(Field(i)))); + } + + let sumM = ZkApp.Request.RequestVector.from(tempSumM); + + let projects: Key[] = [ + { + privateKey: Local.testAccounts[1].privateKey, + publicKey: Local.testAccounts[1].publicKey, + }, + { + privateKey: Local.testAccounts[2].privateKey, + publicKey: Local.testAccounts[2].publicKey, + }, + ]; + + beforeAll(async () => { + let configJson: Config = JSON.parse( + await fs.readFile('config.json', 'utf8') + ); + await Promise.all( + Object.keys(Contract) + .filter((item) => isNaN(Number(item))) + .map(async (e) => { + let config = configJson.deployAliases[e.toLowerCase()]; + // console.log(config); + let keyBase58: { privateKey: string; publicKey: string } = JSON.parse( + await fs.readFile(config.keyPath, 'utf8') + ); + let key = { + privateKey: PrivateKey.fromBase58(keyBase58.privateKey), + publicKey: PublicKey.fromBase58(keyBase58.publicKey), + }; + let contract = (() => { + switch (e.toLowerCase()) { + case Contract.FUNDING: + return new FundingContract(key.publicKey); + case Contract.TREASURY: + return new TreasuryContract(key.publicKey); + case Contract.PARTICIPATION: + return new ParticipationContract(key.publicKey); + case Contract.REQUEST: + return new ZkApp.Request.RequestContract(key.publicKey); + default: + return new SmartContract(key.publicKey); + } + })(); + + addressMerkleTree.setLeaf( + AddressStorage.calculateIndex(ZkAppEnum[e]).toBigInt(), + AddressStorage.calculateLeaf(key.publicKey) + ); + + contracts[e.toLowerCase()] = { + name: e.toLowerCase(), + key: key, + contract: contract, + actionStates: [Reducer.initialActionState], + }; + }) + ); + + allAddressStorage = new AddressStorage(addressMerkleTree); + }); + + // beforeEach(() => {}); + + it('compile proof', async () => { + console.log('ClaimFund.compile...'); + await ClaimFund.compile(); + if (doProofs) { + console.log('TreasuryContract.compile...'); + await TreasuryContract.compile(); + } else { + console.log('FundingContract.analyzeMethods...'); + TreasuryContract.analyzeMethods(); + } + }); + + it('Deploy and funding', async () => { + let treasuryContract = contracts[Contract.TREASURY] + .contract as TreasuryContract; + + tx = await Mina.transaction(feePayerKey.publicKey, () => { + let feePayerAccount = AccountUpdate.fundNewAccount( + feePayerKey.publicKey, + 1 + ); + treasuryContract.deploy(); + treasuryContract.zkApps.set(allAddressStorage.addresses.getRoot()); + feePayerAccount.send({ + to: contracts[Contract.TREASURY].contract, + amount: 5 * 10 ** 9, + }); + }); + await tx.prove(); + await tx + .sign([ + feePayerKey.privateKey, + contracts[Contract.TREASURY].key.privateKey, + ]) + .send(); + + console.log('Claim Fund...'); + + claimFundInput = [ + new ClaimFundInput({ + campaignId: Field(1), + projectId: Field(1), + requestId: Field(6969), + payeeAddress: projects[0].publicKey, + M: sumM, + D: sumD, + DWitness: DStorage.getWitness(Field(6969)), + investVector: investVectors, + participationIndexWitness: participantIndexStorage.getLevel1Witness( + Field(1) + ), + claimedIndex: claimedStorage.getLevel1Witness( + claimedStorage.calculateLevel1Index({ + campaignId: Field(1), + projectId: Field(1), + }) + ), + participationRef: getZkAppRef( + allAddressStorage.addresses, + ZkAppEnum.PARTICIPATION, + contracts[Contract.PARTICIPATION].contract.address + ), + }), + new ClaimFundInput({ + campaignId: Field(1), + projectId: Field(2), + requestId: Field(6969), + payeeAddress: projects[1].publicKey, + M: sumM, + D: sumD, + DWitness: DStorage.getWitness(Field(6969)), + investVector: investVectors, + participationIndexWitness: participantIndexStorage.getLevel1Witness( + Field(3) + ), + claimedIndex: claimedStorage.getLevel1Witness( + claimedStorage.calculateLevel1Index({ + campaignId: Field(1), + projectId: Field(2), + }) + ), + participationRef: getZkAppRef( + allAddressStorage.addresses, + ZkAppEnum.PARTICIPATION, + contracts[Contract.PARTICIPATION].contract.address + ), + }), + ]; + + for (let i = 0; i < projects.length; i++) { + let balanceBefore = Number(Account(projects[i].publicKey).balance.get()); + tx = await Mina.transaction(projects[i].publicKey, () => { + treasuryContract.claimFund(claimFundInput[i]); + }); + await proveAndSend(tx, [projects[i]], Contract.FUNDING, 'fund'); + let balanceAfter = Number(Account(projects[i].publicKey).balance.get()); + console.log('Balance change: ', balanceBefore - balanceAfter); + + treasuryAction.push( + new TreasuryAction({ + campaignId: claimFundInput[i].campaignId, + projectId: claimFundInput[i].projectId, + }) + ); + } + }); + + it('Reduce Treasury', async () => { + await fetchAllContract(contracts, [Contract.TREASURY]); + + let treasuryContract = contracts[Contract.TREASURY] + .contract as TreasuryContract; + let lastActionState = treasuryContract.lastRolledUpActionState.get(); + treasuryActionStates = contracts[Contract.TREASURY].actionStates; + index = treasuryActionStates.findIndex((obj) => + Boolean(obj.equals(lastActionState)) + ); + + console.log('First step: '); + let reduceFundingProof = await ClaimFund.firstStep( + treasuryContract.claimedTreeRoot.get(), + treasuryContract.lastRolledUpActionState.get() + ); + + console.log('Next step: '); + + for (let i = 0; i < projects.length; i++) { + console.log('Step', i); + reduceFundingProof = await ClaimFund.nextStep( + reduceFundingProof, + treasuryAction[i], + claimedStorage.getWitness( + claimedStorage.calculateLevel1Index({ + campaignId: treasuryAction[i].campaignId, + projectId: treasuryAction[i].projectId, + }) + ) + ); + + // update storage: + claimedStorage.updateLeaf( + claimedStorage.calculateLeaf(Bool(true)), + claimedStorage.calculateLevel1Index({ + campaignId: treasuryAction[i].campaignId, + projectId: treasuryAction[i].projectId, + }) + ); + } + + tx = await Mina.transaction(feePayerKey.publicKey, () => { + treasuryContract.rollup(reduceFundingProof); + }); + await proveAndSend(tx, [feePayerKey], Contract.TREASURY, 'rollup'); + }); +});