# GitHub - hidayatgp1/oracle: Oracle Mission **Published by:** [ใ€ŽEMTใ€๐ŸŒ˜ ๐Ÿ›ธ (๐Ÿ’™,๐Ÿงก) .L2 .hft .lens (๐Ÿ“ฆ,๐Ÿ’ซ) (๐Ÿงข,๐Ÿงข)](https://paragraph.com/@0x32123/) **Published on:** 2022-12-10 **URL:** https://paragraph.com/@0x32123/github-hidayatgp1-oracle-oracle-mission ## Content Mina zkApp: Oracle This is tutorial to build Oracle of Mina Protocol Project. Make New Project Delete few files below rm src/Add.ts rm src/Add.test.ts rm src/interact.ts Edit index.ts file in src folder import { OracleExample } from './OracleExample.js'; export { OracleExample }; Create new file in src folder with name CreditScoreOracle.ts and write import { Field, SmartContract, state, State, method, DeployArgs, Permissions, PublicKey, Signature, PrivateKey, } from 'snarkyjs'; // The public key of our trusted data provider const ORACLE_PUBLIC_KEY = 'B62qoAE4rBRuTgC42vqvEyUqCGhaZsW58SKVW4Ht8aYqP9UTvxFWBgy'; export class OracleExample extends SmartContract { // Define contract state @state(PublicKey) oraclePublicKey = State<PublicKey>(); // Define contract events events = { verified: Field, }; deploy(args: DeployArgs) { super.deploy(args); this.setPermissions({ ...Permissions.default(), editState: Permissions.proofOrSignature(), }); } @method init(zkappKey: PrivateKey) { super.init(zkappKey); // Initialize contract state this.oraclePublicKey.set(PublicKey.fromBase58(ORACLE_PUBLIC_KEY)); // Specify that caller should include signature with tx instead of proof this.requireSignature(); } @method verify(id: Field, creditScore: Field, signature: Signature) { // Get the oracle public key from the contract state const oraclePublicKey = this.oraclePublicKey.get(); this.oraclePublicKey.assertEquals(oraclePublicKey); // Evaluate whether the signature is valid for the provided data const validSignature = signature.verify(oraclePublicKey, [id, creditScore]); // Check that the signature is valid validSignature.assertTrue(); // Check that the provided credit score is greater than 700 creditScore.assertGte(Field(700)); // Emit an event containing the verified users id this.emitEvent('verified', id); } } Create new file in src folder with name OracleExampleScaffold.ts and write import { Field, SmartContract, state, State, method, DeployArgs, Permissions, PublicKey, Signature, PrivateKey, } from 'snarkyjs'; // The public key of our trusted data provider const ORACLE_PUBLIC_KEY = 'B62qoAE4rBRuTgC42vqvEyUqCGhaZsW58SKVW4Ht8aYqP9UTvxFWBgy'; export class OracleExample extends SmartContract { // Define contract state // Define contract events deploy(args: DeployArgs) { super.deploy(args); this.setPermissions({ ...Permissions.default(), editState: Permissions.proofOrSignature(), }); } @method init(zkappKey: PrivateKey) { super.init(zkappKey); // Initialize contract state // Specify that caller should include signature with tx instead of proof this.requireSignature(); } @method verify(id: Field, creditScore: Field, signature: Signature) { // Get the oracle public key from the contract state // Evaluate whether the signature is valid for the provided data // Check that the signature is valid // Check that the provided credit score is greater than 700 // Emit an event containing the verified users id } } Create new file in src folder with name OracleExample.ts and write import { Field, SmartContract, state, State, method, DeployArgs, Permissions, PublicKey, Signature, PrivateKey, } from 'snarkyjs'; // The public key of our trusted data provider const ORACLE_PUBLIC_KEY = 'B62qoAE4rBRuTgC42vqvEyUqCGhaZsW58SKVW4Ht8aYqP9UTvxFWBgy'; export class OracleExample extends SmartContract { // Define contract state @state(PublicKey) oraclePublicKey = State<PublicKey>(); // Define contract events events = { verified: Field, }; deploy(args: DeployArgs) { super.deploy(args); this.setPermissions({ ...Permissions.default(), editState: Permissions.proofOrSignature(), }); } @method init(zkappKey: PrivateKey) { super.init(zkappKey); // Initialize contract state this.oraclePublicKey.set(PublicKey.fromBase58(ORACLE_PUBLIC_KEY)); // Specify that caller should include signature with tx instead of proof this.requireSignature(); } @method verify(id: Field, creditScore: Field, signature: Signature) { // Get the oracle public key from the contract state const oraclePublicKey = this.oraclePublicKey.get(); this.oraclePublicKey.assertEquals(oraclePublicKey); // Evaluate whether the signature is valid for the provided data const validSignature = signature.verify(oraclePublicKey, [id, creditScore]); // Check that the signature is valid validSignature.assertTrue(); // Check that the provided credit score is greater than 700 creditScore.assertGte(Field(700)); // Emit an event containing the verified users id this.emitEvent('verified', id); } } Create new file in src folder with name OracleExample.test.ts and write import { OracleExample } from './OracleExample'; import { isReady, shutdown, Field, Mina, PrivateKey, PublicKey, AccountUpdate, Signature, } from 'snarkyjs'; // The public key of our trusted data provider const ORACLE_PUBLIC_KEY = 'B62qoAE4rBRuTgC42vqvEyUqCGhaZsW58SKVW4Ht8aYqP9UTvxFWBgy'; let proofsEnabled = false; function createLocalBlockchain() { const Local = Mina.LocalBlockchain({ proofsEnabled }); Mina.setActiveInstance(Local); return Local.testAccounts[0].privateKey; } async function localDeploy( zkAppInstance: OracleExample, zkAppPrivatekey: PrivateKey, deployerAccount: PrivateKey ) { const txn = await Mina.transaction(deployerAccount, () => { AccountUpdate.fundNewAccount(deployerAccount); zkAppInstance.deploy({ zkappKey: zkAppPrivatekey }); zkAppInstance.init(zkAppPrivatekey); }); await txn.prove(); txn.sign([zkAppPrivatekey]); await txn.send(); } describe('CreditScoreOracle', () => { let deployerAccount: PrivateKey, zkAppAddress: PublicKey, zkAppPrivateKey: PrivateKey; beforeAll(async () => { await isReady; if (proofsEnabled) OracleExample.compile(); }); beforeEach(async () => { deployerAccount = createLocalBlockchain(); zkAppPrivateKey = PrivateKey.random(); zkAppAddress = zkAppPrivateKey.toPublicKey(); }); afterAll(async () => { // `shutdown()` internally calls `process.exit()` which will exit the running Jest process early. // Specifying a timeout of 0 is a workaround to defer `shutdown()` until Jest is done running all tests. // This should be fixed with https://github.com/MinaProtocol/mina/issues/10943 setTimeout(shutdown, 0); }); it('generates and deploys the `CreditScoreOracle` smart contract', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const oraclePublicKey = zkAppInstance.oraclePublicKey.get(); expect(oraclePublicKey).toEqual(PublicKey.fromBase58(ORACLE_PUBLIC_KEY)); }); describe('actual API requests', () => { it('emits an `id` event containing the users id if their credit score is above 700 and the provided signature is valid', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const response = await fetch( 'https://mina-credit-score-signer-pe3eh.ondigitalocean.app/user/1' ); const data = await response.json(); const id = Field(data.data.id); const creditScore = Field(data.data.creditScore); const signature = Signature.fromJSON(data.signature); const txn = await Mina.transaction(deployerAccount, () => { zkAppInstance.verify( id, creditScore, signature ?? fail('something is wrong with the signature') ); }); await txn.prove(); await txn.send(); const events = await zkAppInstance.fetchEvents(); const verifiedEventValue = events[0].event.toFields(null)[0]; expect(verifiedEventValue).toEqual(id); }); it('throws an error if the credit score is below 700 even if the provided signature is valid', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const response = await fetch( 'https://mina-credit-score-signer-pe3eh.ondigitalocean.app/user/2' ); const data = await response.json(); const id = Field(data.data.id); const creditScore = Field(data.data.creditScore); const signature = Signature.fromJSON(data.signature); expect(async () => { await Mina.transaction(deployerAccount, () => { zkAppInstance.verify( id, creditScore, signature ?? fail('something is wrong with the signature') ); }); }).rejects; }); }); describe('hardcoded values', () => { it('emits an `id` event containing the users id if their credit score is above 700 and the provided signature is valid', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const id = Field(1); const creditScore = Field(787); const signature = Signature.fromJSON({ r: '13209474117923890467777795933147746532722569254037337512677934549675287266861', s: '12079365427851031707052269572324263778234360478121821973603368912000793139475', }); const txn = await Mina.transaction(deployerAccount, () => { zkAppInstance.verify( id, creditScore, signature ?? fail('something is wrong with the signature') ); }); await txn.prove(); await txn.send(); const events = await zkAppInstance.fetchEvents(); const verifiedEventValue = events[0].event.toFields(null)[0]; expect(verifiedEventValue).toEqual(id); }); it('throws an error if the credit score is below 700 even if the provided signature is valid', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const id = Field(2); const creditScore = Field(536); const signature = Signature.fromJSON({ r: '25163915754510418213153704426580201164374923273432613331381672085201550827220', s: '20455871399885835832436646442230538178588318835839502912889034210314761124870', }); expect(async () => { await Mina.transaction(deployerAccount, () => { zkAppInstance.verify( id, creditScore, signature ?? fail('something is wrong with the signature') ); }); }).rejects; }); it('throws an error if the credit score is above 700 and the provided signature is invalid', async () => { const zkAppInstance = new OracleExample(zkAppAddress); await localDeploy(zkAppInstance, zkAppPrivateKey, deployerAccount); const id = Field(1); const creditScore = Field(787); const signature = Signature.fromJSON({ r: '26545513748775911233424851469484096799413741017006352456100547880447752952428', s: '7381406986124079327199694038222605261248869991738054485116460354242251864564', }); expect(async () => { await Mina.transaction(deployerAccount, () => { zkAppInstance.verify( id, creditScore, signature ?? fail('something is wrong with the signature') ); }); }).rejects; }); }); }); Run Build Update Browserlist npx browserslist@latest --update-db ##Link with Repository Github Make new repository on Github and run git remote add origin *<your-repo-url>* git push -u origin main Run The Test Run The Test with Command OUTPUT You might see something like this in output, thet it means you done! image License https://github.com/hidayatgp1/oracle/blob/main/LICENSE ## Publication Information - [ใ€ŽEMTใ€๐ŸŒ˜ ๐Ÿ›ธ (๐Ÿ’™,๐Ÿงก) .L2 .hft .lens (๐Ÿ“ฆ,๐Ÿ’ซ) (๐Ÿงข,๐Ÿงข)](https://paragraph.com/@0x32123/): Publication homepage - [All Posts](https://paragraph.com/@0x32123/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0x32123): Subscribe to updates - [Twitter](https://twitter.com/hidayatgp1_sv): Follow on Twitter