From f61c64c7a05de5f9ea2923535292a683779587f0 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 12 Feb 2020 18:41:42 +0000 Subject: [PATCH 01/10] fix(sdk): return null account if user denied metamask connection --- .../extension/src/client/Aztec/ApiManager.js | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/packages/extension/src/client/Aztec/ApiManager.js b/packages/extension/src/client/Aztec/ApiManager.js index 799ad3aac..bc5c90629 100644 --- a/packages/extension/src/client/Aztec/ApiManager.js +++ b/packages/extension/src/client/Aztec/ApiManager.js @@ -12,22 +12,29 @@ export default class ApiManager { this.enableProfileChangeListener = null; Web3Service.bindProfileChange((changedType, newTypeValue) => { - let objValue = newTypeValue; - switch (changedType) { - case 'accountChanged': - objValue = { - address: newTypeValue, - }; - break; - case 'networkChanged': - case 'chainChanged': - objValue = { - id: newTypeValue, - name: getNetworkName(Web3Service.networkId), - }; - break; - default: + let objValue = newTypeValue || null; + if (objValue) { + switch (changedType) { + case 'accountChanged': + objValue = { + address: newTypeValue, + }; + break; + case 'networkChanged': + case 'chainChanged': + if (newTypeValue === 'loading') { + objValue = null; + } else { + objValue = { + id: newTypeValue, + name: getNetworkName(newTypeValue), + }; + } + break; + default: + } } + this.eventListeners.notify('profileChanged', changedType, objValue); }); } From 5e96d23ffbfdeff4c231903f5469e8dae0a51314 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 12 Feb 2020 18:43:54 +0000 Subject: [PATCH 02/10] fix(sdk): handle null userAccess in create note from balance view --- packages/extension/src/ui/pages/CreateNoteFromBalance.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/extension/src/ui/pages/CreateNoteFromBalance.jsx b/packages/extension/src/ui/pages/CreateNoteFromBalance.jsx index 81c3c26c2..9745e9413 100644 --- a/packages/extension/src/ui/pages/CreateNoteFromBalance.jsx +++ b/packages/extension/src/ui/pages/CreateNoteFromBalance.jsx @@ -59,7 +59,9 @@ const CreateNoteFromBalance = ({ const steps = createNoteFromBalanceSteps[isGSNAvailable ? 'gsn' : 'metamask']; const asset = await makeAsset(assetAddress); - const userAccessAccounts = await apis.account.batchGetExtensionAccount(userAccess); + const userAccessAccounts = userAccess + ? await apis.account.batchGetExtensionAccount(userAccess) + : []; const sender = isGSNAvailable ? proxyContract : currentAddress; const amount = parseInputAmount(inputAmount); const numberOfInputNotes = !Object.is(customNumberOfInputNotes, emptyIntValue) From 9899c4c1147e8300642821160e47568d14efc45b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 12 Feb 2020 18:44:43 +0000 Subject: [PATCH 03/10] fix(sdk): cast network ids to string to compare --- packages/extension/src/utils/network/getNetworkName.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension/src/utils/network/getNetworkName.js b/packages/extension/src/utils/network/getNetworkName.js index eba903da7..906eb91e3 100644 --- a/packages/extension/src/utils/network/getNetworkName.js +++ b/packages/extension/src/utils/network/getNetworkName.js @@ -2,7 +2,7 @@ import networks from '~/config/networks'; export default function getNetworkName(networkId) { let networkKey = Object.keys(networks) - .find(name => networks[name].id === networkId); + .find(name => `${networks[name].id}` === `${networkId}`); if (!networkKey) { networkKey = 'GANACHE'; } From c12c1f6bde9e1eca19feac7ae7fae112c92854c5 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 12 Feb 2020 18:46:17 +0000 Subject: [PATCH 04/10] feat(sdk): return detailed error message if input format is wrong --- .../ApiService/middlewares/validateParameters.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/extension/src/background/services/ApiService/middlewares/validateParameters.js b/packages/extension/src/background/services/ApiService/middlewares/validateParameters.js index 97d216496..504e70bb3 100644 --- a/packages/extension/src/background/services/ApiService/middlewares/validateParameters.js +++ b/packages/extension/src/background/services/ApiService/middlewares/validateParameters.js @@ -25,9 +25,14 @@ export default function validateParameters(query, args) { const errorMsg = schema.validate(args); if (errorMsg) { - return argsError('input.invalid', { - message: errorMsg, - }); + const errorResp = argsError('input.invalid'); + return { + ...errorResp, + error: { + ...errorResp.error, + message: errorMsg, + }, + }; } return null; From 6db0bd6c62ce9cfff79188b8a9646c2aba089dec Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 10:51:41 +0000 Subject: [PATCH 05/10] fix(sdk): prevent MetaMask from refreshing in all scripts --- packages/extension/src/client/services/Web3Service.js | 4 ---- packages/extension/src/utils/Web3Service.js | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/extension/src/client/services/Web3Service.js b/packages/extension/src/client/services/Web3Service.js index 372ab66f5..51f9b3511 100644 --- a/packages/extension/src/client/services/Web3Service.js +++ b/packages/extension/src/client/services/Web3Service.js @@ -11,10 +11,6 @@ class ClientWeb3Service extends Web3Service { subscribeProfileListeners() { if (window.ethereum) { - // TODO - to be removed - // https://metamask.github.io/metamask-docs/API_Reference/Ethereum_Provider#ethereum.autorefreshonnetworkchange-(to-be-removed) - window.ethereum.autoRefreshOnNetworkChange = false; - window.ethereum.on('accountsChanged', (accounts) => { this.eventListeners.notify('profile', 'accountChanged', accounts[0]); }); diff --git a/packages/extension/src/utils/Web3Service.js b/packages/extension/src/utils/Web3Service.js index 10deefd59..544b1bca3 100644 --- a/packages/extension/src/utils/Web3Service.js +++ b/packages/extension/src/utils/Web3Service.js @@ -40,6 +40,9 @@ class Web3Service { } } else { provider = window.ethereum; + // TODO - to be removed + // https://metamask.github.io/metamask-docs/API_Reference/Ethereum_Provider#ethereum.autorefreshonnetworkchange-(to-be-removed) + provider.autoRefreshOnNetworkChange = false; } if (!provider) { From 602cbfe03193dec673e07ada8ddd9cb8fdf2045b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 11:52:55 +0000 Subject: [PATCH 06/10] fix(sdk): don't recreate background frame when switching accounts --- packages/extension/src/background/utils/connection.js | 5 +++-- .../extension/src/client/services/ConnectionService/index.js | 3 ++- packages/extension/src/utils/Iframe.js | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/extension/src/background/utils/connection.js b/packages/extension/src/background/utils/connection.js index 97cb154fe..119393311 100644 --- a/packages/extension/src/background/utils/connection.js +++ b/packages/extension/src/background/utils/connection.js @@ -128,7 +128,7 @@ class Connection { webClientId, }); - await this.uiFrame.ensureCreated(); + const frame = await this.uiFrame.ensureCreated(); this.openUi({ requestId, @@ -141,13 +141,14 @@ class Connection { }, }); - this.uiFrame.frame.contentWindow.postMessage({ + frame.contentWindow.postMessage({ type: sendActionEvent, action: { ...action, data: args, }, }, '*'); + loadingElem.style.display = 'none'; uiContainer.style.display = 'block'; this.uiFrame.open(); diff --git a/packages/extension/src/client/services/ConnectionService/index.js b/packages/extension/src/client/services/ConnectionService/index.js index bf5ae08be..ee91efa7d 100644 --- a/packages/extension/src/client/services/ConnectionService/index.js +++ b/packages/extension/src/client/services/ConnectionService/index.js @@ -39,6 +39,7 @@ class ConnectionService { constructor() { this.clientId = randomId(); this.setInitialVars(); + backgroundFrame.init(); } setInitialVars() { @@ -77,7 +78,7 @@ class ConnectionService { } = clientProfile; this.apiKey = apiKey; - const frame = await backgroundFrame.init(); + const frame = await backgroundFrame.ensureCreated(); const backgroundResponse = fromEvent(window, 'message') .pipe( diff --git a/packages/extension/src/utils/Iframe.js b/packages/extension/src/utils/Iframe.js index 98c2ee918..8d528a4b7 100644 --- a/packages/extension/src/utils/Iframe.js +++ b/packages/extension/src/utils/Iframe.js @@ -48,7 +48,7 @@ export default class Iframe { async ensureCreated() { return new Promise((resolve) => { if (this.frameReady) { - resolve(); + resolve(this.frame); } else { this.onReadyCallbacks.push(resolve); } @@ -61,6 +61,8 @@ export default class Iframe { return null; } + this.frameReady = false; + // clear previous unresolved init this.unbindAwaitFrameReady(); From 51866e82b41fdc1d3ce3e0f27f161cdd30c6614b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 13:24:21 +0000 Subject: [PATCH 07/10] fix(sdk): don't add custom deployed contract to Web3Service --- packages/extension/src/utils/Web3Service.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/extension/src/utils/Web3Service.js b/packages/extension/src/utils/Web3Service.js index 544b1bca3..07642ab44 100644 --- a/packages/extension/src/utils/Web3Service.js +++ b/packages/extension/src/utils/Web3Service.js @@ -212,13 +212,9 @@ class Web3Service { async deploy(config, constructorArguments = []) { const { - contractName, abi, bytecode, } = config; - if (!this.abis[contractName]) { - this.registerInterface(config); - } const contractObj = new this.web3.eth.Contract(abi); contractObj.options.data = bytecode; @@ -249,7 +245,11 @@ class Web3Service { const { contractAddress, } = transactionReceipt; - const contract = this.deployed(contractName, contractAddress); + const contract = new this.web3.eth.Contract( + abi, + contractAddress, + ); + contract.address = contractAddress; resolve(contract); } else if (error) { clearInterval(interval); From c73ba2f7cebd444099e836830aa260d1a657b544 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 13:40:33 +0000 Subject: [PATCH 08/10] feat(sdk): parse integer input to be the correct type --- packages/extension/src/client/apis/ZkAsset.js | 30 ++++++++++--------- .../src/client/utils/parseInputInteger.js | 12 ++++++++ .../client/utils/parseInputTransactions.js | 12 ++++++++ 3 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 packages/extension/src/client/utils/parseInputInteger.js create mode 100644 packages/extension/src/client/utils/parseInputTransactions.js diff --git a/packages/extension/src/client/apis/ZkAsset.js b/packages/extension/src/client/apis/ZkAsset.js index 4c43f38d1..351bb7819 100644 --- a/packages/extension/src/client/apis/ZkAsset.js +++ b/packages/extension/src/client/apis/ZkAsset.js @@ -3,6 +3,8 @@ 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 = [ @@ -197,8 +199,8 @@ export default class ZkAsset { { proofType: 'DEPOSIT_PROOF', assetAddress: this.address, - transactions, - numberOfOutputNotes, + transactions: parseInputTransactions(transactions), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), userAccess, }, ); @@ -238,9 +240,9 @@ export default class ZkAsset { { proofType: 'WITHDRAW_PROOF', assetAddress: this.address, - amount, + amount: parseInputInteger(amount), to: to || address, - numberOfInputNotes, + numberOfInputNotes: parseInputInteger(numberOfInputNotes), }, ); }; @@ -274,9 +276,9 @@ export default class ZkAsset { { proofType: 'TRANSFER_PROOF', assetAddress: this.address, - transactions, - numberOfInputNotes, - numberOfOutputNotes, + transactions: parseInputTransactions(transactions), + numberOfInputNotes: parseInputInteger(numberOfInputNotes), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), userAccess, }, ); @@ -395,10 +397,10 @@ export default class ZkAsset { { proofType: 'CREATE_NOTE_FROM_BALANCE_PROOF', assetAddress: this.address, - amount, + amount: parseInputInteger(amount), userAccess, - numberOfInputNotes, - numberOfOutputNotes, + numberOfInputNotes: parseInputInteger(numberOfInputNotes), + numberOfOutputNotes: parseInputInteger(numberOfOutputNotes), }, ) || {}; @@ -429,10 +431,10 @@ export default class ZkAsset { 'fetchNotesFromBalance', { assetAddress: this.address, - greaterThan, - lessThan, - equalTo, - numberOfNotes, + greaterThan: parseInputInteger(greaterThan), + lessThan: parseInputInteger(lessThan), + equalTo: parseInputInteger(equalTo), + numberOfNotes: parseInputInteger(numberOfNotes), }, ); } diff --git a/packages/extension/src/client/utils/parseInputInteger.js b/packages/extension/src/client/utils/parseInputInteger.js new file mode 100644 index 000000000..f9a74fc38 --- /dev/null +++ b/packages/extension/src/client/utils/parseInputInteger.js @@ -0,0 +1,12 @@ +export default function parseInputInteger(val) { + if (typeof val === 'string') { + if (val === '') { + return undefined; + } + if (val.trim().match(/^[0-9]{1,}$/)) { + return parseInt(val, 10); + } + } + + return val; +} diff --git a/packages/extension/src/client/utils/parseInputTransactions.js b/packages/extension/src/client/utils/parseInputTransactions.js new file mode 100644 index 000000000..cdac1335d --- /dev/null +++ b/packages/extension/src/client/utils/parseInputTransactions.js @@ -0,0 +1,12 @@ +import parseInputInteger from './parseInputInteger'; + +export default function parseInputTransactions(transactions) { + if (!Array.isArray(transactions)) { + return transactions; + } + + return transactions.map(tx => ({ + ...tx, + amount: parseInputInteger(tx.amount), + })); +} From 0c6410b7d48b95cb73e04be514d3bfa1b2cf4758 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 13:48:14 +0000 Subject: [PATCH 09/10] fix(sdk): update demo to adopt the latest api spec --- packages/extension/demo/1_apis-usage/asset.js | 85 +++++-------------- .../extension/demo/1_apis-usage/index.html | 4 +- 2 files changed, 25 insertions(+), 64 deletions(-) diff --git a/packages/extension/demo/1_apis-usage/asset.js b/packages/extension/demo/1_apis-usage/asset.js index addcfd040..d33b7b1ef 100644 --- a/packages/extension/demo/1_apis-usage/asset.js +++ b/packages/extension/demo/1_apis-usage/asset.js @@ -90,6 +90,8 @@ } async function approveAllowance() { + allowanceStatus.clear(); + const allowanceInput = document.getElementById('erc20-allowance-value'); const value = parseInt(allowanceInput.value); if (!value) { @@ -97,8 +99,6 @@ return; } - allowanceStatus.clear(); - const registryAddress = window.aztec.web3.getAddress('AccountRegistry'); const erc20Address = asset.linkedTokenAddress; await window.aztec.web3 @@ -115,18 +115,17 @@ } async function deposit() { - const numberOfOutputNotes = parseInt(document.getElementById('deposit-output-number').value, 10); - const toAddress = document.getElementById('deposit-to-address').value; - const depositInput = document.getElementById('deposit-value'); - const value = parseInt(depositInput.value, 10); - depositStatus.clear(); + const numberOfOutputNotes = document.getElementById('deposit-output-number').value; + const toAddress = document.getElementById('deposit-to-address').value; + const amount = document.getElementById('deposit-value').value; + try { const resp = await asset.deposit( [ { - amount: value, + amount, to: toAddress, }, ], @@ -136,7 +135,6 @@ ); console.log('>> deposit response', resp); refreshAssetBalances(); - depositInput.value = ''; } catch (error) { console.error(error); depositStatus.error(error.message); @@ -144,18 +142,15 @@ } async function withdraw() { - const withdrawInput = document.getElementById('withdraw-value'); - const toAddress = document.getElementById('withdraw-to-address').value; - const numberOfInputNotes = parseInt(document.getElementById('withdraw-input-number').value, 10); - const value = parseInt(withdrawInput.value, 10); - withdrawStatus.clear(); - const account = window.aztec.web3.getAccount(); + const amount = document.getElementById('withdraw-value').value; + const toAddress = document.getElementById('withdraw-to-address').value; + const numberOfInputNotes = document.getElementById('withdraw-input-number').value; try { const resp = await asset.withdraw( - value, + amount, { to: toAddress, numberOfInputNotes, @@ -163,7 +158,6 @@ ); console.log('>> withdraw response', resp); refreshAssetBalances(); - withdrawInput.value = ''; } catch (error) { console.error(error); withdrawStatus.error(error.message); @@ -171,28 +165,19 @@ } async function send() { - let numberOfInputNotes = document.getElementById('send-input-number').value.trim(); - numberOfInputNotes = numberOfInputNotes === '' - ? undefined - : parseInt(numberOfInputNotes); - let numberOfOutputNotes = document.getElementById('send-output-number').value.trim(); - numberOfOutputNotes = numberOfOutputNotes === '' - ? undefined - : parseInt(numberOfOutputNotes); - const valueInput = document.getElementById('send-value'); - const address = document.getElementById('send-address').value.trim(); - const value = parseInt(valueInput.value.trim(), 10); - sendStatus.clear(); - const account = window.aztec.web3.getAccount(); + const numberOfInputNotes = document.getElementById('send-input-number').value; + const numberOfOutputNotes = document.getElementById('send-output-number').value; + const amount = document.getElementById('send-value').value; + const address = document.getElementById('send-address').value; try { const resp = await asset.send( [ { to: address, - amount: value, + amount, }, ], { @@ -202,7 +187,6 @@ ); console.log('>> send response', resp); refreshAssetBalances(); - valueInput.value = ''; } catch (error) { console.error(error); sendStatus.error(error.message); @@ -212,16 +196,9 @@ async function createNoteFromBalance() { createStatus.clear(); - let numberOfInputNotes = document.getElementById('create-input-number').value.trim(); - numberOfInputNotes = numberOfInputNotes === '' - ? undefined - : parseInt(numberOfInputNotes); - let numberOfOutputNotes = document.getElementById('create-output-number').value.trim(); - numberOfOutputNotes = numberOfOutputNotes === '' - ? undefined - : parseInt(numberOfOutputNotes); - const valueInput = document.getElementById('create-amount'); - const value = parseInt(valueInput.value.trim()); + const numberOfInputNotes = document.getElementById('create-input-number').value; + const numberOfOutputNotes = document.getElementById('create-output-number').value; + const value = document.getElementById('create-amount').value; const userAccess = []; for (let i = 0; i < 10; i += 1) { const elem = document.getElementById(`create-access-${i}`); @@ -231,8 +208,6 @@ } } - const account = window.aztec.web3.getAccount(); - try { const resp = await asset.createNoteFromBalance( value, @@ -242,10 +217,8 @@ numberOfOutputNotes, }, ); - console.log('>> create note from balance response', resp); refreshAssetBalances(); - valueInput.value = ''; } catch (error) { console.error(error); createStatus.error(error.message); @@ -255,22 +228,10 @@ async function fetchNotesFromBalance() { fetchStatus.clear(); - let equalTo = document.getElementById('fetch-eq-value').value.trim(); - equalTo = equalTo === '' - ? undefined - : parseInt(equalTo); - let greaterThan = document.getElementById('fetch-gt-value').value.trim(); - greaterThan = greaterThan === '' - ? undefined - : parseInt(greaterThan); - let lessThan = document.getElementById('fetch-lt-value').value.trim(); - lessThan = lessThan === '' - ? undefined - : parseInt(lessThan); - let numberOfNotes = document.getElementById('fetch-count-value').value.trim(); - numberOfNotes = numberOfNotes === '' - ? undefined - : parseInt(numberOfNotes); + const equalTo = document.getElementById('fetch-eq-value').value; + const greaterThan = document.getElementById('fetch-gt-value').value; + const lessThan = document.getElementById('fetch-lt-value').value; + const numberOfNotes = document.getElementById('fetch-count-value').value; let notes; try { diff --git a/packages/extension/demo/1_apis-usage/index.html b/packages/extension/demo/1_apis-usage/index.html index 23b3caab0..3720c7a2f 100644 --- a/packages/extension/demo/1_apis-usage/index.html +++ b/packages/extension/demo/1_apis-usage/index.html @@ -13,9 +13,9 @@ function handleReload(type, value) { let message; if (type === 'accountChanged') { - message = `Switching account to ${value}...`; + message = `Switching account to ${value.address}...`; } else if (type === 'networkChanged') { - message = `Switching network to ${value}...`; + message = `Switching network to ${value.name} (${value.id})...`; } else { message = 'Signing in to AZTEC account...'; } From ccb3911b1e7c8adaa565a0a691d6a4e6cb463d7e Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 13 Feb 2020 15:18:49 +0000 Subject: [PATCH 10/10] feat(sdk): show custom metadata approval in ui --- .../apis/account/batchGetExtensionAccount.js | 6 +- .../ui/apis/proof/createNoteFromBalance.js | 16 +-- .../extension/src/ui/apis/proof/deposit.js | 24 ++-- .../components/AnimatedBlocks/EntityBlock.jsx | 2 +- .../src/ui/components/RecipientList/index.jsx | 109 ++++++++++++------ packages/extension/src/ui/locales/en/note.js | 6 + packages/extension/src/ui/pages/Deposit.jsx | 4 +- packages/extension/src/ui/pages/Send.jsx | 4 +- .../ui/views/CreateNoteFromBalanceContent.jsx | 17 +-- .../extension/src/ui/views/DepositContent.jsx | 27 ++++- .../src/ui/views/GrantNoteAccessContent.jsx | 18 +-- .../extension/src/ui/views/SendContent.jsx | 34 +++--- .../src/ui/views/WithdrawContent.jsx | 4 +- 13 files changed, 167 insertions(+), 104 deletions(-) diff --git a/packages/extension/src/ui/apis/account/batchGetExtensionAccount.js b/packages/extension/src/ui/apis/account/batchGetExtensionAccount.js index af33950bf..98f0a0ed9 100644 --- a/packages/extension/src/ui/apis/account/batchGetExtensionAccount.js +++ b/packages/extension/src/ui/apis/account/batchGetExtensionAccount.js @@ -1,12 +1,12 @@ +import uniq from 'lodash/uniq'; import getExtensionAccount from './getExtensionAccount'; export default async function batchGetExtensionAccount(addresses) { - const uniqueAddresses = addresses - .filter((addr, idx, arr) => arr.indexOf(addr) === idx); + const uniqueAddresses = uniq(addresses); const accountMapping = {}; await Promise.all(uniqueAddresses.map(async (addr) => { accountMapping[addr] = await getExtensionAccount(addr); })); - return addresses.map(addr => accountMapping[addr]); + return uniqueAddresses.map(addr => accountMapping[addr]); } diff --git a/packages/extension/src/ui/apis/proof/createNoteFromBalance.js b/packages/extension/src/ui/apis/proof/createNoteFromBalance.js index 1fe4bb8c4..0ffa6c8a9 100644 --- a/packages/extension/src/ui/apis/proof/createNoteFromBalance.js +++ b/packages/extension/src/ui/apis/proof/createNoteFromBalance.js @@ -3,6 +3,7 @@ import { ProofUtils, } from 'aztec.js'; import { keccak256 } from 'web3-utils'; +import uniqBy from 'lodash/uniqBy'; import { METADATA_AZTEC_DATA_LENGTH, } from '~/config/constants'; @@ -164,14 +165,15 @@ export default async function createNoteFromBalance({ address: to, linkedPublicKey, }; - const userAccess = !userAccessAccounts + const userAccess = !userAccessAccounts.length ? ownerAccess - : [ - ...userAccessAccounts, - ownerAccess, - ].filter((access, i, arr) => i === arr.findIndex(({ - address, - }) => address === access.address)); + : uniqBy( + [ + ...userAccessAccounts, + ownerAccess, + ], + 'address', + ); const newNotes = await createNotes( values, spendingPublicKey, diff --git a/packages/extension/src/ui/apis/proof/deposit.js b/packages/extension/src/ui/apis/proof/deposit.js index 9b040cb5b..a8788ea25 100644 --- a/packages/extension/src/ui/apis/proof/deposit.js +++ b/packages/extension/src/ui/apis/proof/deposit.js @@ -2,6 +2,7 @@ import { JoinSplitProof, ProofUtils, } from 'aztec.js'; +import uniqBy from 'lodash/uniqBy'; import { randomSumArray, } from '~/utils/random'; @@ -24,15 +25,19 @@ export default async function deposit({ ? numberOfOutputNotes : await settings('NUMBER_OF_OUTPUT_NOTES'); + const accountMapping = {}; const addresses = transactions.map(({ to }) => to); const accounts = await batchGetExtensionAccount(addresses); + accounts.forEach((account) => { + accountMapping[account.address] = account; + }); const outputTransactionNotes = await Promise.all( transactions.map(async ({ amount, to, numberOfOutputNotes: txNumberOfOutputNotes, - }, i) => { + }) => { const noteValues = randomSumArray( amount, txNumberOfOutputNotes || numberOfNotes, @@ -40,19 +45,20 @@ export default async function deposit({ const { linkedPublicKey, spendingPublicKey, - } = accounts[i] || {}; + } = accountMapping[to]; const ownerAccess = { address: to, linkedPublicKey, }; - const userAccess = !userAccessAccounts + const userAccess = !userAccessAccounts.length ? ownerAccess - : [ - ...userAccessAccounts, - ownerAccess, - ].filter((access, idx, arr) => idx === arr.findIndex(({ - address, - }) => address === access.address)); + : uniqBy( + [ + ...userAccessAccounts, + ownerAccess, + ], + 'address', + ); const notes = await createNotes( noteValues, spendingPublicKey, diff --git a/packages/extension/src/ui/components/AnimatedBlocks/EntityBlock.jsx b/packages/extension/src/ui/components/AnimatedBlocks/EntityBlock.jsx index 6580f9754..1778d4f2b 100644 --- a/packages/extension/src/ui/components/AnimatedBlocks/EntityBlock.jsx +++ b/packages/extension/src/ui/components/AnimatedBlocks/EntityBlock.jsx @@ -98,7 +98,7 @@ const EntityBlock = ({ )} {!!extraContent && (
- + {extraContent}
diff --git a/packages/extension/src/ui/components/RecipientList/index.jsx b/packages/extension/src/ui/components/RecipientList/index.jsx index 55da28975..9987ad1ba 100644 --- a/packages/extension/src/ui/components/RecipientList/index.jsx +++ b/packages/extension/src/ui/components/RecipientList/index.jsx @@ -3,50 +3,91 @@ import PropTypes from 'prop-types'; import { Offset, Block, + Text, } from '@aztec/guacamole-ui'; import ListItem from '~/ui/components/ListItem'; import HashText from '~/ui/components/HashText'; const RecipientList = ({ className, + title, + description, recipients, -}) => ( - - {recipients.map(({ - address, - footnote, - }, i) => ( - - - )} - size="xxs" - footnote={footnote} - /> +}) => { + const recipientNodes = ( + + {recipients.map(({ + address, + footnote, + }, i) => ( + + + )} + size="xxs" + footnote={footnote} + /> + + ))} + + ); + + if (!title && !description) { + return ( + + {recipientNodes} + + ); + } + + return ( + + {!!title && ( + + + + )} + + {recipientNodes} - ))} - -); + {!!description && ( + + + + )} + + ); +}; RecipientList.propTypes = { className: PropTypes.string, + title: PropTypes.string, + description: PropTypes.string, recipients: PropTypes.arrayOf(PropTypes.shape({ address: PropTypes.string.isRequired, footnote: PropTypes.oneOfType([ @@ -58,6 +99,8 @@ RecipientList.propTypes = { RecipientList.defaultProps = { className: '', + title: '', + description: '', }; export default RecipientList; diff --git a/packages/extension/src/ui/locales/en/note.js b/packages/extension/src/ui/locales/en/note.js index f5ff6cfff..54df5a994 100644 --- a/packages/extension/src/ui/locales/en/note.js +++ b/packages/extension/src/ui/locales/en/note.js @@ -35,6 +35,12 @@ export default { description: `If everything looks good hit send! `, }, + user: { + _: 'Access', + description: `The above user will be granted view access to the new zkTokens. + It will not allow the zkTokens to be spent without a signature from their recipient's MetaMask account. + `, + }, }, sign: { title: 'Approve Note Spending', diff --git a/packages/extension/src/ui/pages/Deposit.jsx b/packages/extension/src/ui/pages/Deposit.jsx index 13a137fb3..6e161c275 100644 --- a/packages/extension/src/ui/pages/Deposit.jsx +++ b/packages/extension/src/ui/pages/Deposit.jsx @@ -36,7 +36,9 @@ const Deposit = ({ const asset = await makeAsset(assetAddress); const parsedTransactions = parseInputTransactions(transactions); const amount = parsedTransactions.reduce((sum, tx) => sum + tx.amount, 0); - const userAccessAccounts = await apis.account.batchGetExtensionAccount(userAccess); + const userAccessAccounts = userAccess + ? await apis.account.batchGetExtensionAccount(userAccess) + : []; let allowanceSpender = Web3Service.getAddress('AccountRegistry'); let publicOwner = allowanceSpender; diff --git a/packages/extension/src/ui/pages/Send.jsx b/packages/extension/src/ui/pages/Send.jsx index 19a436f4d..ad5eb9db5 100644 --- a/packages/extension/src/ui/pages/Send.jsx +++ b/packages/extension/src/ui/pages/Send.jsx @@ -37,7 +37,9 @@ const Send = ({ const asset = await makeAsset(assetAddress); const parsedTransactions = parseInputTransactions(transactions); const amount = parsedTransactions.reduce((sum, tx) => sum + tx.amount, 0); - const userAccessAccounts = await apis.account.batchGetExtensionAccount(userAccess); + const userAccessAccounts = userAccess + ? await apis.account.batchGetExtensionAccount(userAccess) + : []; return { steps, diff --git a/packages/extension/src/ui/views/CreateNoteFromBalanceContent.jsx b/packages/extension/src/ui/views/CreateNoteFromBalanceContent.jsx index 4bbac4971..363d37404 100644 --- a/packages/extension/src/ui/views/CreateNoteFromBalanceContent.jsx +++ b/packages/extension/src/ui/views/CreateNoteFromBalanceContent.jsx @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Block, - Text, SVG, } from '@aztec/guacamole-ui'; import { @@ -96,18 +95,10 @@ class CreateNoteFromBalanceContent extends StepContentHelper { type: 'asset', }, extraContent: ( - - - - - - - - + ), }; } diff --git a/packages/extension/src/ui/views/DepositContent.jsx b/packages/extension/src/ui/views/DepositContent.jsx index 6b03c9d9a..0dbb07880 100644 --- a/packages/extension/src/ui/views/DepositContent.jsx +++ b/packages/extension/src/ui/views/DepositContent.jsx @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Block, Text, } from '@aztec/guacamole-ui'; import { @@ -29,6 +28,7 @@ class DepositContent extends StepContentHelper { asset, amount, transactions, + userAccessAccounts, loading, error, } = this.props; @@ -112,11 +112,22 @@ class DepositContent extends StepContentHelper { ...asset, type: 'asset', }, - extraContent: ( - - - - ), + extraContent: [ + , + currentStep === 0 && userAccessAccounts.length + ? ( + + ) + : null, + ], }, ]; } @@ -145,10 +156,14 @@ DepositContent.propTypes = { asset: assetShape.isRequired, amount: PropTypes.number.isRequired, transactions: PropTypes.arrayOf(transactionShape).isRequired, + userAccessAccounts: PropTypes.arrayOf(PropTypes.shape({ + address: PropTypes.string.isRequired, + })), }; DepositContent.defaultProps = { titleKey: 'deposit.title', + userAccessAccounts: [], }; export default DepositContent; diff --git a/packages/extension/src/ui/views/GrantNoteAccessContent.jsx b/packages/extension/src/ui/views/GrantNoteAccessContent.jsx index 00c03b8ff..69dca1b39 100644 --- a/packages/extension/src/ui/views/GrantNoteAccessContent.jsx +++ b/packages/extension/src/ui/views/GrantNoteAccessContent.jsx @@ -1,8 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Block, - Text, SVG, } from '@aztec/guacamole-ui'; import { @@ -90,18 +88,10 @@ class GrantNoteAccessContent extends StepContentHelper { type: 'asset', }, extraContent: ( - - - - - - - - + ), }; } diff --git a/packages/extension/src/ui/views/SendContent.jsx b/packages/extension/src/ui/views/SendContent.jsx index b3faf7494..ef58f83c5 100644 --- a/packages/extension/src/ui/views/SendContent.jsx +++ b/packages/extension/src/ui/views/SendContent.jsx @@ -30,6 +30,7 @@ class SendContent extends StepContentHelper { asset, amount, transactions, + userAccessAccounts, } = this.props; const currentStepName = steps[currentStep].name; @@ -87,20 +88,23 @@ class SendContent extends StepContentHelper { ...asset, type: 'asset', }, - extraContent: ( - - - , + currentStep === 0 && userAccessAccounts.length + ? ( + - - - - - - ), + ) + : null, + ], }; } @@ -161,6 +165,9 @@ SendContent.propTypes = { asset: assetShape.isRequired, amount: PropTypes.number.isRequired, transactions: PropTypes.arrayOf(transactionShape).isRequired, + userAccessAccounts: PropTypes.arrayOf(PropTypes.shape({ + address: PropTypes.string.isRequired, + })), spender: PropTypes.string.isRequired, proofHash: PropTypes.string, }; @@ -168,6 +175,7 @@ SendContent.propTypes = { SendContent.defaultProps = { titleKey: 'send.title', proofHash: '', + userAccessAccounts: [], }; export default SendContent; diff --git a/packages/extension/src/ui/views/WithdrawContent.jsx b/packages/extension/src/ui/views/WithdrawContent.jsx index 876e34bd5..07e28c85d 100644 --- a/packages/extension/src/ui/views/WithdrawContent.jsx +++ b/packages/extension/src/ui/views/WithdrawContent.jsx @@ -108,9 +108,7 @@ class WithdrawContent extends StepContentHelper { type: 'token', }, extraContent: ( - - - + ), }, ];