From 41ea7ac83716d4b1836d33f9f3667b0797d575b1 Mon Sep 17 00:00:00 2001 From: Shjorty <201505261@post.au.dk> Date: Fri, 5 Jan 2024 10:59:21 +0100 Subject: [PATCH 1/5] Added migration to add euroe token + add token to accounts when created / restored --- .../browser-wallet/src/background/index.ts | 54 ++++++++++++++++++- .../browser-wallet/src/background/update.ts | 29 +++++++++- .../src/shared/constants/migrations.ts | 3 ++ .../src/shared/constants/token-metadata.ts | 23 ++++++++ .../src/shared/storage/access.ts | 2 + .../src/shared/storage/types.ts | 1 + 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 packages/browser-wallet/src/shared/constants/migrations.ts diff --git a/packages/browser-wallet/src/background/index.ts b/packages/browser-wallet/src/background/index.ts index f716cdf2..e4b719ca 100644 --- a/packages/browser-wallet/src/background/index.ts +++ b/packages/browser-wallet/src/background/index.ts @@ -13,17 +13,28 @@ import { sessionPasscode, storedAcceptedTerms, storedAllowlist, + storedCredentials, storedCurrentNetwork, + storedMigrations, storedSelectedAccount, + storedTokenMetadata, + storedTokens, } from '@shared/storage/access'; import { mainnet, stagenet, testnet } from '@shared/constants/networkConfiguration'; -import { ChromeStorageKey, NetworkConfiguration } from '@shared/storage/types'; +import { ChromeStorageKey, NetworkConfiguration, TokenStorage } from '@shared/storage/types'; import { getTermsAndConditionsConfig } from '@shared/utils/network-helpers'; import { parsePayload } from '@shared/utils/payload-helpers'; import { BackgroundSendTransactionPayload } from '@shared/utils/types'; import { buildURLwithSearchParameters } from '@shared/utils/url-helpers'; import { Buffer } from 'buffer/'; +import { Migrations } from '@shared/constants/migrations'; +import { + EUROE_MAINNET_INDEX, + EUROE_METADATA, + EUROE_TESTNET_INDEX, + euroeTokenStorage, +} from '@shared/constants/token-metadata'; import { startMonitoringPendingStatus } from './confirmation'; import { sendCredentialHandler } from './credential-deployment'; import { createIdProofHandler, runIfValidProof } from './id-proof'; @@ -152,11 +163,52 @@ async function migrateNetwork(network: NetworkConfiguration) { } } +/* + * Add the given token to all accounts of the given network, that don't already have it. + */ +async function addTokenToAccounts(network: NetworkConfiguration, contractIndex: number, token: TokenStorage) { + const tokens = await storedTokens.get(network.genesisHash); + const creds = await storedCredentials.get(network.genesisHash); + if (creds && creds.length > 0) { + const accountAddresses = creds.map((cred) => cred.address); + const newTokens = accountAddresses.reduce((accumulator, address) => { + const accTokens = tokens?.[address] || {}; + if (contractIndex in accTokens) { + accumulator[address] = accTokens; + } else { + accumulator[address] = { [contractIndex]: [token], ...accTokens }; + } + return accumulator; + }, {} as Record>); + await storedTokens.set(network.genesisHash, newTokens); + } +} + +/** + * Add euroe tokens to all accounts that don't already have it, if the migration have no already been run, and sets the euroe migration check. + */ +async function euroeMigration() { + const migrations = (await storedMigrations.get()) || []; + if (!migrations.includes(Migrations.euroe)) { + // Add metadata, if not present + const metadata = (await storedTokenMetadata.get()) || {}; + const { metadataLink } = euroeTokenStorage; + if (!(metadataLink in metadata)) { + metadata[metadataLink] = EUROE_METADATA; + await storedTokenMetadata.set(metadata); + } + await addTokenToAccounts(mainnet, EUROE_MAINNET_INDEX, euroeTokenStorage); + await addTokenToAccounts(testnet, EUROE_TESTNET_INDEX, euroeTokenStorage); + await storedMigrations.set([...migrations, Migrations.euroe]); + } +} + const startupHandler = async () => { const network = await storedCurrentNetwork.get(); if (network) { await migrateNetwork(network); await startMonitoringPendingStatus(network); + await euroeMigration(); } checkForNewTermsAndConditions(); diff --git a/packages/browser-wallet/src/background/update.ts b/packages/browser-wallet/src/background/update.ts index c07aa7a4..02a20b35 100644 --- a/packages/browser-wallet/src/background/update.ts +++ b/packages/browser-wallet/src/background/update.ts @@ -1,10 +1,13 @@ -import { storedCredentials, storedIdentities, useIndexedStorage } from '@shared/storage/access'; -import { addToList, editList } from '@shared/storage/update'; +import { storedCredentials, storedIdentities, storedTokens, useIndexedStorage } from '@shared/storage/access'; +import { addToList, editList, updateRecord } from '@shared/storage/update'; import { Identity, WalletCredential } from '@shared/storage/types'; import { identityMatch } from '@shared/utils/identity-helpers'; +import { EUROE_MAINNET_INDEX, EUROE_TESTNET_INDEX, euroeTokenStorage } from '@shared/constants/token-metadata'; +import { mainnet, testnet } from '@shared/constants/networkConfiguration'; const identityLock = 'concordium_identity_lock'; const credentialLock = 'concordium_credential_lock'; +const tokenLock = 'concordium_token_lock'; export async function addIdentity(identity: Identity | Identity[], genesisHash: string): Promise { return addToList( @@ -14,7 +17,29 @@ export async function addIdentity(identity: Identity | Identity[], genesisHash: ); } +// Add the euroe token to the credential(s) +async function addEuroeToken(cred: WalletCredential | WalletCredential[], genesisHash: string): Promise { + const storage = useIndexedStorage(storedTokens, async () => genesisHash); + const add = async (index: string) => { + for (const { address } of Array.isArray(cred) ? cred : [cred]) { + await updateRecord(tokenLock, storage, address, { [index]: [euroeTokenStorage] }); + } + }; + switch (genesisHash) { + case mainnet.genesisHash: + await add(EUROE_MAINNET_INDEX.toString()); + break; + case testnet.genesisHash: + await add(EUROE_TESTNET_INDEX.toString()); + break; + default: + } +} + export async function addCredential(cred: WalletCredential | WalletCredential[], genesisHash: string): Promise { + // All accounts should have euroe token added as default + addEuroeToken(cred, genesisHash); + return addToList( credentialLock, cred, diff --git a/packages/browser-wallet/src/shared/constants/migrations.ts b/packages/browser-wallet/src/shared/constants/migrations.ts new file mode 100644 index 00000000..e29d9758 --- /dev/null +++ b/packages/browser-wallet/src/shared/constants/migrations.ts @@ -0,0 +1,3 @@ +export enum Migrations { + euroe = "euroe_migration" +} diff --git a/packages/browser-wallet/src/shared/constants/token-metadata.ts b/packages/browser-wallet/src/shared/constants/token-metadata.ts index 663efd27..93930f6b 100644 --- a/packages/browser-wallet/src/shared/constants/token-metadata.ts +++ b/packages/browser-wallet/src/shared/constants/token-metadata.ts @@ -12,3 +12,26 @@ export const CCD_METADATA: TokenMetadata = { display: CCD_IMAGE, thumbnail: CCD_IMAGE, }; + +export const EUROE_METADATA: TokenMetadata = { + name: 'EUROe Stablecoin', + symbol: 'EUROe', + decimals: 6, + unique: false, + description: 'EUROe is a modern European stablecoin - a digital representation of fiat Euros.', + thumbnail: { + url: 'https://dev.euroe.com/persistent/token-icon/png/32x32.png', + }, + display: { + url: 'https://dev.euroe.com/persistent/token-icon/png/256x256.png', + }, + attributes: [], +}; + +export const euroeTokenStorage = { + id: '', + metadataLink: 'https://euroesolanametadadev.blob.core.windows.net/euroesolanametadatadev/metadata-concordium.json', +}; + +export const EUROE_MAINNET_INDEX = 9390; +export const EUROE_TESTNET_INDEX = 7260; diff --git a/packages/browser-wallet/src/shared/storage/access.ts b/packages/browser-wallet/src/shared/storage/access.ts index 3b31f115..3ed3b972 100644 --- a/packages/browser-wallet/src/shared/storage/access.ts +++ b/packages/browser-wallet/src/shared/storage/access.ts @@ -2,6 +2,7 @@ import { stringify } from '@concordium/browser-wallet-api/src/util'; import { parse } from '@shared/utils/payload-helpers'; import { VerifiableCredentialMetadata } from '@shared/utils/verifiable-credential-helpers'; import { Log } from '@shared/utils/log-helpers'; +import { Migrations } from '@shared/constants/migrations'; import { ChromeStorageKey, EncryptedData, @@ -237,3 +238,4 @@ export const sessionVerifiableCredentialMetadataUrls = makeIndexedStorageAccesso 'session', ChromeStorageKey.TemporaryVerifiableCredentialMetadataUrls ); +export const storedMigrations = makeStorageAccessor('local', ChromeStorageKey.Migrations); diff --git a/packages/browser-wallet/src/shared/storage/types.ts b/packages/browser-wallet/src/shared/storage/types.ts index 399c5121..0c58130f 100644 --- a/packages/browser-wallet/src/shared/storage/types.ts +++ b/packages/browser-wallet/src/shared/storage/types.ts @@ -41,6 +41,7 @@ export enum ChromeStorageKey { TemporaryVerifiableCredentialMetadataUrls = 'tempVerifiableCredentialMetadataUrls', Allowlist = 'allowlist', Log = 'log', + Migrations = 'migrations', } export enum Theme { From 63b7a9ad6b66931ed1168fb98efc3fa07dd416d8 Mon Sep 17 00:00:00 2001 From: Hjort Date: Mon, 8 Jan 2024 10:07:50 +0100 Subject: [PATCH 2/5] Fix type error --- packages/browser-wallet/src/popup/store/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/browser-wallet/src/popup/store/utils.ts b/packages/browser-wallet/src/popup/store/utils.ts index 6f5d26b0..52ee9192 100644 --- a/packages/browser-wallet/src/popup/store/utils.ts +++ b/packages/browser-wallet/src/popup/store/utils.ts @@ -33,6 +33,7 @@ import { sessionVerifiableCredentials, sessionVerifiableCredentialMetadataUrls, storedLog, + storedMigrations, } from '@shared/storage/access'; import { ChromeStorageKey } from '@shared/storage/types'; import { atom, PrimitiveAtom, WritableAtom } from 'jotai'; @@ -73,6 +74,7 @@ const accessorMap: Record> = { getGenesisHash ), [ChromeStorageKey.Log]: storedLog, + [ChromeStorageKey.Migrations]: storedMigrations, }; export function resetOnUnmountAtom(initial: V): PrimitiveAtom { From 688a60c89abf06a7c0f2ce0eee2afa5f3a5bbd70 Mon Sep 17 00:00:00 2001 From: Hjort Date: Mon, 8 Jan 2024 10:23:48 +0100 Subject: [PATCH 3/5] Fix lint error --- packages/browser-wallet/src/shared/constants/migrations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-wallet/src/shared/constants/migrations.ts b/packages/browser-wallet/src/shared/constants/migrations.ts index e29d9758..d446b7e1 100644 --- a/packages/browser-wallet/src/shared/constants/migrations.ts +++ b/packages/browser-wallet/src/shared/constants/migrations.ts @@ -1,3 +1,3 @@ export enum Migrations { - euroe = "euroe_migration" + euroe = 'euroe_migration', } From 4160f3f1e89cc203bb2aa08e903c46e625f40134 Mon Sep 17 00:00:00 2001 From: Hjort Date: Mon, 8 Jan 2024 10:47:55 +0100 Subject: [PATCH 4/5] Address feedback --- packages/browser-wallet/src/background/index.ts | 12 +++++++++--- packages/browser-wallet/src/background/update.ts | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/browser-wallet/src/background/index.ts b/packages/browser-wallet/src/background/index.ts index e4b719ca..5ba63814 100644 --- a/packages/browser-wallet/src/background/index.ts +++ b/packages/browser-wallet/src/background/index.ts @@ -185,7 +185,7 @@ async function addTokenToAccounts(network: NetworkConfiguration, contractIndex: } /** - * Add euroe tokens to all accounts that don't already have it, if the migration have no already been run, and sets the euroe migration check. + * Add euroe tokens to all accounts that don't already have it, if the migration has not atlready been run, and sets the euroe migration check. */ async function euroeMigration() { const migrations = (await storedMigrations.get()) || []; @@ -203,12 +203,18 @@ async function euroeMigration() { } } +async function runMigrations(network?: NetworkConfiguration) { + if (network) { + await migrateNetwork(network); + } + await euroeMigration(); +} + const startupHandler = async () => { const network = await storedCurrentNetwork.get(); + runMigrations(network); if (network) { - await migrateNetwork(network); await startMonitoringPendingStatus(network); - await euroeMigration(); } checkForNewTermsAndConditions(); diff --git a/packages/browser-wallet/src/background/update.ts b/packages/browser-wallet/src/background/update.ts index 02a20b35..6b5f35f5 100644 --- a/packages/browser-wallet/src/background/update.ts +++ b/packages/browser-wallet/src/background/update.ts @@ -33,6 +33,7 @@ async function addEuroeToken(cred: WalletCredential | WalletCredential[], genesi await add(EUROE_TESTNET_INDEX.toString()); break; default: + // The euroe Token only exists on mainnet and testnet, so for other networks we don't do anything. } } From 5e3b95391809e73c7e90fb1f23ba9a43bd0d24e5 Mon Sep 17 00:00:00 2001 From: Hjort Date: Mon, 8 Jan 2024 11:54:04 +0100 Subject: [PATCH 5/5] Bump version --- packages/browser-wallet/CHANGELOG.md | 6 ++++++ packages/browser-wallet/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/browser-wallet/CHANGELOG.md b/packages/browser-wallet/CHANGELOG.md index d0c96b0b..43f3ae00 100644 --- a/packages/browser-wallet/CHANGELOG.md +++ b/packages/browser-wallet/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.3.0 + +### Added + +- The EuroE token is now added to all accounts by default. + ## 1.2.1 ### Fixed diff --git a/packages/browser-wallet/package.json b/packages/browser-wallet/package.json index cd35ef40..4855083c 100644 --- a/packages/browser-wallet/package.json +++ b/packages/browser-wallet/package.json @@ -1,7 +1,7 @@ { "name": "@concordium/browser-wallet", "private": true, - "version": "1.2.1", + "version": "1.3.0", "description": "Browser extension wallet for the Concordium blockchain", "author": "Concordium Software", "license": "Apache-2.0",