From 14af84d71cdf076c7f684d056c043a008ab8faf5 Mon Sep 17 00:00:00 2001 From: huyminh1115 Date: Sat, 3 Feb 2024 01:43:19 +0700 Subject: [PATCH] Update contract Funding --- src/contracts/Funding.ts | 48 ++++++++++++++++++++++----------- src/contracts/FundingStorage.ts | 20 ++++++++++++++ src/contracts/SharedStorage.ts | 1 - src/scripts/Funding.test.ts | 33 ++++++++++++++++------- src/scripts/Platform.ts | 48 +++++++++++++++++++++++---------- 5 files changed, 111 insertions(+), 39 deletions(-) diff --git a/src/contracts/Funding.ts b/src/contracts/Funding.ts index e3d073c..8a5495e 100644 --- a/src/contracts/Funding.ts +++ b/src/contracts/Funding.ts @@ -37,6 +37,7 @@ import { EMPTY_LEVEL_1_TREE, ValueStorage, RequestIdStorage, + TotalFundStorage, } from './FundingStorage.js'; const DefaultLevel1Root = EMPTY_LEVEL_1_TREE().getRoot(); @@ -53,6 +54,7 @@ export class RequestSent extends Struct({ requestId: Field, sumR: DKG_Contracts.Request.RequestVector, sumM: DKG_Contracts.Request.RequestVector, + totalFundAmount: Field, }) { static fromFields(action: Field[]): RequestSent { return super.fromFields(action) as RequestSent; @@ -77,6 +79,7 @@ export class FundingAction extends Struct({ campaignId: Field, R: DKG_Contracts.Request.RequestVector, M: DKG_Contracts.Request.RequestVector, + fundAmount: Field, }) { hash(): Field { return Poseidon.hash(FundingAction.toFields(this)); @@ -171,9 +174,8 @@ export class RollupActionsOutput extends Struct({ campaignId: Field, sum_R: DKG_Contracts.Request.RequestVector, sum_M: DKG_Contracts.Request.RequestVector, - // TODO: make that we can increase number of investor + totalFundAmount: Field, initialStatusRoot: Field, - finalStatusRoot: Field, }) { hash(): Field { return Poseidon.hash(RollupActionsOutput.toFields(this)); @@ -211,12 +213,7 @@ export const CreateRollupProof = ZkProgram({ Field(ActionStatus.REDUCED) ); key.assertEquals(actionState); - root.assertEquals(preProof.publicOutput.finalStatusRoot); - - // Update satus to ROLL_UPED - let [newRoot] = rollupStatusWitness.computeRootAndKey( - Field(ActionStatus.ROLL_UPED) - ); + root.assertEquals(preProof.publicOutput.initialStatusRoot); let sum_R = preProof.publicOutput.sum_R; let sum_M = preProof.publicOutput.sum_M; @@ -232,12 +229,16 @@ export const CreateRollupProof = ZkProgram({ ); } + let newTotalFund = preProof.publicOutput.totalFundAmount.add( + action.fundAmount + ); + return new RollupActionsOutput({ campaignId: campaignId, sum_R, sum_M, + totalFundAmount: newTotalFund, initialStatusRoot: preProof.publicOutput.initialStatusRoot, - finalStatusRoot: newRoot, }); }, }, @@ -258,8 +259,8 @@ export const CreateRollupProof = ZkProgram({ sum_M: DKG_Contracts.Request.RequestVector.empty( maxInvestorSize ), + totalFundAmount: Field(0), initialStatusRoot, - finalStatusRoot: initialStatusRoot, }); }, }, @@ -273,6 +274,7 @@ export class FundingContract extends SmartContract { @state(Field) actionStatus = State(); @state(Field) R_root = State(); // campaignId -> sum R @state(Field) M_root = State(); // campaignId -> sum M + @state(Field) totalFundAmount_root = State(); // campaignId -> total fubnd amount @state(Field) requestId_root = State(); // campaignId -> requestId @state(Field) zkApps = State(); @@ -288,6 +290,7 @@ export class FundingContract extends SmartContract { this.actionStatus.set(EMPTY_REDUCE_MT().getRoot()); this.R_root.set(DefaultLevel1Root); this.M_root.set(DefaultLevel1Root); + this.totalFundAmount_root.set(DefaultLevel1Root); this.requestId_root.set(DefaultLevel1Root); } @@ -387,6 +390,7 @@ export class FundingContract extends SmartContract { campaignId: fundingInput.campaignId, R, M, + fundAmount: totalMinaInvest, }) ); @@ -416,14 +420,16 @@ export class FundingContract extends SmartContract { this.emitEvent(EventEnum.ACTIONS_REDUCED, lastActionState); } - // TODO: adding N, T to check REQUEST_MAX_SIZE by interact with Committee contract - // TODO: checking Campaign contract config -> committeeId and keyId + // TODO: add time condition to check rollup + // TODO: adding N, T to check REQUEST_MAX_SIZE by interact with Committee contract (???) + // TODO: checking Campaign contract config -> committeeId and keyId is valid @method rollupRequest( proof: ProofRollupAction, committeeId: Field, keyId: Field, R_witness: Level1Witness, M_witness: Level1Witness, + totalFundAmount_witness: Level1Witness, requestId_witness: Level1Witness, requestZkAppRef: ZkAppRef ) { @@ -440,26 +446,34 @@ export class FundingContract extends SmartContract { let R_root = this.R_root.getAndRequireEquals(); let M_root = this.M_root.getAndRequireEquals(); let requestId_root = this.requestId_root.getAndRequireEquals(); + let totalFundAmount_root = + this.totalFundAmount_root.getAndRequireEquals(); let actionStatus = this.actionStatus.getAndRequireEquals(); actionStatus.assertEquals(proof.publicOutput.initialStatusRoot); + let R_key = R_witness.calculateIndex(); let old_R_root = R_witness.calculateRoot(Field(0)); let M_key = M_witness.calculateIndex(); let old_M_root = M_witness.calculateRoot(Field(0)); let requestId_key = requestId_witness.calculateIndex(); let old_requestId_root = requestId_witness.calculateRoot(Field(0)); + let totalFundAmount_key = totalFundAmount_witness.calculateIndex(); + let old_totalFundAmount_root = totalFundAmount_witness.calculateRoot( + Field(0) + ); R_key.assertEquals(proof.publicOutput.campaignId); M_key.assertEquals(proof.publicOutput.campaignId); requestId_key.assertEquals(proof.publicOutput.campaignId); + totalFundAmount_key.assertEquals(proof.publicOutput.campaignId); R_root.assertEquals(old_R_root); M_root.assertEquals(old_M_root); requestId_root.assertEquals(old_requestId_root); + totalFundAmount_root.assertEquals(old_totalFundAmount_root); // TODO: check number of investor - // maybe add time in the future let new_R_root = R_witness.calculateRoot( ValueStorage.calculateLeaf(proof.publicOutput.sum_R) ); @@ -469,14 +483,17 @@ export class FundingContract extends SmartContract { let new_requestId_root = requestId_witness.calculateRoot( RequestIdStorage.calculateLeaf(requestId) ); + let new_totalFundAmount_root = totalFundAmount_witness.calculateRoot( + TotalFundStorage.calculateLeaf(proof.publicOutput.totalFundAmount) + ); // update on-chain state this.R_root.set(new_R_root); this.M_root.set(new_M_root); this.requestId_root.set(new_requestId_root); - this.actionStatus.set(proof.publicOutput.finalStatusRoot); + this.totalFundAmount_root.set(new_totalFundAmount_root); - // TODO: request to Request contract + // Request to Request contract // Verify zkApp references let zkApps = this.zkApps.getAndRequireEquals(); @@ -506,6 +523,7 @@ export class FundingContract extends SmartContract { requestId, sumR: proof.publicOutput.sum_R, sumM: proof.publicOutput.sum_M, + totalFundAmount: proof.publicOutput.totalFundAmount, }) ); } diff --git a/src/contracts/FundingStorage.ts b/src/contracts/FundingStorage.ts index eb9cb40..0f69f89 100644 --- a/src/contracts/FundingStorage.ts +++ b/src/contracts/FundingStorage.ts @@ -124,3 +124,23 @@ export class RequestIdStorage extends FundingStorage { return RequestIdStorage.calculateLevel1Index(campaignId); } } + +export type TotalFundLeaf = Field; + +export class TotalFundStorage extends FundingStorage { + static calculateLeaf(totalFundAmount: TotalFundLeaf): Field { + return totalFundAmount; + } + + calculateLeaf(totalFundAmount: TotalFundLeaf): Field { + return TotalFundStorage.calculateLeaf(totalFundAmount); + } + + static calculateLevel1Index(campaignId: Field): Field { + return campaignId; + } + + calculateLevel1Index(campaignId: Field): Field { + return TotalFundStorage.calculateLevel1Index(campaignId); + } +} diff --git a/src/contracts/SharedStorage.ts b/src/contracts/SharedStorage.ts index a960502..617a3db 100644 --- a/src/contracts/SharedStorage.ts +++ b/src/contracts/SharedStorage.ts @@ -122,7 +122,6 @@ export function getZkAppRef( export const enum ActionStatus { NOT_EXISTED, REDUCED, - ROLL_UPED, } export class ReduceStorage { diff --git a/src/scripts/Funding.test.ts b/src/scripts/Funding.test.ts index a488aad..3f576e9 100644 --- a/src/scripts/Funding.test.ts +++ b/src/scripts/Funding.test.ts @@ -28,7 +28,11 @@ import { FundingInput, FundingAction, } from '../contracts/Funding.js'; -import { RequestIdStorage, ValueStorage } from '../contracts/FundingStorage.js'; +import { + RequestIdStorage, + TotalFundStorage, + ValueStorage, +} from '../contracts/FundingStorage.js'; import { Key, Config } from './helper/config.js'; import { AddressStorage, @@ -64,6 +68,7 @@ describe('Funding', () => { let sumRStorage = new ValueStorage(); let sumMStorage = new ValueStorage(); let requestIdStorage = new RequestIdStorage(); + let totalFundStorage = new TotalFundStorage(); let fundingAddressStorage = new AddressStorage(); let fundingAction: FundingAction[] = []; let fundingInput: FundingInput[]; @@ -233,11 +238,24 @@ describe('Funding', () => { let { R, M } = result!; + let dimension = fundingInput[i].secretVector.length; + let totalMinaInvest = Provable.witness(Field, () => { + let curSum = 0n; + for (let j = 0; j < dimension.toBigInt(); j++) { + curSum += fundingInput[i].secretVector + .get(Field(j)) + .toScalar() + .toBigInt(); + } + return Field(curSum); + }); + fundingAction.push( new FundingAction({ campaignId: fundingInput[i].campaignId, R, M, + fundAmount: totalMinaInvest, }) ); } @@ -315,14 +333,6 @@ describe('Funding', () => { fundingActionStates[index + 1 + i] ) ); - - // update storage: - fundingReduceStorage.updateLeaf( - fundingReduceStorage.calculateIndex( - fundingActionStates[index + 1 + i] - ), - fundingReduceStorage.calculateLeaf(ActionStatus.ROLL_UPED) - ); } tx = await Mina.transaction(feePayerKey.publicKey, () => { @@ -345,6 +355,11 @@ describe('Funding', () => { fundingAction[0].campaignId ) ), + totalFundStorage.getLevel1Witness( + requestIdStorage.calculateLevel1Index( + fundingAction[0].campaignId + ) + ), fundingAddressStorage.getZkAppRef( ZkAppEnum.REQUEST, contracts[Contract.REQUEST].contract.address diff --git a/src/scripts/Platform.ts b/src/scripts/Platform.ts index 163e4c2..5004af8 100644 --- a/src/scripts/Platform.ts +++ b/src/scripts/Platform.ts @@ -65,7 +65,11 @@ import { FundingAction, FundingInput, } from '../contracts/Funding.js'; -import { RequestIdStorage, ValueStorage } from '../contracts/FundingStorage.js'; +import { + RequestIdStorage, + ValueStorage, + TotalFundStorage, +} from '../contracts/FundingStorage.js'; import { ParticipationContract, JoinCampaign, @@ -181,6 +185,7 @@ async function main() { let fundingReduceStorage = new ReduceStorage(); let sumRStorage = new ValueStorage(); let sumMStorage = new ValueStorage(); + let totalFundStorage = new TotalFundStorage(); let requestIdStorage = new RequestIdStorage(); let fundingAddressStorage = new AddressStorage(); let fundingAction: FundingAction[] = []; @@ -857,11 +862,24 @@ async function main() { let { R, M } = result!; + let dimension = fundingInput[i].secretVector.length; + let totalMinaInvest = Provable.witness(Field, () => { + let curSum = 0n; + for (let j = 0; j < dimension.toBigInt(); j++) { + curSum += fundingInput[i].secretVector + .get(Field(j)) + .toScalar() + .toBigInt(); + } + return Field(curSum); + }); + fundingAction.push( new FundingAction({ campaignId: fundingInput[i].campaignId, R, M, + fundAmount: totalMinaInvest, }) ); } @@ -930,14 +948,6 @@ async function main() { fundingActionStates[index + 1 + i] ) ); - - // update storage: - fundingReduceStorage.updateLeaf( - fundingReduceStorage.calculateIndex( - fundingActionStates[index + 1 + i] - ), - fundingReduceStorage.calculateLeaf(ActionStatus.ROLL_UPED) - ); } tx = await Mina.transaction( @@ -962,6 +972,11 @@ async function main() { fundingAction[0].campaignId ) ), + totalFundStorage.getLevel1Witness( + requestIdStorage.calculateLevel1Index( + fundingAction[0].campaignId + ) + ), fundingAddressStorage.getZkAppRef( ZkAppEnum.REQUEST, contracts[Contract.REQUEST].contract.address @@ -1090,12 +1105,17 @@ async function main() { Account(projects[i].publicKey).balance.get() ); tx = await Mina.transaction( - { sender: projects[i].publicKey, fee }, - () => { - treasuryContract.claimFund(claimFundInput[i]); - } + { sender: projects[i].publicKey, fee }, + () => { + treasuryContract.claimFund(claimFundInput[i]); + } + ); + await proveAndSend( + tx, + [projects[i]], + Contract.TREASURY, + 'claimFund' ); - await proveAndSend(tx, [projects[i]], Contract.TREASURY, 'claimFund'); let balanceAfter = Number( Account(projects[i].publicKey).balance.get() );