From 2e2e37c9c2088c99d70b382131780f912b0a3d46 Mon Sep 17 00:00:00 2001 From: Greg Santos Date: Mon, 11 Jul 2022 15:25:32 -0700 Subject: [PATCH] update: add FCLCrypto contract and deploy instructions --- README.md | 20 +++-- flow.json | 27 +++++++ flow/cadence/contracts/FCLCrypto.cdc | 108 +++++++++++++++++++++++++++ flow/config.js | 2 +- 4 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 flow.json create mode 100644 flow/cadence/contracts/FCLCrypto.cdc diff --git a/README.md b/README.md index 290c80e..f4991e4 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,32 @@ It demonstrates some of the basic features of a **Flow Dapp** using **FCL** ## Getting Started -First, run the development server: +```bash +npm install +``` + +Run the development server: ```bash npm run dev -# or -yarn dev ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. Check the console output for useful logs and transaction status. -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. +### Deploy Contracts to Emulator -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. +For local development you can deploy contracts to the Flow emulator. +Add them to `flow.json` and run: +```js +flow project deploy --network=emulator +``` + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/verify](http://localhost:3000/api/verify). + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. ## FCL Local Development diff --git a/flow.json b/flow.json new file mode 100644 index 0000000..30e36eb --- /dev/null +++ b/flow.json @@ -0,0 +1,27 @@ +{ + "emulators": { + "default": { + "port": 3569, + "serviceAccount": "emulator-account" + } + }, + "contracts": { + "FCLCrypto": "./flow/cadence/contracts/FCLCrypto.cdc" + }, + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testnet": "access.devnet.nodes.onflow.org:9000" + }, + "accounts": { + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": "28b9aa18adda109686c9d4937a58e4b3044ab57bac55679b1050ef9898bf4bba" + } + }, + "deployments": { + "emulator": { + "emulator-account": ["FCLCrypto"] + } + } +} diff --git a/flow/cadence/contracts/FCLCrypto.cdc b/flow/cadence/contracts/FCLCrypto.cdc new file mode 100644 index 0000000..ebebb20 --- /dev/null +++ b/flow/cadence/contracts/FCLCrypto.cdc @@ -0,0 +1,108 @@ +pub contract FCLCrypto { + + pub fun verifyUserSignatures( + address: Address, + message: String, + keyIndices: [Int], + signatures: [String] + ): Bool { + return self.verifySignatures( + address: address, + message: message, + keyIndices: keyIndices, + signatures: signatures, + domainSeparationTag: self.domainSeparationTagFlowUser, + ) + } + + pub fun verifyAccountProofSignatures( + address: Address, + message: String, + keyIndices: [Int], + signatures: [String] + ): Bool { + return self.verifySignatures( + address: address, + message: message, + keyIndices: keyIndices, + signatures: signatures, + domainSeparationTag: self.domainSeparationTagAccountProof, + ) || + self.verifySignatures( + address: address, + message: message, + keyIndices: keyIndices, + signatures: signatures, + domainSeparationTag: self.domainSeparationTagFlowUser, + ) + } + + priv fun verifySignatures( + address: Address, + message: String, + keyIndices: [Int], + signatures: [String], + domainSeparationTag: String, + ): Bool { + pre { + keyIndices.length == signatures.length : "Key index list length does not match signature list length" + } + + let account = getAccount(address) + let messageBytes = message.decodeHex() + + var totalWeight: UFix64 = 0.0 + let seenKeyIndices: {Int: Bool} = {} + + var i = 0 + + for keyIndex in keyIndices { + + let accountKey = account.keys.get(keyIndex: keyIndex) ?? panic("Key provided does not exist on account") + let signature = signatures[i].decodeHex() + + // Ensure this key index has not already been seen + + if seenKeyIndices[accountKey.keyIndex] ?? false { + return false + } + + // Record the key index was seen + + seenKeyIndices[accountKey.keyIndex] = true + + // Ensure the key is not revoked + + if accountKey.isRevoked { + return false + } + + // Ensure the signature is valid + + if !accountKey.publicKey.verify( + signature: signature, + signedData: messageBytes, + domainSeparationTag: domainSeparationTag, + hashAlgorithm: accountKey.hashAlgorithm + ) { + return false + } + + totalWeight = totalWeight + accountKey.weight + + i = i + 1 + } + + return totalWeight >= 1000.0 + } + + priv let domainSeparationTagFlowUser: String + priv let domainSeparationTagFCLUser: String + priv let domainSeparationTagAccountProof: String + + init() { + self.domainSeparationTagFlowUser = "FLOW-V0.0-user" + self.domainSeparationTagFCLUser = "FCL-USER-V0.0" + self.domainSeparationTagAccountProof = "FCL-ACCOUNT-PROOF-V0.0" + } +} \ No newline at end of file diff --git a/flow/config.js b/flow/config.js index a5eed9f..61d44fd 100644 --- a/flow/config.js +++ b/flow/config.js @@ -1,7 +1,7 @@ import * as fcl from "@onflow/fcl" import getConfig from "next/config" -const USE_LOCAL = false +const USE_LOCAL = true const resolver = async () => ({ appIdentifier: "Awesome App (v0.0)", nonce: "3037366134636339643564623330316636626239323161663465346131393662",