From ae25421eb7c1861f68060149b00d491a7a4933f6 Mon Sep 17 00:00:00 2001 From: thomas-waite Date: Fri, 20 Mar 2020 19:15:17 +0000 Subject: [PATCH 01/19] build(documentation): add images folder into public build, update import --- packages/documentation/package.json | 5 +++-- .../styleguide/categories/Introduction/joinSplitProof.md | 2 +- .../styleguide/categories/Introduction/standardFlow.md | 2 +- .../styleguide/categories/Introduction/utxoModel.md | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 29ee3582a..1f30cee97 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -7,9 +7,10 @@ }, "description": "AZTEC Protocol documentation based on React Styleguidist", "scripts": { - "build": "truffle compile --all && styleguidist build && yarn copy", + "build": "truffle compile --all && styleguidist build && yarn copyApis && yarn copyImages", "clean": "shx rm -rf ./build ./dist ./public || true", - "copy": "find ../extension/src/client/apis -iregex '.(ZkNote|Account|ZkAsset).' -exec cp {} ./public/apis \\;", + "copyApis": "find ../extension/src/client/apis -iregex '.(ZkNote|Account|ZkAsset).' -exec cp {} ./public/apis \\;", + "copyImages": "cp -r ./images ./public", "generateStyles": "guacamole generateStyles", "lint": "eslint --ignore-path .eslintignore .", "start": "yarn styleguide", diff --git a/packages/documentation/styleguide/categories/Introduction/joinSplitProof.md b/packages/documentation/styleguide/categories/Introduction/joinSplitProof.md index 803888c6f..dca296949 100644 --- a/packages/documentation/styleguide/categories/Introduction/joinSplitProof.md +++ b/packages/documentation/styleguide/categories/Introduction/joinSplitProof.md @@ -7,7 +7,7 @@ In a `JoinSplit` proof particular notes are provided as inputs, and certain note Consider the below example as to how value can be transferred using a JoinSplit proof:   - +   Alice wishes to confidentially transfer Bob 75 zkDAI. She starts off with 2 notes whose value sum to 100 zkDAI, whilst Bob starts off with no notes and no zkDAI. diff --git a/packages/documentation/styleguide/categories/Introduction/standardFlow.md b/packages/documentation/styleguide/categories/Introduction/standardFlow.md index e294689bd..a760017c4 100644 --- a/packages/documentation/styleguide/categories/Introduction/standardFlow.md +++ b/packages/documentation/styleguide/categories/Introduction/standardFlow.md @@ -32,4 +32,4 @@ The below diagram gives an overview of how the key smart contract infrastructure     - + diff --git a/packages/documentation/styleguide/categories/Introduction/utxoModel.md b/packages/documentation/styleguide/categories/Introduction/utxoModel.md index 30972588e..5d0f9fc6d 100644 --- a/packages/documentation/styleguide/categories/Introduction/utxoModel.md +++ b/packages/documentation/styleguide/categories/Introduction/utxoModel.md @@ -3,4 +3,4 @@ AZTEC utilises a UTXO model like that of Bitcoin, where the UTXOs are called `no     - + From 41cae6865e38f2f2906f77f872cf6baf3eeb39e8 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 23 Mar 2020 12:13:05 +0000 Subject: [PATCH 02/19] fix(documentation): fix command for coping apis from sdk to docs --- packages/documentation/package.json | 3 +- packages/documentation/src/apis/Account.js | 131 ++++ packages/documentation/src/apis/ZkAsset.js | 678 +++++++++++++++++++++ packages/documentation/src/apis/ZkNote.js | 284 +++++++++ 4 files changed, 1095 insertions(+), 1 deletion(-) create mode 100644 packages/documentation/src/apis/Account.js create mode 100644 packages/documentation/src/apis/ZkAsset.js create mode 100644 packages/documentation/src/apis/ZkNote.js diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 29ee3582a..93deb361e 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -9,7 +9,8 @@ "scripts": { "build": "truffle compile --all && styleguidist build && yarn copy", "clean": "shx rm -rf ./build ./dist ./public || true", - "copy": "find ../extension/src/client/apis -iregex '.(ZkNote|Account|ZkAsset).' -exec cp {} ./public/apis \\;", + "copy": "cp -r src/apis public/apis", + "copy:local": "find -E ../extension/src/client/apis -regex '.*(Zk|Account).*' -exec cp {} ./src/apis \\;", "generateStyles": "guacamole generateStyles", "lint": "eslint --ignore-path .eslintignore .", "start": "yarn styleguide", diff --git a/packages/documentation/src/apis/Account.js b/packages/documentation/src/apis/Account.js new file mode 100644 index 000000000..b3b28e08f --- /dev/null +++ b/packages/documentation/src/apis/Account.js @@ -0,0 +1,131 @@ +import { + note as noteUtils, +} from 'aztec.js'; +import uniq from 'lodash/uniq'; +import Web3Service from '~/client/services/Web3Service'; +import ConnectionService from '~/client/services/ConnectionService'; +import ApiError from '~/client/utils/ApiError'; + +const dataProperties = [ + 'address', + 'linkedPublicKey', + 'spendingPublicKey', +]; + +class Account { + constructor(account) { + dataProperties.forEach((key) => { + this[key] = account[key] || ''; + }); + this.id = account.address; + } + + get registered() { + return !!this.linkedPublicKey; + } + + /** + * + * @function user.createNote + * @description Description: Create an AZTEC note owned by the user. + * + * @param {Integer} value Value of the note. + * + * @param {[Address]} userAccess Optional array of address that will be granted view access to the note value. + * + * @returns {AztecNote} note An AZTEC note owned by the user. + * + */ + async createNote(value, userAccess = []) { + if (!this.registered) { + throw new ApiError('user.unregistered', { + fn: 'createNote', + }); + } + + let noteAccess = []; + if (userAccess && userAccess.length) { + ({ + accounts: noteAccess, + } = await ConnectionService.query( + 'users', + { + where: { + address_in: uniq(userAccess), + }, + }, + ` + address + linkedPublicKey + `, + ) || {}); + } + + return noteUtils.create( + this.spendingPublicKey, + value, + noteAccess, + this.address, + ); + } + + /** + * + * @function user.encryptMessage + * @description Description: Encrypt a message using the user's public key. + * + * @param {String} message Message to be encrypted. + * + * @returns {HexString} encrypted An encrypted message. + * + */ + async encryptMessage(message) { + if (!this.registered) { + throw new ApiError('user.unregistered', { + fn: 'encryptMessage', + }); + } + + const { encrypted } = await ConnectionService.query( + 'encryptMessage', + { + address: this.address, + linkedPublicKey: this.linkedPublicKey, + message, + }, + ) || {}; + + return encrypted; + } + + /** + * + * @function user.decryptMessage + * @description Description: Decrypt a message using the user's private key. + * This method is available only for current user. + * + * @param {HexString} encrypted An encrypted message. + * + * @returns {String} message The decrypted message. + * + */ + async decryptMessage(message) { + if (this.address !== Web3Service.account.address) { + throw new ApiError('user.logout', { + fn: 'decryptMessage', + }); + } + + const { decrypted } = await ConnectionService.query( + 'decryptMessage', + { + address: this.address, + message, + }, + ) || {}; + + return decrypted; + } +} + +export default Account; diff --git a/packages/documentation/src/apis/ZkAsset.js b/packages/documentation/src/apis/ZkAsset.js new file mode 100644 index 000000000..1293cfa29 --- /dev/null +++ b/packages/documentation/src/apis/ZkAsset.js @@ -0,0 +1,678 @@ +import BN from 'bn.js'; +import { + tokenToNoteValue, + noteToTokenValue, + recoverJoinSplitProof, +} from '~/utils/transformData'; +import Web3Service from '~/client/services/Web3Service'; +import ConnectionService from '~/client/services/ConnectionService'; +import ContractError from '~/client/utils/ContractError'; +import ApiError from '~/client/utils/ApiError'; +import parseInputTransactions from '~/client/utils/parseInputTransactions'; +import parseInputInteger from '~/client/utils/parseInputInteger'; +import SubscriptionManager from './SubscriptionManager'; + +const dataProperties = [ + 'address', + 'linkedTokenAddress', + 'scalingFactor', + 'canAdjustSupply', + 'canConvert', + 'token', +]; + +export default class ZkAsset { + constructor({ + id, + ...asset + } = {}) { + dataProperties.forEach((key) => { + this[key] = asset[key]; + }); + this.id = id; + this.subscriptions = new SubscriptionManager(); + } + + get valid() { + return !!this.address; + } + + isValid() { + return !!this.address; + } + + /** + * + * @function zkAsset.balance + * @description Description: Get the balance of a ZkAsset. + * + * @returns {Integer} balance Balance of the ZkAsset. + * + */ + async balance() { + const { balance } = await ConnectionService.query( + 'assetBalance', + { id: this.id }, + ) || {}; + + return balance || 0; + } + + /** + * + * @function zkAsset.totalSupplyOfLinkedToken + * @description Description: Get the total supply of the ERC20 token linked to the ZkAsset + * + * @returns {BigNumber} totalSupply Token number of ERC20 tokens + * + */ + async totalSupplyOfLinkedToken() { + if (!this.linkedTokenAddress) { + throw new ApiError('zkAsset.private', { + fn: 'totalSupplyOfLinkedToken', + }); + } + + let totalSupply = 0; + try { + totalSupply = await Web3Service + .useContract('ERC20') + .at(this.linkedTokenAddress) + .method('totalSupply') + .call(); + } catch (error) { + throw new ContractError('erc20.totalSupply'); + } + + return new BN(totalSupply); + } + + /** + * @function zkAsset.balanceOfLinkedToken + * @description Description: Get the linked ERC20 token balance for an address. + * + * @param {String} account Optional Ethereum address for which the balance of the linked ERC20 token is being fetched. + * Will use the current user's address if not defined. + * + * @returns {BigNumber} balance Number of linked ERC20 tokens held by the `account`. + * + */ + balanceOfLinkedToken = async (account) => { + if (!this.linkedTokenAddress) { + throw new ApiError('zkAsset.private', { + fn: 'balanceOfLinkedToken', + }); + } + + let balance = 0; + let accountAddress = account; + if (!accountAddress) { + ({ + address: accountAddress, + } = Web3Service.account); + } + + try { + balance = await Web3Service + .useContract('ERC20') + .at(this.linkedTokenAddress) + .method('balanceOf') + .call(accountAddress); + } catch (error) { + throw new ContractError('erc20.balanceOf', { + messageOptions: { + account: accountAddress, + }, + }); + } + + return new BN(balance); + }; + + /** + * + * @function zkAsset.allowanceOfLinkedToken + * @description Description: Get the number of linked ERC20 tokens a spender is allowed to spend on behalf of an owner. + * + * @param {String} owner Optional Ethereum address which owns linked ERC20 tokens. + * Will use the current user's address if not defined. + * + * @param {String} spender Optional Ethereum address that is expected to have previously been approved to spend ERC20 tokens on behalf of the owner. + * Will use the address of `ACE` contract if not defined. + * + * @returns {BigNumber} allowance Number of linked ERC20 tokens the spender has been approved to spend on the owner's behalf. + * + */ + allowanceOfLinkedToken = async (owner = '', spender = '') => { + if (!this.linkedTokenAddress) { + throw new ApiError('zkAsset.private', { + fn: 'allowanceOfLinkedToken', + }); + } + + let allowance = 0; + let ownerAddress = owner; + if (!ownerAddress) { + ({ + address: ownerAddress, + } = Web3Service.account); + } + + let spenderAddress = spender; + if (!spenderAddress) { + spenderAddress = Web3Service.getAddress('ACE'); + } + + try { + allowance = await Web3Service + .useContract('ERC20') + .at(this.linkedTokenAddress) + .method('allowance') + .call( + ownerAddress, + spenderAddress, + ); + } catch (error) { + throw new ContractError('erc20.allowance', { + owner: ownerAddress, + spender: spenderAddress, + }); + } + + return new BN(allowance); + }; + + /** + * + * @function zkAsset.subscribeToBalance + * @description Description: Get notified whenever the balance of an asset is changed. + * + * @param {Function} callback A listener, which will receive the new value whenever the balance is changed: + * + * - callback(*balance*): Where balance is an Integer. + * + */ + subscribeToBalance = async (subscriber) => { + if (!this.isValid()) { + return false; + } + + return this.subscriptions.add( + 'ASSET_BALANCE', + this.id, + subscriber, + ); + }; + + unsubscribeToBalance = async subscriber => this.subscriptions.remove( + 'ASSET_BALANCE', + this.id, + subscriber, + ); + + /** + * @function zkAsset.deposit + * @description Description: Deposit funds into zero-knowledge form - convert public ERC20 tokens into zero-knowledge AZTEC notes. + * + * @param {[Transaction]} transactions Transaction information which the user wants to have enacted. Each transaction object consists of: + * + * - *amount* (Integer): Number of public ERC20 tokens being converted into notes. + * + * - *to* (Address): Ethereum address to which the user is 'depositing' the zero-knowledge funds. + * The address will become the owner of the notes. + * + * - *numberOfOutputNotes* (Integer) (optional): Number of output notes to create. + * + * - *aztecAccountNotRequired* (Boolean) (optional): Not to enforce recipient to have an aztec account. + * Useful when depositing funds to a contract. + * + * @param {Object} options Optional parameters to be passed: + * + * - *numberOfOutputNotes* (Integer): Number of new notes for each transaction. + * Unless `numberOfOutputNotes` is defined in that transaction. + * Will use default value in sdk settings if undefined. + * + * - *userAccess* ([Address]): Addresses that have been granted view access to the note value. + * + * - *returnProof* (Boolean): Return the JoinSplit proof instead of sending it. + * + * - *sender* (Address): The proof sender. Available only when `returnProof` is true. + * + * - *publicOwner* (Address): The owner of ERC token. Available only when `returnProof` is true. + * + * @returns {Object} txSummary Transaction summary information containing: + * + * - *success* (Boolean): Describes whether the transaction was successful. + * + * - *outputNotes* ([Note]): Notes deposited into the recipient accounts. + * + * - *proof* (JoinSplitProof): Available when `returnProof` is set to true. + * + */ + deposit = async (transactions, { + numberOfOutputNotes, + userAccess = [], + returnProof, + sender, + publicOwner, + } = {}) => { + if (!this.linkedTokenAddress) { + throw new ApiError('zkAsset.private', { + fn: 'deposit', + }); + } + + const { + success, + outputNotes, + proofData, + } = await ConnectionService.query( + 'constructProof', + { + proofType: 'DEPOSIT_PROOF', + assetAddress: this.address, + transactions: parseInputTransactions(transactions), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), + userAccess, + returnProof, + sender, + publicOwner, + }, + ); + + let proof; + if (proofData) { + proof = proofData + ? await recoverJoinSplitProof(proofData) + : null; + } + + return { + success, + outputNotes, + proof, + }; + }; + + /** + * + * @function zkAsset.withdraw + * @description Description: Withdraw zero-knowledge funds into public form - convert notes into public ERC20 tokens. + * + * @param {Integer} amount Units of value being withdrawn - will equal the number of ERC20 tokens the `to` address receives. + * + * @param {Object} options Optional arguments to be passed: + * + * - *to* (Address): Ethereum address to the ERC20 tokens should be sent, upon withdrawal. Will use current address if undefined. + * + * - *numberOfInputNotes* (Integer): Number of notes to be destroyed. + * The sdk will pick a random number of notes if undefined. + * + * - *inputNoteHashes* ([NoteHash]): Notes to be destroyed. + * Their total value should be larger than or equal to the total transaction amount + * if `numberOfInputNotes` is defined and is equal to the array size. + * Otherwise, the sdk will pick extra notes if necessary. + * + * - *returnProof* (Boolean): Return the JoinSplit proof instead of sending it. + * + * - *sender* (Address): The proof sender. Available only when `returnProof` is true. + * + * @returns {Object} txSummary Transaction summary information containing: + * + * - *success* (Boolean): Describes whether the transaction was successful. + * + * - *proof* (JoinSplitProof): Available when `returnProof` is set to true. + * + */ + withdraw = async (amount, { + to, + numberOfInputNotes, + inputNoteHashes, + returnProof, + sender, + } = {}) => { + if (!this.linkedTokenAddress) { + throw new ApiError('zkAsset.private', { + fn: 'withdraw', + }); + } + + const { + address, + } = Web3Service.account; + + const { + success, + proofData, + } = await ConnectionService.query( + 'constructProof', + { + proofType: 'WITHDRAW_PROOF', + assetAddress: this.address, + amount: parseInputInteger(amount), + to: to || address, + publicOwner: to || address, + numberOfInputNotes: parseInputInteger(numberOfInputNotes), + inputNoteHashes, + returnProof, + sender, + }, + ); + + let proof = null; + if (proofData) { + proof = proofData + ? await recoverJoinSplitProof(proofData) + : null; + } + + return { + success, + proof, + }; + }; + + /** + * + * @function zkAsset.send + * @description Description: Send funds confidentially to another Ethereum address. + * + * @param {[Transaction]} transactions Transaction information which the user wants to have enacted. Each transaction object consists of: + * + * - *amount* (Integer): Units of value to transfer, where 1 unit is equivalent in value to 1 ERC20 token. + * + * - *to* (Address): Ethereum address to which the user is sending zero-knowledge funds. + * + * - *numberOfOutputNotes* (Integer) (optional): Number of output notes of this transaction. + * + * - *aztecAccountNotRequired* (Boolean) (optional): Not to enforce recipient to have an aztec account. + * + * @param {Object} options Optional arguments to be passed: + * + * - *numberOfInputNotes* (Integer): Number of notes to be destroyed. + * The sdk will pick a random number of notes if undefined. + * + * - *numberOfOutputNotes* (Integer): Number of new notes for each transaction. + * Unless `numberOfOutputNotes` is defined in that transaction. + * Will use default value in sdk settings if undefined. + * + * - *inputNoteHashes* ([NoteHash]): Notes to be destroyed. + * Their total value should be larger than or equal to the total transaction amount + * if `numberOfInputNotes` is defined and is equal to the array size. + * Otherwise, the sdk will pick extra notes if necessary. + * + * - *userAccess* ([Address]): The addresses that are able to see the real note value. + * + * - *returnProof* (Boolean): Return the JoinSplit proof instead of sending it. + * + * - *sender* (Address): The proof sender. Available only when `returnProof` is true. + * + * - *publicOwner* (Address): The owner of ERC token. Available only when `returnProof` is true. + * + * @returns {Object} txSummary Transaction summary information containing: + * + * - *success* (Boolean): Describes whether the transaction was successful. + * + * - *outputNotes* ([Note]): Notes sent to the recipient accounts. + * + * - *proof* (JoinSplitProof): Available when `returnProof` is set to true. + * + */ + send = async (transactions, { + numberOfInputNotes, + numberOfOutputNotes, + inputNoteHashes, + userAccess, + returnProof, + sender, + publicOwner, + } = {}) => { + const { + success, + outputNotes, + proofData, + } = await ConnectionService.query( + 'constructProof', + { + proofType: 'TRANSFER_PROOF', + assetAddress: this.address, + transactions: parseInputTransactions(transactions), + numberOfInputNotes: parseInputInteger(numberOfInputNotes), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), + inputNoteHashes, + userAccess, + returnProof, + sender, + publicOwner, + }, + ); + + let proof; + if (proofData) { + proof = proofData + ? await recoverJoinSplitProof(proofData) + : null; + } + + return { + success, + outputNotes, + proof, + }; + }; + + /** + * + * Swap + * + * - swap object containing the notes to be swapped + * makerBid Note Hash of the makers bid + * takerBid Note Hash of the takers bid + * takerAsk Note Hash of the takers ask + * makerAsk Note Hash of the makers ask + * + * - options + * sender (String): The proof sender. + * numberOfInputNotes (Int): Number of notes picked from esisting pool. + * Will use extension's or user's setting if undefined. + * numberOfOutputNotes (Int): Number of new notes for each transaction. + * Unless numberOfOutputNotes is defined in that transaction. + * + * @returns ([Notes!]) + */ + swap = async ( + // swap, + // { + // sender = '', + // } = {}, + ) => { + // TODO + }; + + + /** + * + * Mint + * This api is available only when the asset is ZkAssetMintable + * + * - transactions ([Transaction!]) Transaction = { amount, to, numberOfOutputNotes } + * - options + * sender (String): The proof sender. + * If empty, will use extension's current user. + * numberOfOutputNotes (Int): Number of new notes. + * If input amount is an array, this value will be ignored. + * + * @returns ([Notes!]) + */ + mint = async ( + // transactions, + // { + // sender = '', + // numberOfOutputNotes = 1, + // } = {}, + ) => { + if (!this.canAdjustSupply) { + throw new ApiError('api.mint.notValid'); + } + + // TODO + }; + + /** + * + * Burn + * This api is available only when the asset is ZkAssetBurnable + * + * - notes ([Note!] or [AztecNote!]) + * - options + * sender (String): The proof sender. + * If empty, will use extension's current user. + * numberOfOutputNotes (Int): Number of new notes. + * If input amount is an array, this value will be ignored. + * + * @returns ([Notes!]) + */ + burn = async ( + // notes, + // { + // sender = '', + // } = {}, + ) => { + if (!this.canAdjustSupply) { + throw new ApiError('api.burn.notValid'); + } + + // TODO + }; + + /** + * + * @function zkAsset.createNoteFromBalance + * @description Description: Manually create notes, with particular values drawn from the user's balance. + * + * @param {Integer} amount Total value of the notes to be created. + * + * @param {Object} options Optional arguments to be passed: + * + * - *userAccess* ([Address]): The addresses that are able to see the real value of the new notes. + * + * - *numberOfInputNotes* (Integer): Number of notes to be destroyed. + * The sdk will pick a random number of notes if undefined. + * + * - *numberOfOutputNotes* (Integer): Number of new notes to be created. Default value is 1. + * + * @returns {[Note]} notes An Array of notes that have been created, where each note object contains: + * + * - *noteHash* (String) + * + * - *value* (Integer) + * + */ + createNoteFromBalance = async (amount, { + userAccess = [], + numberOfInputNotes, + numberOfOutputNotes = 1, + } = {}) => { + const { + notes, + } = await ConnectionService.query( + 'constructProof', + { + proofType: 'CREATE_NOTE_FROM_BALANCE_PROOF', + assetAddress: this.address, + amount: parseInputInteger(amount), + userAccess, + numberOfInputNotes: parseInputInteger(numberOfInputNotes), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), + }, + ) || {}; + + return notes; + }; + + /** + * + * @function zkAsset.fetchNotesFromBalance + * @description Description: Fetch the notes stored in the `zkAsset` that are owned by the user and match the given query. + * + * @param {Object} query Optional query object that can be used to refine the parameters of the note fetch. + * If not supplied, will return all the notes owned by the user. + * + * - *equalTo* (Integer): The exact value all notes need to match. + * + * - *greaterThan* (Integer): If no equalTo parameter, the minimum value of notes returned. + * + * - *lessThan* (Integer): If no equalTo parameter, the maximum value of notes returned. + * + * - *numberOfNotes* (Integer): Number of notes which match the query to return. + * + * @returns {[Note]} notes Fetched notes that satisfy the parameters of the fetch query. Each note is an object containing: + * + * - *noteHash* (String) + * + * - *value* (Integer) + * + */ + fetchNotesFromBalance = async ({ + greaterThan, + lessThan, + equalTo, + numberOfNotes, + } = {}) => ConnectionService.query( + 'fetchNotesFromBalance', + { + assetAddress: this.address, + greaterThan: parseInputInteger(greaterThan), + lessThan: parseInputInteger(lessThan), + equalTo: parseInputInteger(equalTo), + numberOfNotes: parseInputInteger(numberOfNotes), + }, + ); + + /** + * + * @function zkAsset.toNoteValue + * @description Description: Convert the ERC20 token value to its equivalent note value. + * + * @param {Integer|String|BigNumber} tokenValue Value of ERC20 token to be converted. + * + * @returns {Integer} noteValue Equivalent note value of `tokenValue`. + * + */ + toNoteValue = (tokenValue) => { + const { + decimals, + } = this.token || {}; + + return tokenToNoteValue({ + value: tokenValue, + scalingFactor: this.scalingFactor, + decimals: decimals || 0, + }); + }; + + /** + * + * @function zkAsset.toTokenValue + * @description Description: Convert note value to its equivalent ERC20 token value. + * + * @param {Integer|String|BigNumber} noteValue Value of note to be converted. + * + * @param {Boolean} format Optional parameter to format the output string. + * + * @returns {String} tokenValue Equivalent ERC20 token value of `noteValue`. + * + */ + toTokenValue = (noteValue, format = false) => { + const { + decimals, + } = this.token || {}; + + return noteToTokenValue({ + value: noteValue, + scalingFactor: this.scalingFactor, + decimals: decimals || 0, + format, + }); + }; +} diff --git a/packages/documentation/src/apis/ZkNote.js b/packages/documentation/src/apis/ZkNote.js new file mode 100644 index 000000000..4a480bcd9 --- /dev/null +++ b/packages/documentation/src/apis/ZkNote.js @@ -0,0 +1,284 @@ +import { + fromViewingKey, +} from '~/utils/note'; +import ConnectionService from '~/client/services/ConnectionService'; +import provePrivateRange from '~/client/apis/privateRange/prove'; + +const dataProperties = [ + 'noteHash', + 'value', + 'viewingKey', + 'owner', + 'asset', + 'status', +]; + +export default class ZkNote { + constructor({ + id, + ...note + } = {}) { + dataProperties.forEach((key) => { + this[key] = note[key]; + }); + this.id = id; + } + + get valid() { + return typeof this.value === 'number'; + } + + get visible() { + return !!this.viewingKey; + } + + get destroyed() { + return this.status === 'DESTROYED'; + } + + /** + * + * @function note.export + * @description Description: Export an aztec.js note instance for use in proofs. + * + * @returns {AztecNote} note An AZTEC note. + * + */ + async export() { + if (!this.visible) { + return null; + } + + const { + note, + } = await ConnectionService.query( + 'noteWithViewingKey', + { id: this.id }, + ) || {}; + + if (!note || !note.decryptedViewingKey) { + return null; + } + + const { + decryptedViewingKey, + owner = {}, + } = note; + + return fromViewingKey(decryptedViewingKey, owner.address); + } + + /** + * + * @function note.grantAccess + * @description Description: Grant note view access to an array of Ethereum addresses. + * + * @param {[Address]} addresses Array of Ethereum addresses that are to be granted note view access. + * + * @returns {Boolean} success Boolean describing whether the granting of view access was successfull. + * + */ + async grantAccess(addresses) { + if (!this.visible + || this.destroyed + ) { + return false; + } + + const addressList = typeof addresses === 'string' + ? [addresses] + : addresses; + + const { + success, + } = await ConnectionService.query( + 'grantNoteAccess', + { + id: this.id, + addresses: addressList, + }, + ) || {}; + + return success || false; + } + + /** + * + * @function note.equal + * @description Description: Construct a proof that the note is equal to a particular value. + * + * @param {ZkNote|AztecNote} comparisonNote Note that is being compared. + * + * @param {Object} options Optional parameters to be passed: + * + * - *sender* (Address): The proof sender. Will use current address if empty. + * + * - *remainderNote* (ZkNote|AztecNote): Helper note to make the equation hold. + * In this api, its value should be 0. + * The sdk will construct one if not provided. + * + * @returns {PrivateRangeProof} proof Instance of the constructed proof. + * + */ + async equal(comparisonNote, { + sender = '', + remainderNote = null, + } = {}) { + if (!this.visible) { + return false; + } + + const originalNote = await this.export(); + return provePrivateRange({ + type: 'eq', + originalNote, + comparisonNote, + remainderNote, + sender, + }); + } + + /** + * + * @function note.greaterThan + * @description Description: Construct a proof that the note is greater than a particular value. + * + * @param {ZkNote|AztecNote} comparisonNote Note that is being compared. + * + * @param {Object} options Optional parameters to be passed: + * + * - *sender* (Address): The proof sender. Will use current address if empty. + * + * - *remainderNote* (ZkNote|AztecNote): Helper note to make the equation hold. + * In this api, its value should be the value of the original zkNote minus the value of `comparisonNote`. + * The sdk will construct one if not provided. + * + * @returns {PrivateRangeProof} proof Instance of the constructed proof. + * + */ + async greaterThan(comparisonNote, { + sender = '', + remainderNote = null, + } = {}) { + if (!this.visible) { + return false; + } + + const originalNote = await this.export(); + return provePrivateRange({ + type: 'gt', + originalNote, + comparisonNote, + remainderNote, + sender, + }); + } + + /** + * + * @function note.lessThan + * @description Description: Construct a proof that the note value is less than a particular value. + * + * @param {ZkNote|AztecNote} comparisonNote Note that is being compared. + * + * @param {Object} options Optional parameters to be passed: + * + * - *sender* (Address): The proof sender. Will use current address if empty. + * + * - *remainderNote* (ZkNote|AztecNote): Helper note to make the equation hold. + * In this api, its value should be the value of `comparisonNote` minus the value of the original zkNote. + * The sdk will construct one if not provided. + * + * @returns {PrivateRangeProof} proof Instance of the constructed proof. + * + */ + async lessThan(comparisonNote, { + sender = '', + remainderNote = null, + } = {}) { + if (!this.visible) { + return false; + } + + const originalNote = await this.export(); + return provePrivateRange({ + type: 'lt', + originalNote, + comparisonNote, + remainderNote, + sender, + }); + } + + /** + * + * @function note.greaterThanOrEqualTo + * @description Description: Construct a proof that the note value is greater than or equal to a particular value. + * + * @param {ZkNote|AztecNote} comparisonNote Note that is being compared. + * + * @param {Object} options Optional parameters to be passed: + * + * - *sender* (Address): The proof sender. Will use current address if empty. + * + * - *remainderNote* (ZkNote|AztecNote): Helper note to make the equation hold. + * In this api, its value should be the value of the original zkNote minus the value of `comparisonNote`. + * The sdk will construct one if not provided. + * + * @returns {PrivateRangeProof} proof Instance of the constructed proof. + * + */ + async greaterThanOrEqualTo(comparisonNote, { + sender = '', + remainderNote = null, + } = {}) { + if (!this.visible) { + return false; + } + + const originalNote = await this.export(); + return provePrivateRange({ + type: 'gte', + originalNote, + comparisonNote, + remainderNote, + sender, + }); + } + + /** + * + * @function note.lessThanOrEqualTo + * @description Description: Construct a proof that the note value is less than or equal to a particular value. + * + * @param {ZkNote|AztecNote} comparisonNote Note that is being compared. + * + * @param {Object} options Optional parameters to be passed: + * + * - *sender* (Address): The proof sender. Will use current address if empty. + * + * - *remainderNote* (ZkNote|AztecNote): Helper note to make the equation hold. + * In this api, its value should be the value of `comparisonNote` minus the value of the original zkNote. + * The sdk will construct one if not provided. + * + * @returns {PrivateRangeProof} proof Instance of the constructed proof. + * + */ + async lessThanOrEqualTo(comparisonNote, { + sender = '', + remainderNote = null, + } = {}) { + if (!this.visible) { + return false; + } + + const originalNote = await this.export(); + return provePrivateRange({ + type: 'lte', + originalNote, + comparisonNote, + remainderNote, + sender, + }); + } +} From cef61cb9c10ac310d49ff06db454558d76801d4e Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 24 Mar 2020 16:26:32 +0000 Subject: [PATCH 03/19] fix(sdk): init aztec when DOMContentLoaded has already been fired --- packages/extension/src/index.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/extension/src/index.js b/packages/extension/src/index.js index 95676a714..68cb91645 100644 --- a/packages/extension/src/index.js +++ b/packages/extension/src/index.js @@ -1,6 +1,6 @@ import Aztec from '~/client/Aztec'; -document.addEventListener('DOMContentLoaded', async () => { +const initializeAZTEC = async () => { const aztec = new Aztec(); await aztec.generateInitialApis(); delete aztec.generateInitialApis; @@ -11,4 +11,17 @@ document.addEventListener('DOMContentLoaded', async () => { if (typeof window.aztecCallback === 'function') { window.aztecCallback(); } -}); +}; + +const readyStates = [ + 'complete', + 'interactive', +]; + +if (readyStates.indexOf(document.readyState) >= 0) { + initializeAZTEC(); +} else { + document.addEventListener('DOMContentLoaded', () => { + initializeAZTEC(); + }); +} From f66ae85a3032e9e01a3adf3b99ff945ab832881b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 24 Mar 2020 17:09:46 +0000 Subject: [PATCH 04/19] feat(sdk): add sdk installer --- packages/sdk-installer/.eslintignore | 3 + packages/sdk-installer/.eslintrc.js | 19 +++ packages/sdk-installer/README.md | 48 +++++++ packages/sdk-installer/babel.config.js | 20 +++ packages/sdk-installer/package.json | 32 +++++ packages/sdk-installer/src/InstallManager.js | 59 +++++++++ packages/sdk-installer/src/installer.js | 38 ++++++ packages/sdk-installer/tests/env-node.test.js | 20 +++ .../sdk-installer/tests/installer.test.js | 122 ++++++++++++++++++ 9 files changed, 361 insertions(+) create mode 100644 packages/sdk-installer/.eslintignore create mode 100644 packages/sdk-installer/.eslintrc.js create mode 100644 packages/sdk-installer/README.md create mode 100644 packages/sdk-installer/babel.config.js create mode 100644 packages/sdk-installer/package.json create mode 100644 packages/sdk-installer/src/InstallManager.js create mode 100644 packages/sdk-installer/src/installer.js create mode 100644 packages/sdk-installer/tests/env-node.test.js create mode 100644 packages/sdk-installer/tests/installer.test.js diff --git a/packages/sdk-installer/.eslintignore b/packages/sdk-installer/.eslintignore new file mode 100644 index 000000000..42d107c1e --- /dev/null +++ b/packages/sdk-installer/.eslintignore @@ -0,0 +1,3 @@ +# ignored directories +node_modules/* +/dist/* diff --git a/packages/sdk-installer/.eslintrc.js b/packages/sdk-installer/.eslintrc.js new file mode 100644 index 000000000..e22741447 --- /dev/null +++ b/packages/sdk-installer/.eslintrc.js @@ -0,0 +1,19 @@ +module.exports = { + extends: 'airbnb/base', + parser: 'babel-eslint', + env: { + browser: true, + es6: true, + node: true, + jest: true, + }, + rules: { + indent: [ + 'error', + 4, + { + SwitchCase: 1, + }, + ], + }, +}; diff --git a/packages/sdk-installer/README.md b/packages/sdk-installer/README.md new file mode 100644 index 000000000..a2221e417 --- /dev/null +++ b/packages/sdk-installer/README.md @@ -0,0 +1,48 @@ +# AZTEC SDK Installer + +This is a simple npm package that helps you setup AZTEC in your project. + +### Install + +```sh +yarn add @aztec/sdk-installer +``` + +or + +```sh +npm install @aztec/sdk-installer +``` + +### Getting started + +When you import installer to your code, the installer will add a script tag to the html. The content of the SDK will start loading at this point and might not be available immediately. So you will also need to provide a callback to the installer. The callback will be triggered once the SDK is ready to use. + +```js +import installer from '@aztec/sdk-installer'; + +const startUsingAztec = () => {}; + +installer.onLoad(startUsingAztec); +``` + +_** Note that the webpage will fetch the SDK with the same version as the installer. So upgrade the installer regularly to get the latest version of the SDK._ + + +### Using the SDK + +Once the SDK is loaded, you can access `aztec` by: + +```js +await window.aztec.enable(); +``` + +or + +```js +import installer from '@aztec/sdk-installer'; +await installer.aztec.enable(); +``` + +#### For the full AZTEC SDK usage +Checkout the docs here: **[https://docs.aztecprotocol.com/](https://docs.aztecprotocol.com/)** diff --git a/packages/sdk-installer/babel.config.js b/packages/sdk-installer/babel.config.js new file mode 100644 index 000000000..bf0e07788 --- /dev/null +++ b/packages/sdk-installer/babel.config.js @@ -0,0 +1,20 @@ +module.exports = { + presets: [ + '@babel/preset-env', + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-object-rest-spread', + ], + env: { + transpile: { + presets: [ + '@babel/preset-env', + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-object-rest-spread', + ], + }, + }, +}; diff --git a/packages/sdk-installer/package.json b/packages/sdk-installer/package.json new file mode 100644 index 000000000..59dc5a08b --- /dev/null +++ b/packages/sdk-installer/package.json @@ -0,0 +1,32 @@ +{ + "name": "@aztec/sdk-installer", + "description": "NPM package for AZTEC SDK", + "license": "LGPL-3.0", + "version": "1.10.1", + "author": "AZTEC", + "bugs": { + "url": "https://github.com/AztecProtocol/AZTEC/issues" + }, + "main": "dist/installer.js", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn transpile", + "lint": "eslint ./ --color", + "test": "jest ./tests", + "transpile": "BABEL_ENV=transpile babel src -d dist" + }, + "devDependencies": { + "@babel/cli": "^7.2.3", + "@babel/core": "^7.4.0", + "@babel/node": "^7.2.2", + "@babel/plugin-proposal-class-properties": "^7.4.4", + "@babel/plugin-proposal-object-rest-spread": "^7.4.4", + "@babel/preset-env": "^7.4.4", + "babel-eslint": "^10.0.2", + "eslint": "^6.8.0", + "eslint-config-airbnb-base": "^14.1.0", + "jest": "^25.1.0" + } +} diff --git a/packages/sdk-installer/src/InstallManager.js b/packages/sdk-installer/src/InstallManager.js new file mode 100644 index 000000000..66404da94 --- /dev/null +++ b/packages/sdk-installer/src/InstallManager.js @@ -0,0 +1,59 @@ +export default class InstallerManager { + constructor(version) { + this.version = version; + this.scriptId = 'aztec-sdk-script'; + this.onLoadListeners = new Set(); + + this.init(); + } + + init() { + if (window.aztec) return; + + if (window.aztecCallback) { + this.onLoadListeners.add(window.aztecCallback); + } + window.aztecCallback = this.handleAztecLoaded; + + const readyStates = [ + 'complete', + 'interactive', + ]; + + if (readyStates.indexOf(document.readyState) >= 0) { + this.addSdkScript(); + } else { + document.addEventListener('DOMContentLoaded', () => { + this.addSdkScript(); + }); + } + } + + addSdkScript() { + const prevScript = document.getElementById(this.scriptId); + if (prevScript) return; + + const script = document.createElement('script'); + script.id = this.scriptId; + script.type = 'module'; + script.src = `https://sdk.aztecprotocol.com/${this.version}/sdk/aztec.js`; + document.body.appendChild(script); + } + + handleAztecLoaded = () => { + if (!this.onLoadListeners) return; + + this.onLoadListeners.forEach((cb) => { + cb(); + }); + this.onLoadListeners = null; + }; + + onLoad(cb) { + if (window.aztec) { + cb(); + } else { + this.onLoadListeners.add(cb); + } + } +} diff --git a/packages/sdk-installer/src/installer.js b/packages/sdk-installer/src/installer.js new file mode 100644 index 000000000..1eb9b2a14 --- /dev/null +++ b/packages/sdk-installer/src/installer.js @@ -0,0 +1,38 @@ +import json from '../package.json'; +import InstallManager from './InstallManager'; + +let manager = null; + +class AztecSdkInstaller { + constructor() { + if (typeof window === 'undefined') { + console.error('AZTEC SDK can only be run in web browser.'); // eslint-disable-line no-console + return; + } + + this.version = json.version; + this.aztec = null; + + manager = new InstallManager(this.version); + + manager.onLoad(() => { + this.aztec = window.aztec; + }); + + if (process.env.NODE_ENV === 'test') { + this.manager = manager; + } + } + + onLoad(cb) { // eslint-disable-line class-methods-use-this + manager.onLoad(cb); + } +} + +const SdkInstaller = process.env.NODE_ENV === 'test' ? AztecSdkInstaller : null; + +export { + SdkInstaller, +}; + +export default new AztecSdkInstaller(); diff --git a/packages/sdk-installer/tests/env-node.test.js b/packages/sdk-installer/tests/env-node.test.js new file mode 100644 index 000000000..450a6ad6d --- /dev/null +++ b/packages/sdk-installer/tests/env-node.test.js @@ -0,0 +1,20 @@ +/** + * @jest-environment node + */ + +const importInstaller = () => require('../src/installer.js').default; // eslint-disable-line global-require + +describe('installer', () => { + it('log error if window is not defined', () => { + const errors = []; + const errorLogMock = jest.spyOn(console, 'error') + .mockImplementation((error) => { + errors.push(error); + }); + + importInstaller(); + expect(errors).toEqual(['AZTEC SDK can only be run in web browser.']); + + errorLogMock.mockRestore(); + }); +}); diff --git a/packages/sdk-installer/tests/installer.test.js b/packages/sdk-installer/tests/installer.test.js new file mode 100644 index 000000000..230b61f35 --- /dev/null +++ b/packages/sdk-installer/tests/installer.test.js @@ -0,0 +1,122 @@ +import aztecSdkInsterller, { + SdkInstaller, +} from '../src/installer'; +import json from '../package.json'; + +const { scriptId } = aztecSdkInsterller.manager; + +const mockSdkLoaded = () => { + window.aztec = {}; + window.aztecCallback(); +}; + +beforeEach(() => { + window.aztec = null; + window.aztecCallback = null; + document.body.innerHTML = ''; +}); + +describe('installer constructor', () => { + it('has the same version as defined in package.json', () => { + const installer = new SdkInstaller(); + expect(installer.version).toBe(json.version); + }); + + it('append a script tag to body', () => { + const prevScript = document.getElementById(scriptId); + expect(prevScript).toBe(null); + + const installer = new SdkInstaller(); + + const script = document.getElementById(scriptId); + expect(script).not.toBe(null); + expect(script.type).toBe('module'); + expect(script.src).toContain(installer.version); + }); + + it('will not append another script tag if it is already in body', () => { + const appendChildSpy = jest.spyOn(document.body, 'appendChild'); + expect(appendChildSpy).toHaveBeenCalledTimes(0); + + const installer = new SdkInstaller(); + + expect(appendChildSpy).toHaveBeenCalledTimes(1); + const script = document.getElementById(scriptId); + expect(script).not.toBe(null); + expect(script.src).toContain(installer.version); + + const installer2 = new SdkInstaller(); + + expect(appendChildSpy).toHaveBeenCalledTimes(1); + expect(installer2).not.toBe(installer); + const script2 = document.getElementById(scriptId); + expect(script).toBe(script2); + }); + + it('will not append script tag before document is ready', () => { + Object.defineProperty(document, 'readyState', { + get: jest.fn(() => 'loading'), + }); + + const appendChildSpy = jest.spyOn(document.body, 'appendChild'); + appendChildSpy.mockReset(); + + const installer = new SdkInstaller(); + + const addSdkScriptSpy = jest.spyOn(installer.manager, 'addSdkScript'); + + expect(appendChildSpy).toHaveBeenCalledTimes(0); + const script = document.getElementById(scriptId); + expect(script).toBe(null); + expect(addSdkScriptSpy).toHaveBeenCalledTimes(0); + + const event = document.createEvent('Event'); + event.initEvent('DOMContentLoaded', true, true); + window.document.dispatchEvent(event); + + expect(appendChildSpy).toHaveBeenCalledTimes(1); + expect(addSdkScriptSpy).toHaveBeenCalledTimes(1); + }); + + it('trigger callbacks when sdk is loaded', () => { + const cb1 = jest.fn(); + const cb2 = jest.fn(); + + const installer = new SdkInstaller(); + installer.onLoad(cb1); + installer.onLoad(cb2); + + expect(cb1).toHaveBeenCalledTimes(0); + expect(cb2).toHaveBeenCalledTimes(0); + + mockSdkLoaded(); + + expect(cb1).toHaveBeenCalledTimes(1); + expect(cb2).toHaveBeenCalledTimes(1); + }); + + it('callbacks will be triggered immediately when sdk is loaded', () => { + const installer = new SdkInstaller(); + + mockSdkLoaded(); + + const cb = jest.fn(); + installer.onLoad(cb); + expect(cb).toHaveBeenCalledTimes(1); + }); + + it('the same callbacks will be triggered only once', () => { + const cb = jest.fn(); + + const installer = new SdkInstaller(); + + installer.onLoad(cb); + installer.onLoad(cb); + + expect(cb).toHaveBeenCalledTimes(0); + + mockSdkLoaded(); + + expect(cb).toHaveBeenCalledTimes(1); + }); +}); From 17853e821f8edf9bb75f58060105f9162dfa4430 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 26 Mar 2020 11:17:07 +0000 Subject: [PATCH 05/19] fix(sdk): always add user's own access when creating note from the api --- packages/extension/src/client/apis/Account.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/extension/src/client/apis/Account.js b/packages/extension/src/client/apis/Account.js index b3b28e08f..d0003894b 100644 --- a/packages/extension/src/client/apis/Account.js +++ b/packages/extension/src/client/apis/Account.js @@ -51,7 +51,7 @@ class Account { 'users', { where: { - address_in: uniq(userAccess), + address_in: uniq(userAccess).filter(a => a !== this.address), }, }, ` @@ -60,6 +60,10 @@ class Account { `, ) || {}); } + noteAccess.push({ + address: this.address, + linkedPublicKey: this.linkedPublicKey, + }); return noteUtils.create( this.spendingPublicKey, From d868eb6134ba0d13ed5925e11b12d43f9fccd80f Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 26 Mar 2020 11:39:26 +0000 Subject: [PATCH 06/19] style(sdk): fix styles for prettier --- packages/sdk-installer/README.md | 4 ++-- packages/sdk-installer/babel.config.js | 18 ++++-------------- packages/sdk-installer/src/InstallManager.js | 5 +---- packages/sdk-installer/src/installer.js | 7 +++---- packages/sdk-installer/tests/env-node.test.js | 7 +++---- packages/sdk-installer/tests/installer.test.js | 4 +--- 6 files changed, 14 insertions(+), 31 deletions(-) diff --git a/packages/sdk-installer/README.md b/packages/sdk-installer/README.md index a2221e417..1557e5b82 100644 --- a/packages/sdk-installer/README.md +++ b/packages/sdk-installer/README.md @@ -26,8 +26,7 @@ const startUsingAztec = () => {}; installer.onLoad(startUsingAztec); ``` -_** Note that the webpage will fetch the SDK with the same version as the installer. So upgrade the installer regularly to get the latest version of the SDK._ - +_\*\* Note that the webpage will fetch the SDK with the same version as the installer. So upgrade the installer regularly to get the latest version of the SDK._ ### Using the SDK @@ -45,4 +44,5 @@ await installer.aztec.enable(); ``` #### For the full AZTEC SDK usage + Checkout the docs here: **[https://docs.aztecprotocol.com/](https://docs.aztecprotocol.com/)** diff --git a/packages/sdk-installer/babel.config.js b/packages/sdk-installer/babel.config.js index bf0e07788..a41b8d547 100644 --- a/packages/sdk-installer/babel.config.js +++ b/packages/sdk-installer/babel.config.js @@ -1,20 +1,10 @@ module.exports = { - presets: [ - '@babel/preset-env', - ], - plugins: [ - '@babel/plugin-proposal-class-properties', - '@babel/plugin-proposal-object-rest-spread', - ], + presets: ['@babel/preset-env'], + plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-object-rest-spread'], env: { transpile: { - presets: [ - '@babel/preset-env', - ], - plugins: [ - '@babel/plugin-proposal-class-properties', - '@babel/plugin-proposal-object-rest-spread', - ], + presets: ['@babel/preset-env'], + plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-object-rest-spread'], }, }, }; diff --git a/packages/sdk-installer/src/InstallManager.js b/packages/sdk-installer/src/InstallManager.js index 66404da94..91895404a 100644 --- a/packages/sdk-installer/src/InstallManager.js +++ b/packages/sdk-installer/src/InstallManager.js @@ -15,10 +15,7 @@ export default class InstallerManager { } window.aztecCallback = this.handleAztecLoaded; - const readyStates = [ - 'complete', - 'interactive', - ]; + const readyStates = ['complete', 'interactive']; if (readyStates.indexOf(document.readyState) >= 0) { this.addSdkScript(); diff --git a/packages/sdk-installer/src/installer.js b/packages/sdk-installer/src/installer.js index 1eb9b2a14..ebce0a64c 100644 --- a/packages/sdk-installer/src/installer.js +++ b/packages/sdk-installer/src/installer.js @@ -1,3 +1,4 @@ +/* eslint-disable class-methods-use-this */ import json from '../package.json'; import InstallManager from './InstallManager'; @@ -24,15 +25,13 @@ class AztecSdkInstaller { } } - onLoad(cb) { // eslint-disable-line class-methods-use-this + onLoad(cb) { manager.onLoad(cb); } } const SdkInstaller = process.env.NODE_ENV === 'test' ? AztecSdkInstaller : null; -export { - SdkInstaller, -}; +export { SdkInstaller }; export default new AztecSdkInstaller(); diff --git a/packages/sdk-installer/tests/env-node.test.js b/packages/sdk-installer/tests/env-node.test.js index 450a6ad6d..ba3be7720 100644 --- a/packages/sdk-installer/tests/env-node.test.js +++ b/packages/sdk-installer/tests/env-node.test.js @@ -7,10 +7,9 @@ const importInstaller = () => require('../src/installer.js').default; // eslint- describe('installer', () => { it('log error if window is not defined', () => { const errors = []; - const errorLogMock = jest.spyOn(console, 'error') - .mockImplementation((error) => { - errors.push(error); - }); + const errorLogMock = jest.spyOn(console, 'error').mockImplementation((error) => { + errors.push(error); + }); importInstaller(); expect(errors).toEqual(['AZTEC SDK can only be run in web browser.']); diff --git a/packages/sdk-installer/tests/installer.test.js b/packages/sdk-installer/tests/installer.test.js index 230b61f35..b6bea217d 100644 --- a/packages/sdk-installer/tests/installer.test.js +++ b/packages/sdk-installer/tests/installer.test.js @@ -1,6 +1,4 @@ -import aztecSdkInsterller, { - SdkInstaller, -} from '../src/installer'; +import aztecSdkInsterller, { SdkInstaller } from '../src/installer'; import json from '../package.json'; const { scriptId } = aztecSdkInsterller.manager; From 3ac037fa33cb0160a7df9c9ce2286a6536a0d2ec Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 26 Mar 2020 11:59:31 +0000 Subject: [PATCH 07/19] style(documentation): exclude sdk apis from prettier --- .prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 4537df6c3..a52b65395 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,5 +16,5 @@ package.json # packages packages/contract-addresses/addresses/ packages/contract-artifacts/artifacts/ -packages/graph/ +packages/documentation/src/apis/ packages/extension/ From 10a7ea094b20ea03f477bc3473a1acb82ce8b279 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 26 Mar 2020 12:32:24 +0000 Subject: [PATCH 08/19] style(documentation): exclude all sdk api files from prettier --- .prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index a52b65395..897fe0ade 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,5 +16,5 @@ package.json # packages packages/contract-addresses/addresses/ packages/contract-artifacts/artifacts/ -packages/documentation/src/apis/ +packages/documentation/*/apis/ packages/extension/ From e064dd0d5a64d58e537b4ce3965fa24c01fbe680 Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Mon, 30 Mar 2020 13:50:50 +0100 Subject: [PATCH 09/19] chore(monorepo-scripts): update source of dependency --- packages/monorepo-scripts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 71354b7da..a022c40e2 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -8,7 +8,7 @@ "eslint-config-airbnb-base": "^13.1.0", "eslint-config-prettier": "^6.0.0", "eslint-plugin-import": "^2.16.0", - "multi-semantic-release": "AztecProtocol/multi-semantic-release" + "multi-semantic-release": "^1.1.2" }, "engines": { "node": ">=8.3" From 2fa00faca3c3f55d373082566977ba8eb648e7db Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Tue, 31 Mar 2020 19:35:20 +0100 Subject: [PATCH 10/19] build(documentation): rename copy to copyapis --- packages/documentation/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 0b260fa80..1b1abee0e 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "truffle compile --all && styleguidist build && yarn copyApis && yarn copyImages", "clean": "shx rm -rf ./build ./dist ./public || true", - "copy": "cp -r src/apis public/apis", + "copyApis": "cp -r src/apis public/apis", "copy:local": "find -E ../extension/src/client/apis -regex '.*(Zk|Account).*' -exec cp {} ./src/apis \\;", "copyImages": "cp -r ./images ./public", "generateStyles": "guacamole generateStyles", From b92d6cdc204f82464be8dcda9bb55c2bb238c32d Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Wed, 1 Apr 2020 11:04:10 +0100 Subject: [PATCH 11/19] docs(documentation): remove reference to loan-dapp-starter-kit --- packages/documentation/styleguide/categories/Examples/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/documentation/styleguide/categories/Examples/index.md b/packages/documentation/styleguide/categories/Examples/index.md index 50ca61df8..66f01f3f1 100644 --- a/packages/documentation/styleguide/categories/Examples/index.md +++ b/packages/documentation/styleguide/categories/Examples/index.md @@ -3,5 +3,4 @@ This section summaries the various starter kits, examples and demos of the Aztec | Example | Description | Link | Last updated | | | ------------------------- | ------------------------------------------------------ | ---------------------------------------------------------- | ------------ | --- | | sdk-starter-kit | Starting point for building a dapp with the Aztec SDK | https://github.com/AztecProtocol/sdk-starter-kit | Feb 2020 | | -| loan-dapp-starter-kit | PoC confidential financial asset built with `aztec.js` | https://github.com/AztecProtocol/loan-dapp-starter-kit | March 2020 | | | aztec-ganache-starter-kit | Demo of using `aztec.js` and the protocol on ganache | https://github.com/AztecProtocol/aztec-ganache-starter-kit | Feb 2020 | | From 6f5f90500b920955a6ac4e1e03a1012c3b97964c Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Wed, 1 Apr 2020 11:25:20 +0100 Subject: [PATCH 12/19] docs(documentation): fix link to SDK first page --- .../documentation/styleguide/categories/Introduction/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/styleguide/categories/Introduction/index.md b/packages/documentation/styleguide/categories/Introduction/index.md index 89c10ae90..86d169ebd 100644 --- a/packages/documentation/styleguide/categories/Introduction/index.md +++ b/packages/documentation/styleguide/categories/Introduction/index.md @@ -2,7 +2,7 @@ AZTEC is a privacy engine for Ethereum, enabling confidential transactions over This documentation site acts as a single source of information about the AZTEC protocol. It provides information about the: -- [`SDK`](/#/SDK): high level developer SDK for building Dapps +- [`SDK`](/#/SDK/The%20role%20of%20the%20SDK): high level developer SDK for building Dapps - [`aztec.js`](/#/aztec.js): low level JavaScript npm package, used for proof construction - [`Examples`](/#/Examples): starter kits, demos and code examples for getting started - [`Specification`](/#/Specification): technical protocol specification From b493b78731dd0389764d8def415bd2c9cd4f0907 Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Wed, 1 Apr 2020 16:49:00 +0100 Subject: [PATCH 13/19] test(protocol): set time for ganache correctly --- packages/protocol/truffle-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/truffle-config.js b/packages/protocol/truffle-config.js index 46b92750c..b59c0a2d3 100644 --- a/packages/protocol/truffle-config.js +++ b/packages/protocol/truffle-config.js @@ -80,7 +80,7 @@ switch (process.env.MODE) { } let ganacheSubprovider = {}; -ganacheSubprovider = new GanacheSubprovider({ mnemonic: process.env.TEST_MNEMONIC }); +ganacheSubprovider = new GanacheSubprovider({ mnemonic: process.env.TEST_MNEMONIC , time: new Date('2019-12-31')}); engine.addProvider(ganacheSubprovider); engine.start((err) => { From 1d342d08a8048a1d9d5047734273d75c54a5ea9b Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Wed, 1 Apr 2020 17:23:48 +0100 Subject: [PATCH 14/19] style(): fix lint --- .../documentation/styleguide/categories/Examples/index.md | 8 ++++---- packages/protocol/truffle-config.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/documentation/styleguide/categories/Examples/index.md b/packages/documentation/styleguide/categories/Examples/index.md index 66f01f3f1..786509dd2 100644 --- a/packages/documentation/styleguide/categories/Examples/index.md +++ b/packages/documentation/styleguide/categories/Examples/index.md @@ -1,6 +1,6 @@ This section summaries the various starter kits, examples and demos of the Aztec protocol code. It is a good starting point for working with the protocol. -| Example | Description | Link | Last updated | | -| ------------------------- | ------------------------------------------------------ | ---------------------------------------------------------- | ------------ | --- | -| sdk-starter-kit | Starting point for building a dapp with the Aztec SDK | https://github.com/AztecProtocol/sdk-starter-kit | Feb 2020 | | -| aztec-ganache-starter-kit | Demo of using `aztec.js` and the protocol on ganache | https://github.com/AztecProtocol/aztec-ganache-starter-kit | Feb 2020 | | +| Example | Description | Link | Last updated | | +| ------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | ------------ | --- | +| sdk-starter-kit | Starting point for building a dapp with the Aztec SDK | https://github.com/AztecProtocol/sdk-starter-kit | Feb 2020 | | +| aztec-ganache-starter-kit | Demo of using `aztec.js` and the protocol on ganache | https://github.com/AztecProtocol/aztec-ganache-starter-kit | Feb 2020 | | diff --git a/packages/protocol/truffle-config.js b/packages/protocol/truffle-config.js index b59c0a2d3..c764b75d5 100644 --- a/packages/protocol/truffle-config.js +++ b/packages/protocol/truffle-config.js @@ -80,7 +80,7 @@ switch (process.env.MODE) { } let ganacheSubprovider = {}; -ganacheSubprovider = new GanacheSubprovider({ mnemonic: process.env.TEST_MNEMONIC , time: new Date('2019-12-31')}); +ganacheSubprovider = new GanacheSubprovider({ mnemonic: process.env.TEST_MNEMONIC, time: new Date('2019-12-31') }); engine.addProvider(ganacheSubprovider); engine.start((err) => { From 7ee1f8ddf252c5439dcc2fa2188aa9671d72f222 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 9 Apr 2020 15:36:34 +0100 Subject: [PATCH 15/19] Fix issue template --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 36da2336b..92b53ad1c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,4 @@ - ## Expected Behaviour From b97763efac360cfca4d0eeeac3f70321f656bae1 Mon Sep 17 00:00:00 2001 From: Arnaud Schenk Date: Mon, 27 Apr 2020 12:01:29 +0100 Subject: [PATCH 16/19] docs(documentation): fix discord link --- .../documentation/styleguide/components/SdkPlayground/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentation/styleguide/components/SdkPlayground/index.jsx b/packages/documentation/styleguide/components/SdkPlayground/index.jsx index 1663c0b6c..ca2c7ba43 100644 --- a/packages/documentation/styleguide/components/SdkPlayground/index.jsx +++ b/packages/documentation/styleguide/components/SdkPlayground/index.jsx @@ -199,7 +199,7 @@ class SdkPlayground extends PureComponent { <>