UNPKG

pulsar-contracts

Version:

209 lines 10.5 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { SmartContract, Permissions, state, State, Field, method, UInt64, AccountUpdate, Provable, Poseidon, PublicKey, Reducer, Bool, Struct, } from 'o1js'; import { SettlementProof } from './SettlementProof.js'; import { AGGREGATE_THRESHOLD, BATCH_SIZE, MINIMUM_DEPOSIT_AMOUNT, WITHDRAW_DOWN_PAYMENT, } from './utils/constants.js'; import { ValidateReduceProof } from './ValidateReduce.js'; import { Batch, PulsarAction } from './types/PulsarAction.js'; import { ReduceMask } from './types/common.js'; import { ActionStackProof } from './ActionStack.js'; import { actionListAdd, emptyActionListHash, merkleActionsAdd, } from './types/actionHelpers.js'; export { SettlementContract, SettlementEvent }; class SettlementEvent extends Struct({ fromActionState: Field, endActionState: Field, mask: Field, }) { } class SettlementContract extends SmartContract { constructor() { super(...arguments); this.actionState = State(); this.merkleListRoot = State(); this.stateRoot = State(); this.blockHeight = State(); this.depositListHash = State(); this.withdrawalListHash = State(); this.rewardListHash = State(); this.reducer = Reducer({ actionType: PulsarAction }); this.events = { Settlement: SettlementEvent, }; } async deploy() { await super.deploy(); this.account.permissions.set({ ...Permissions.default(), send: Permissions.proof(), setVerificationKey: Permissions.VerificationKey.impossibleDuringCurrentVersion(), }); } async initialize(merkleListRoot) { super.init(); this.merkleListRoot.set(merkleListRoot); this.actionState.set(Reducer.initialActionState); } async settle(settlementProof) { settlementProof.verify(); const { InitialMerkleListRoot, InitialStateRoot, InitialBlockHeight, NewBlockHeight, NewMerkleListRoot, NewStateRoot, ProofGeneratorsList, } = settlementProof.publicInput; InitialBlockHeight.assertEquals(this.blockHeight.getAndRequireEquals(), 'Initial block height mismatch with on-chain state'); InitialMerkleListRoot.assertEquals(this.merkleListRoot.getAndRequireEquals(), 'Initial MerkleList root mismatch with on-chain state'); InitialStateRoot.assertEquals(this.stateRoot.getAndRequireEquals(), 'Initial Pulsar state root mismatch with on-chain state'); NewBlockHeight.assertEquals(InitialBlockHeight.add(Field.from(AGGREGATE_THRESHOLD)), 'New block height must be equal to initial block height + AGGREGATE_THRESHOLD'); this.reducer.dispatch(PulsarAction.settlement(InitialStateRoot, NewStateRoot, InitialMerkleListRoot, NewMerkleListRoot, InitialBlockHeight, NewBlockHeight, ProofGeneratorsList)); } async deposit(amount) { amount.assertGreaterThanOrEqual(UInt64.from(MINIMUM_DEPOSIT_AMOUNT), `At least ${Number(MINIMUM_DEPOSIT_AMOUNT / 1e9)} MINA is required`); const sender = this.sender.getUnconstrained(); const depositAccountUpdate = AccountUpdate.createSigned(sender); depositAccountUpdate.send({ to: this.address, amount }); this.reducer.dispatch(PulsarAction.deposit(sender, amount.value)); } async withdraw(amount) { const account = this.sender.getUnconstrained(); const withdrawalUpdate = AccountUpdate.createSigned(account); withdrawalUpdate.send({ to: this.address, amount: amount.add(UInt64.from(WITHDRAW_DOWN_PAYMENT)), }); this.reducer.dispatch(PulsarAction.withdrawal(account, amount.value)); } async reduce(batch, useActionStack, actionStackProof, mask, validateReduceProof) { let stateRoot = this.stateRoot.getAndRequireEquals(); let merkleListRoot = this.merkleListRoot.getAndRequireEquals(); let blockHeight = this.blockHeight.getAndRequireEquals(); let depositListHash = this.depositListHash.getAndRequireEquals(); let withdrawalListHash = this.withdrawalListHash.getAndRequireEquals(); let rewardListHash = this.rewardListHash.getAndRequireEquals(); let initialActionState = this.actionState.getAndRequireEquals(); let actionState = initialActionState; for (let i = 0; i < BATCH_SIZE; i++) { const action = batch.actions[i]; const isDummy = PulsarAction.isDummy(action); actionState = Provable.if(isDummy, actionState, merkleActionsAdd(actionState, actionListAdd(emptyActionListHash, action))); const shouldSettle = PulsarAction.isSettlement(action) .and(action.initialState.equals(stateRoot)) .and(action.initialMerkleListRoot.equals(merkleListRoot)) .and(action.initialBlockHeight.equals(blockHeight)) .and(isDummy.not()) .and(mask.list[i]); const shouldDeposit = PulsarAction.isDeposit(action) .and(isDummy.not()) .and(mask.list[i]); const shouldWithdraw = PulsarAction.isWithdrawal(action) .and(isDummy.not()) .and(mask.list[i]); stateRoot = Provable.if(shouldSettle, action.newState, stateRoot); merkleListRoot = Provable.if(shouldSettle, action.newMerkleListRoot, merkleListRoot); blockHeight = Provable.if(shouldSettle, action.newBlockHeight, blockHeight); depositListHash = Provable.if(shouldDeposit, Poseidon.hash([ depositListHash, ...action.account.toFields(), action.amount, ]), depositListHash); withdrawalListHash = Provable.if(shouldWithdraw, Poseidon.hash([ withdrawalListHash, ...action.account.toFields(), action.amount, ]), withdrawalListHash); const recipient = Provable.if(shouldWithdraw, action.account, PublicKey.empty()); this.send({ to: AccountUpdate.create(recipient), amount: Provable.if(shouldWithdraw, UInt64.Unsafe.fromField(action.amount).add(WITHDRAW_DOWN_PAYMENT), UInt64.from(0)), }); rewardListHash = Provable.if(shouldSettle, Poseidon.hash([rewardListHash, action.rewardListUpdateHash]), rewardListHash); } validateReduceProof.verify(); stateRoot.assertEquals(validateReduceProof.publicInput.stateRoot); merkleListRoot.assertEquals(validateReduceProof.publicInput.merkleListRoot); blockHeight.assertEquals(validateReduceProof.publicInput.blockHeight); depositListHash.assertEquals(validateReduceProof.publicInput.depositListHash); withdrawalListHash.assertEquals(validateReduceProof.publicInput.withdrawalListHash); rewardListHash.assertEquals(validateReduceProof.publicInput.rewardListHash); actionStackProof.verifyIf(useActionStack); Provable.assertEqualIf(useActionStack, Field, actionStackProof.publicInput, actionState); this.account.actionState.requireEquals(Provable.if(useActionStack, actionStackProof.publicOutput, actionState)); this.emitEvent('Settlement', new SettlementEvent({ fromActionState: initialActionState, endActionState: actionState, mask: mask.toField(), })); this.actionState.set(actionState); this.stateRoot.set(stateRoot); this.merkleListRoot.set(merkleListRoot); this.blockHeight.set(blockHeight); this.depositListHash.set(depositListHash); this.withdrawalListHash.set(withdrawalListHash); this.rewardListHash.set(rewardListHash); } } __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "actionState", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "merkleListRoot", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "stateRoot", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "blockHeight", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "depositListHash", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "withdrawalListHash", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], SettlementContract.prototype, "rewardListHash", void 0); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [Field]), __metadata("design:returntype", Promise) ], SettlementContract.prototype, "initialize", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [SettlementProof]), __metadata("design:returntype", Promise) ], SettlementContract.prototype, "settle", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [UInt64]), __metadata("design:returntype", Promise) ], SettlementContract.prototype, "deposit", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [UInt64]), __metadata("design:returntype", Promise) ], SettlementContract.prototype, "withdraw", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [Batch, Bool, ActionStackProof, ReduceMask, ValidateReduceProof]), __metadata("design:returntype", Promise) ], SettlementContract.prototype, "reduce", null); //# sourceMappingURL=SettlementContract.js.map