UNPKG

@nori-zk/mina-token-bridge

Version:

A Mina zk-program contract allowing users to mint tokens on Nori Bridge.

199 lines 8.61 kB
import { __decorate, __metadata } from "tslib"; import { AccountUpdate, assert, Bool, Field, method, Permissions, Poseidon, Provable, PublicKey, State, state, TokenContract, UInt64, VerificationKey, } from 'o1js'; import { NoriStorageInterface } from './NoriStorageInterface.js'; import { FungibleToken } from './TokenBase.js'; import { EthDepositProgramProofType } from './e2ePrerequisites.js'; import { ProvableEcdsaSigPresentation } from './credentialAttestation.js'; export class NoriTokenController extends TokenContract { constructor() { super(...arguments); this.adminPublicKey = State(); this.tokenBaseAddress = State(); this.ethProcessorAddress = State(); this.storageVKHash = State(); this.mintLock = State(); } async deploy(props) { await super.deploy(props); this.adminPublicKey.set(props.adminPublicKey); this.tokenBaseAddress.set(props.tokenBaseAddress); this.ethProcessorAddress.set(props.ethProcessorAddress); this.storageVKHash.set(props.storageVKHash); this.mintLock.set(Bool(true)); this.account.permissions.set({ ...Permissions.default(), setVerificationKey: Permissions.VerificationKey.impossibleDuringCurrentVersion(), setPermissions: Permissions.impossible(), editState: Permissions.proof(), send: Permissions.proof(), }); } approveBase(forest) { throw Error('block updates'); } async setUpStorage(user, vk) { let tokenAccUpdate = AccountUpdate.createSigned(user, this.deriveTokenId()); // TODO: what if someone sent token to this address before? tokenAccUpdate.account.isNew.requireEquals(Bool(true)); // could use the idea of vkMap from latest standard const storageVKHash = this.storageVKHash.getAndRequireEquals(); storageVKHash.assertEquals(vk.hash); tokenAccUpdate.body.update.verificationKey = { isSome: Bool(true), value: vk, }; tokenAccUpdate.body.update.permissions = { isSome: Bool(true), value: { ...Permissions.default(), editState: Permissions.proof(), // VK upgradability here? setVerificationKey: Permissions.VerificationKey.impossibleDuringCurrentVersion(), setPermissions: Permissions.proof(), //imposible? }, }; AccountUpdate.setValue(tokenAccUpdate.update.appState[0], //NoriStorageInterface.userKeyHash Poseidon.hash(user.toFields())); AccountUpdate.setValue(tokenAccUpdate.update.appState[1], //NoriStorageInterface.mintedSoFar Field(0)); } /** Update the verification key. */ async updateVerificationKey(vk) { await this.ensureAdminSignature(); this.account.verificationKey.set(vk); } async ensureAdminSignature() { const admin = await Provable.witnessAsync(PublicKey, async () => { let pk = await this.adminPublicKey.fetch(); assert(pk !== undefined, 'could not fetch admin public key'); return pk; }); this.adminPublicKey.requireEquals(admin); return AccountUpdate.createSigned(admin); } async noriMint(ethDepositProof, presentationProof) { const userAddress = this.sender.getUnconstrained(); //TODO make user pass signature due to limit of AU const tokenAddress = this.tokenBaseAddress.getAndRequireEquals(); let { claims, outputClaim } = presentationProof.verify({ publicKey: this.address, tokenId: this.tokenId, methodName: 'verifyPresentation', // TODO RENAME }); Provable.asProver(() => { Provable.log('ethDepositProof.publicOutput.attestationHash', 'outputClaim.messageHash', ethDepositProof.publicOutput.attestationHash, outputClaim.messageHash); }); ethDepositProof.publicOutput.attestationHash.assertEquals(outputClaim.messageHash); //TODO when add ethProcessor // assert ethDepositProof.publicOutput.storageDepositRoot; const controllerTokenId = this.deriveTokenId(); let storage = new NoriStorageInterface(userAddress, controllerTokenId); storage.account.isNew.requireEquals(Bool(false)); // that somehow allows to getState without index out of bounds storage.userKeyHash .getAndRequireEquals() .assertEquals(Poseidon.hash(userAddress.toFields()), ' userKeyHash mismatch'); // LHS e1 -> s1 -> 1 RHS s1 + mpt + da .... 1 mint // LHS e1 -> s2 -> 1(2) RHS s2 + mpr + da .... want to mint 2.... total locked 1 claim (1).... cannot claim 2 because in this run we only deposited 1 const amountToMint = await storage.increaseMintedAmount(ethDepositProof.publicOutput.totalLocked); // TODO test mint amount is sane. Provable.log(amountToMint, 'amount to mint'); // Here we have only one destination there is only m1..... let token = new FungibleToken(tokenAddress); this.mintLock.set(Bool(false)); Provable.asProver(() => { console.log('UInt64.Unsafe.fromField(amountToMint)', UInt64.Unsafe.fromField(amountToMint).toBigInt()); }); // Mint! await token.mint(userAddress, UInt64.Unsafe.fromField(amountToMint)); } async canMint(_accountUpdate) { this.mintLock.requireEquals(Bool(false)); this.mintLock.set(Bool(true)); return Bool(true); } async canChangeAdmin(_admin) { await this.ensureAdminSignature(); return Bool(true); } async canPause() { await this.ensureAdminSignature(); return Bool(true); } async canResume() { await this.ensureAdminSignature(); return Bool(true); } async canChangeVerificationKey(_vk) { await this.ensureAdminSignature(); return Bool(true); } } __decorate([ state(PublicKey), __metadata("design:type", Object) ], NoriTokenController.prototype, "adminPublicKey", void 0); __decorate([ state(PublicKey), __metadata("design:type", Object) ], NoriTokenController.prototype, "tokenBaseAddress", void 0); __decorate([ state(PublicKey), __metadata("design:type", Object) ], NoriTokenController.prototype, "ethProcessorAddress", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], NoriTokenController.prototype, "storageVKHash", void 0); __decorate([ state(Bool), __metadata("design:type", Object) ], NoriTokenController.prototype, "mintLock", void 0); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [PublicKey, VerificationKey]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "setUpStorage", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [VerificationKey]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "updateVerificationKey", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [EthDepositProgramProofType, ProvableEcdsaSigPresentation]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "noriMint", null); __decorate([ method.returns(Bool), __metadata("design:type", Function), __metadata("design:paramtypes", [AccountUpdate]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "canMint", null); __decorate([ method.returns(Bool), __metadata("design:type", Function), __metadata("design:paramtypes", [PublicKey]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "canChangeAdmin", null); __decorate([ method.returns(Bool), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "canPause", null); __decorate([ method.returns(Bool), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "canResume", null); __decorate([ method.returns(Bool), __metadata("design:type", Function), __metadata("design:paramtypes", [VerificationKey]), __metadata("design:returntype", Promise) ], NoriTokenController.prototype, "canChangeVerificationKey", null); //# sourceMappingURL=NoriTokenController.js.map