pulsar-contracts
Version:
191 lines • 9.09 kB
JavaScript
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, PulsarAuth } 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.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, } = 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.blockHeight.set(NewBlockHeight);
this.merkleListRoot.set(NewMerkleListRoot);
this.stateRoot.set(NewStateRoot);
}
async deposit(amount, pulsarAuth) {
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, pulsarAuth));
}
async withdraw(amount) {
const account = this.sender.getUnconstrained();
const withdrawalUpdate = AccountUpdate.createSigned(account);
withdrawalUpdate.send({
to: this.address,
amount: UInt64.from(WITHDRAW_DOWN_PAYMENT),
});
this.reducer.dispatch(PulsarAction.withdrawal(account, amount.value));
}
async reduce(batch, useActionStack, actionStackProof, mask, validateReduceProof) {
let merkleListRoot = this.merkleListRoot.getAndRequireEquals();
let depositListHash = this.depositListHash.getAndRequireEquals();
let withdrawalListHash = this.withdrawalListHash.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 shouldDeposit = PulsarAction.isDeposit(action)
.and(isDummy.not())
.and(mask.list[i]);
const shouldWithdraw = PulsarAction.isWithdrawal(action)
.and(isDummy.not())
.and(mask.list[i]);
depositListHash = Provable.if(shouldDeposit, Poseidon.hash([
depositListHash,
...action.account.toFields(),
action.amount,
...action.pulsarAuth.toFields(),
]), depositListHash);
withdrawalListHash = Provable.if(shouldWithdraw, Poseidon.hash([
withdrawalListHash,
...action.account.toFields(),
action.amount,
]), withdrawalListHash);
const to = Provable.if(shouldWithdraw, action.account, PublicKey.from({
x: Field(0),
isOdd: Bool(false),
}));
const amount = Provable.if(shouldWithdraw, UInt64.Unsafe.fromField(action.amount).add(WITHDRAW_DOWN_PAYMENT), UInt64.from(0));
this.send({
to,
amount,
});
}
validateReduceProof.verify();
merkleListRoot.assertEquals(validateReduceProof.publicInput.merkleListRoot);
depositListHash.assertEquals(validateReduceProof.publicInput.depositListHash);
withdrawalListHash.assertEquals(validateReduceProof.publicInput.withdrawalListHash);
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.depositListHash.set(depositListHash);
this.withdrawalListHash.set(withdrawalListHash);
}
}
__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([
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, PulsarAuth]),
__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