From d56737f485bce752a1624b6e426fc80208f78d51 Mon Sep 17 00:00:00 2001 From: aii23 Date: Wed, 9 Oct 2024 18:34:04 +0700 Subject: [PATCH] Changed random API path --- .gitignore | 3 +++ random_request_cid | 2 +- random_request_file | 6 +++--- scripts/pbuy_ticket.ts | 41 +++++++++++++++++++++++++++++++++---- scripts/publish_request.ts | 35 ++++++++++++++++++------------- src/Random/RandomManager.ts | 10 ++++++--- src/index.ts | 6 +++++- 7 files changed, 77 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 6137df5..ee005e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ coverage # System .DS_Store +# Deploy info. Consist private keys and other sensitive data. +deployV2 + # Never commit keys to Git! keys diff --git a/random_request_cid b/random_request_cid index a0721c6..c13f9ac 100644 --- a/random_request_cid +++ b/random_request_cid @@ -1 +1 @@ -bafkreif2ett25ddjcevhnmaxmimkjdoigtsaj6bfyfil5gu65l2r6luxqm \ No newline at end of file +bafkreicnannsz4gqqk3ccfwfd3z2hfzonr63z3hgsplefgrmz37psay23y \ No newline at end of file diff --git a/random_request_file b/random_request_file index e76e99e..6f08bcd 100644 --- a/random_request_file +++ b/random_request_file @@ -1,6 +1,6 @@ { "method": "GET", - "baseURL": "https://quantum-random.com/quantum", - "path": "seed", - "zkapp": "var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n 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;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nimport { Field, MerkleMap, MerkleMapWitness, Poseidon, PublicKey, SmartContract, State, Struct, UInt32, ZkProgram, method, state, } from 'o1js';\nimport { BLOCK_PER_ROUND, ZkOnCoordinatorAddress } from '../constants.js';\nimport { convertToUInt32 } from '../util.js';\nimport { ZkonZkProgram, ZkonRequestCoordinator, ExternalRequestEvent, } from 'zkon-zkapp';\nimport { getIPFSCID } from '../../scripts/utils.js';\nconst emptyMapRoot = new MerkleMap().getRoot();\nexport let ZkonProof_ = ZkProgram.Proof(ZkonZkProgram);\nexport class ZkonProof extends ZkonProof_ {\n}\nexport class CommitValue extends Struct({\n value: Field,\n salt: Field,\n}) {\n hash() {\n return Poseidon.hash([this.value, this.salt]);\n }\n}\nconst { hashPart1, hashPart2 } = getIPFSCID();\n// Add events\nexport function getRandomManager(owner, coordinatorAddress = ZkOnCoordinatorAddress) {\n class RandomManager extends SmartContract {\n constructor() {\n super(...arguments);\n this.commitRoot = State();\n this.resultRoot = State();\n this.curRandomValue = State();\n this.startSlot = State();\n this.events = {\n requested: ExternalRequestEvent,\n };\n }\n init() {\n super.init();\n this.commitRoot.set(emptyMapRoot);\n this.resultRoot.set(emptyMapRoot);\n }\n /**\n * @notice Inital set of start slot.\n * @dev It should be equal to startBlock on PLottery. Called only once.\n *\n * @param startSlot start slot value.\n *\n */\n async setStartSlot(startSlot) {\n this.permissionCheck();\n this.startSlot.getAndRequireEquals().assertEquals(UInt32.from(0));\n this.startSlot.set(startSlot);\n }\n /**\n * @notice Commit hidden value.\n * @dev Only hash o value and salt is stored. So value is hidden.\n *\n * @param commitValue Commit value = value + slot.\n * @param commitWitness Witness of commit tree.\n *\n */\n async commit(commitValue, commitWitness) {\n this.permissionCheck();\n const [prevCommitRoot, round] = commitWitness.computeRootAndKey(Field(0));\n this.checkRoundDoNotEnd(convertToUInt32(round));\n this.commitRoot\n .getAndRequireEquals()\n .assertEquals(prevCommitRoot, 'commit: Wrong commit witness');\n const [newCommitRoot] = commitWitness.computeRootAndKey(commitValue.hash());\n this.commitRoot.set(newCommitRoot);\n }\n /**\n * @notice Reveal number commited previously.\n * @dev This function can be called only after oracle provided its random value\n *\n * @param commitValue Commit value = value + slot.\n * @param commitWitness Witness of commit tree.\n * @param resultWitness Witness of result tree.\n *\n */\n async reveal(commitValue, commitWitness, resultWitness) {\n this.permissionCheck();\n // Check VRF computed\n const curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertGreaterThan(Field(0), 'reveal: No random value in stash');\n // Check commit witness\n const [prevCommitRoot, round] = commitWitness.computeRootAndKey(commitValue.hash());\n this.commitRoot\n .getAndRequireEquals()\n .assertEquals(prevCommitRoot, 'reveal: Wrong commit witness');\n // Check result witness\n const [prevResultRoot, resultRound] = resultWitness.computeRootAndKey(Field(0));\n this.resultRoot\n .getAndRequireEquals()\n .assertEquals(prevResultRoot, 'reveal: wrong result witness');\n round.assertEquals(resultRound, 'reveal: Round for commit and result should be equal');\n // Check round is over\n this.checkRoundPass(convertToUInt32(round));\n // Compute result\n const resultValue = Poseidon.hash([commitValue.value, curRandomValue]);\n // Update result\n const [newResultRoot] = resultWitness.computeRootAndKey(resultValue);\n this.resultRoot.set(newResultRoot);\n // Consume random value\n this.curRandomValue.set(Field(0));\n }\n /**\n * @notice Sends request to ZKOn oracle.\n * @dev Request body is stored on IPFS.\n *\n */\n async callZkon() {\n let curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertEquals(Field(0), 'receiveZkonResponse: prev random value was not consumed. Call reveal first');\n const coordinator = new ZkonRequestCoordinator(coordinatorAddress);\n const requestId = await coordinator.sendRequest(this.address, hashPart1, hashPart2);\n const event = new ExternalRequestEvent({\n id: requestId,\n hash1: hashPart1,\n hash2: hashPart2,\n });\n this.emitEvent('requested', event);\n }\n /**\n * @notice Callback function for ZKOn response\n *\n */\n async receiveZkonResponse(requestId, proof) {\n let curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertEquals(Field(0), 'receiveZkonResponse: prev random value was not consumed. Call reveal first');\n const coordinator = new ZkonRequestCoordinator(coordinatorAddress);\n await coordinator.recordRequestFullfillment(requestId, proof);\n this.curRandomValue.set(proof.publicInput.dataField);\n }\n /**\n * @notice Checks that sender is the owner of the contract.\n *\n */\n permissionCheck() {\n this.sender.getAndRequireSignature().assertEquals(owner);\n }\n /**\n * @notice Checks that specified round have already passed.\n *\n * @param round Round to check\n */\n checkRoundPass(round) {\n const startBlock = this.startSlot.getAndRequireEquals();\n this.network.globalSlotSinceGenesis.requireBetween(startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)), UInt32.MAXINT());\n }\n /**\n * @notice Checks that round have not ended yet\n *\n * @param round Round to check\n */\n checkRoundDoNotEnd(round) {\n const startBlock = this.startSlot.getAndRequireEquals();\n this.network.globalSlotSinceGenesis.requireBetween(UInt32.from(0), startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)));\n }\n }\n __decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n ], RandomManager.prototype, \"commitRoot\", void 0);\n __decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n ], RandomManager.prototype, \"resultRoot\", void 0);\n __decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n ], RandomManager.prototype, \"curRandomValue\", void 0);\n __decorate([\n state(UInt32),\n __metadata(\"design:type\", Object)\n ], RandomManager.prototype, \"startSlot\", void 0);\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [UInt32]),\n __metadata(\"design:returntype\", Promise)\n ], RandomManager.prototype, \"setStartSlot\", null);\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [CommitValue,\n MerkleMapWitness]),\n __metadata(\"design:returntype\", Promise)\n ], RandomManager.prototype, \"commit\", null);\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [CommitValue,\n MerkleMapWitness,\n MerkleMapWitness]),\n __metadata(\"design:returntype\", Promise)\n ], RandomManager.prototype, \"reveal\", null);\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", []),\n __metadata(\"design:returntype\", Promise)\n ], RandomManager.prototype, \"callZkon\", null);\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [Field, ZkonProof]),\n __metadata(\"design:returntype\", Promise)\n ], RandomManager.prototype, \"receiveZkonResponse\", null);\n return RandomManager;\n}\nexport function getMockedRandomManager(owner) {\n class MockedRandomManager extends getRandomManager(owner, PublicKey.empty()) {\n async mockReceiveZkonResponse(newValue) {\n this.curRandomValue.set(newValue);\n }\n }\n __decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [Field]),\n __metadata(\"design:returntype\", Promise)\n ], MockedRandomManager.prototype, \"mockReceiveZkonResponse\", null);\n return MockedRandomManager;\n}\n//# sourceMappingURL=RandomManager.js.map" + "baseURL": "https://random-data-api.com/api/number/random_number", + "path": "number", + "zkapp": "var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n 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;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nimport { Field, MerkleMap, Poseidon, PublicKey, SmartContract, State, Struct, UInt32, ZkProgram, method, state, } from 'o1js';\nimport { BLOCK_PER_ROUND, ZkOnCoordinatorAddress } from '../constants.js';\nimport { ZkonZkProgram, ZkonRequestCoordinator, ExternalRequestEvent, } from 'zkon-zkapp';\nimport { getIPFSCID } from '../util.js';\nconst emptyMapRoot = new MerkleMap().getRoot();\nexport let ZkonProof_ = ZkProgram.Proof(ZkonZkProgram);\nexport class ZkonProof extends ZkonProof_ {\n}\nexport class CommitValue extends Struct({\n value: Field,\n salt: Field,\n}) {\n hash() {\n return Poseidon.hash([this.value, this.salt]);\n }\n}\nconst { hashPart1, hashPart2 } = getIPFSCID();\nconst coordinatorAddress = ZkOnCoordinatorAddress;\nconst owner = PublicKey.fromBase58('B62qjGsPY47SMkTykivPBAU3riS9gvMMrGr7ve6ynoHJNBzAhQmtoBn');\nexport class RandomManager extends SmartContract {\n constructor() {\n super(...arguments);\n this.startSlot = State();\n this.commit = State();\n this.result = State();\n this.curRandomValue = State();\n this.events = {\n requested: ExternalRequestEvent,\n };\n }\n // init() {\n // super.init();\n // // assert(\n // // Bool(false),\n // // 'This contract is supposed to be deployed from factory. No init call there'\n // // );\n // }\n /**\n * @notice Commit hidden value.\n * @dev Only hash o value and salt is stored. So value is hidden.\n *\n * @param commitValue Commit value = value + slot.\n *\n */\n async commitValue(commitValue) {\n this.permissionCheck();\n const currentCommit = this.commit.getAndRequireEquals();\n currentCommit.assertEquals(Field(0), 'Already committed');\n this.commit.set(commitValue.hash());\n await this.callZkon();\n }\n /*\n \n /**\n * @notice Reveal number committed previously.\n * @dev This function can be called only after oracle provided its random value\n *\n * @param commitValue Commit value = value + slot.\n *\n */\n async reveal(commitValue) {\n this.permissionCheck();\n const result = this.result.getAndRequireEquals();\n result.assertEquals(Field(0), 'reveal: Result already computed');\n // Check VRF computed\n const curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertGreaterThan(Field(0), 'reveal: No random value');\n // Check commit\n const commit = this.commit.getAndRequireEquals();\n commit.assertEquals(commitValue.hash(), 'reveal: wrong commit value');\n // Check round is over\n this.checkRoundPass();\n // Compute result\n const resultValue = Poseidon.hash([commitValue.value, curRandomValue]);\n // Update result\n this.result.set(resultValue);\n }\n /**\n * @notice Sends request to ZKOn oracle.\n * @dev Request body is stored on IPFS.\n *\n */\n async callZkon() {\n let curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertEquals(Field(0), 'random value have already been computed');\n const coordinator = new ZkonRequestCoordinator(coordinatorAddress);\n const requestId = await coordinator.sendRequest(this.address, hashPart1, hashPart2);\n const event = new ExternalRequestEvent({\n id: requestId,\n hash1: hashPart1,\n hash2: hashPart2,\n });\n this.emitEvent('requested', event);\n }\n /**\n * @notice Callback function for ZKOn response\n *\n */\n async receiveZkonResponse(requestId, proof) {\n let curRandomValue = this.curRandomValue.getAndRequireEquals();\n curRandomValue.assertEquals(Field(0), 'receiveZkonResponse: prev random value was not consumed. Call reveal first');\n const coordinator = new ZkonRequestCoordinator(coordinatorAddress);\n await coordinator.recordRequestFullfillment(requestId, proof);\n this.curRandomValue.set(proof.publicInput.dataField);\n }\n /**\n * @notice Checks that sender is the owner of the contract.\n *\n */\n permissionCheck() {\n this.sender.getAndRequireSignature().assertEquals(owner);\n }\n /**\n * @notice Checks that specified round have already passed.\n *\n * @param round Round to check\n */\n checkRoundPass() {\n const startSlot = this.startSlot.getAndRequireEquals();\n this.network.globalSlotSinceGenesis.requireBetween(startSlot.add(BLOCK_PER_ROUND), UInt32.MAXINT());\n }\n}\n__decorate([\n state(UInt32),\n __metadata(\"design:type\", Object)\n], RandomManager.prototype, \"startSlot\", void 0);\n__decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n], RandomManager.prototype, \"commit\", void 0);\n__decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n], RandomManager.prototype, \"result\", void 0);\n__decorate([\n state(Field),\n __metadata(\"design:type\", Object)\n], RandomManager.prototype, \"curRandomValue\", void 0);\n__decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [CommitValue]),\n __metadata(\"design:returntype\", Promise)\n], RandomManager.prototype, \"commitValue\", null);\n__decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [CommitValue]),\n __metadata(\"design:returntype\", Promise)\n], RandomManager.prototype, \"reveal\", null);\n__decorate([\n method,\n __metadata(\"design:type\", Function),\n __metadata(\"design:paramtypes\", [Field, ZkonProof]),\n __metadata(\"design:returntype\", Promise)\n], RandomManager.prototype, \"receiveZkonResponse\", null);\n//# sourceMappingURL=RandomManager.js.map" } \ No newline at end of file diff --git a/scripts/pbuy_ticket.ts b/scripts/pbuy_ticket.ts index 5392e25..f674c9b 100644 --- a/scripts/pbuy_ticket.ts +++ b/scripts/pbuy_ticket.ts @@ -5,6 +5,7 @@ import { Mina, NetworkId, PrivateKey, + PublicKey, UInt32, fetchAccount, } from 'o1js'; @@ -16,6 +17,7 @@ import { configDefaultInstance, getFedFactoryManager } from './utils.js'; import { PlotteryFactory } from '../src/Factory.js'; import { BLOCK_PER_ROUND } from '../src/constants.js'; import { PLottery } from '../src/PLottery.js'; +import axios from 'axios'; const { transactionFee } = configDefaultInstance(); @@ -28,13 +30,44 @@ const deployer = deployerKey.toPublicKey(); // Get factory const factoryDataPath = `./deployV2/${networkId}/${verificationKey.hash.toString()}/factory.json`; -const factoryAddress = JSON.parse( - fs.readFileSync(factoryDataPath).toString() -).address; +const factoryAddress = PublicKey.fromBase58( + JSON.parse(fs.readFileSync(factoryDataPath).toString()).address +); + +console.log(factoryAddress.toBase58()); + +await fetchAccount({ publicKey: factoryAddress }); const factory = new PlotteryFactory(factoryAddress); const startSlot = factory.startSlot.get(); -const currentSlot = Mina.currentSlot(); + +const data = await axios.post( + 'https://api.minascan.io/node/devnet/v1/graphql', + JSON.stringify({ + query: ` + query { + bestChain(maxLength:1) { + protocolState { + consensusState { + blockHeight, + slotSinceGenesis + } + } + } + } +`, + }), + { + headers: { + 'Content-Type': 'application/json', + }, + responseType: 'json', + } +); +const currentSlot = UInt32.from( + data.data.data.bestChain[0].protocolState.consensusState.slotSinceGenesis +); + const currentRound = currentSlot.sub(startSlot).div(BLOCK_PER_ROUND); const factoryManager = await getFedFactoryManager(factory); diff --git a/scripts/publish_request.ts b/scripts/publish_request.ts index 29a714f..88829ea 100644 --- a/scripts/publish_request.ts +++ b/scripts/publish_request.ts @@ -1,17 +1,17 @@ -// import dotenv from 'dotenv'; -// dotenv.config(); +import dotenv from 'dotenv'; +dotenv.config(); -// import { readFileSync, writeFileSync } from 'fs'; -// import { PinataSDK } from 'pinata'; +import { readFileSync, writeFileSync } from 'fs'; +import { PinataSDK } from 'pinata'; -// // bafkreif2ett25ddjcevhnmaxmimkjdoigtsaj6bfyfil5gu65l2r6luxqm +// bafkreif2ett25ddjcevhnmaxmimkjdoigtsaj6bfyfil5gu65l2r6luxqm -// const pinata = new PinataSDK({ -// pinataJwt: process.env.PINATA_JWT!, -// pinataGateway: process.env.PINATA_GATEWAY, -// }); +const pinata = new PinataSDK({ + pinataJwt: process.env.PINATA_JWT!, + pinataGateway: process.env.PINATA_GATEWAY, +}); -// const contractCode = readFileSync('./build/src/Random/RandomManager.js'); +const contractCode = readFileSync('./build/src/Random/RandomManager.js'); // const json = { // method: 'GET', @@ -20,9 +20,16 @@ // zkapp: contractCode.toString(), // }; -// let response = await pinata.upload.json(json); +const json = { + method: 'GET', + baseURL: 'https://random-data-api.com/api/number/random_number', + path: 'number', + zkapp: contractCode.toString(), +}; -// console.log(response.IpfsHash); -// writeFileSync('./random_request_cid', response.IpfsHash.toString()); +let response = await pinata.upload.json(json); -// writeFileSync('./random_request_file', JSON.stringify(json, null, 2)); +console.log(response.IpfsHash); +writeFileSync('./random_request_cid', response.IpfsHash.toString()); + +writeFileSync('./random_request_file', JSON.stringify(json, null, 2)); diff --git a/src/Random/RandomManager.ts b/src/Random/RandomManager.ts index 7fd5051..26d6ede 100644 --- a/src/Random/RandomManager.ts +++ b/src/Random/RandomManager.ts @@ -39,7 +39,9 @@ export class CommitValue extends Struct({ const { hashPart1, hashPart2 } = getIPFSCID(); const coordinatorAddress = ZkOnCoordinatorAddress; -const owner = PublicKey.empty(); // #TODO change with real owner address +const owner = PublicKey.fromBase58( + 'B62qjGsPY47SMkTykivPBAU3riS9gvMMrGr7ve6ynoHJNBzAhQmtoBn' +); export class RandomManager extends SmartContract { @state(UInt32) startSlot = State(); @@ -74,6 +76,8 @@ export class RandomManager extends SmartContract { currentCommit.assertEquals(Field(0), 'Already committed'); this.commit.set(commitValue.hash()); + + await this.callZkon(); } /* @@ -113,7 +117,7 @@ export class RandomManager extends SmartContract { * @dev Request body is stored on IPFS. * */ - @method async callZkon() { + public async callZkon() { let curRandomValue = this.curRandomValue.getAndRequireEquals(); curRandomValue.assertEquals( Field(0), @@ -159,7 +163,7 @@ export class RandomManager extends SmartContract { * */ public permissionCheck() { - // this.sender.getAndRequireSignature().assertEquals(owner); + this.sender.getAndRequireSignature().assertEquals(owner); } /** diff --git a/src/index.ts b/src/index.ts index cd7acac..e10784f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,14 @@ export * from './PLottery.js'; +// export * from './Factory.js'; +// export * from './Random/RandomManager.js'; export * from './Structs/Ticket.js'; +// export * from './Structs/CustomMerkleMap.js'; export * from './util.js'; export * from './Structs/CustomMerkleMap.js'; export * from './constants.js'; export * from './StateManager/PStateManager.js'; -export * from './constants'; +export * from './StateManager/RandomManagerManager.js'; +export * from './StateManager/FactoryStateManager.js'; import { DistributionProofPublicInput,