diff --git a/README.md b/README.md
index f0a1b84d8..fac2e7b6a 100644
--- a/README.md
+++ b/README.md
@@ -131,17 +131,6 @@ Under the current implementation, all stablecoins may choose to implement a proo
> A proof of reserve is, in very simple terms, an external feed that provides the backing of the tokens in real world. This may be FIAT or other assets.
-## Multisignature functionality
-
-The Stablecoin solution enables the management of a stablecoin through a multi-key account, where the admin key is configured as either a key list or a threshold key.
-
-When an operation (cash-in, burn, ...) is carried out using the _multisig_ mode, the corresponding transaction will not be directly submitted to the Hedera DLT, instead, it will be temporarily stored in a backend waiting for the multisig account key owners to sign it. Once it has been signed by all the required keys it will be available for submission.
-
-It's crucial to note that there is a time constraint for multisig transactions: they must be signed and submitted within three minutes of their initiation. If this timeframe is not met, the Hedera DLT will consider these transactions as expired and reject them.
-
-> The functionality has a limitation: Complex keys must have only one level, in other words, key list and threshold keys must contain only ED25519/ECDSA keys, they cannot contain firther key lists and/or threshold keys.
-
-
### Setting up a proof of reserve
During setup, it is possible to link an existing data feed by providing the smart contract's address, or create a new one based on our implementation. If a reserve was created during the stablecoin deployment, it will also be possible to edit the amount of the reserve.
@@ -160,6 +149,42 @@ In any case, the reserve address can be edited after creation. However, changing
For more information about the SDK and the methods to perform these operations, visit to the [docs](https://github.com/hashgraph/stablecoin-studio/tree/main/sdk#reserve-data-feed).
+## Multisignature functionality
+
+Hedera allows for the creation of accounts with complex key structures (__multi-key accounts__), enabling configurations that require multiple signatures from different ED25519 or ECDSA keys to authorize transactions.
+
+These accounts can use simple multi-signature setups or more sophisticated threshold key arrangements, where a specific number of approvals from a designated group of key holders is necessary to execute transactions. This functionality is ideal for enhancing security and governance in applications requiring collective decision-making.
+
+For more information about this type of account please check the official Hedera documentation about [key structures](https://docs.hedera.com/hedera/core-concepts/keys-and-signatures#key-structures).
+
+> If you need to deploy a brand new multikey account you can use our [script](https://github.com/hashgraph/stablecoin-studio/tree/main/sdk/scripts/CreateMultisigAccount.ts). Follow the instructions in the script itself (comment section at the begining)
+
+The Stablecoin solution enables the management of a stablecoin through multi-key accounts.
+
+When an operation (cash-in, burn, ...) is carried out using the _multisig_ mode, the corresponding transaction will not be directly submitted to the Hedera DLT, instead, it will be temporarily stored in a backend waiting for the multisig account key owners to sign it. Once it has been signed by all the required keys it will be available for submission.
+
+It's crucial to note that there is a time constraint for multisig transactions: they must be signed and submitted within three minutes of their initiation. If this timeframe is not met, the Hedera DLT will consider these transactions as expired and reject them.
+
+> The functionality has a limitation: Complex keys must have only one level, in other words, key list and threshold keys must contain only ED25519/ECDSA keys, they cannot contain further key lists and/or threshold keys.
+
+### Steps to deploy a multisig-managed stablecoin
+
+If you wish to deploy a stablecoin and fully manage it with a multisig account the steps to follow are:
+- Using a single key account, deploy a stablecoin assigning all roles and the proxy admin ownership to the multisig account
+- Once the stablecoin is deployed, assign the "admin" role to the multisig account.
+> The admin role is the only one that cannot be assigned automatically during the initial deployment
+- Remove the admin role from the single key account used to deploy the stablecoin
+> The admin role is automatically assigned to the deploying account
+- Connect to the stablecoin platform using the multisig account and manually import the deployed stablecoin
+> Since the deployment was carried out by another account, the multisig account was not associated to the token, that is the reason why you need to import it manually. It you associate your multisig account to the stablecoin's hedera token, you will not need to import it anymore.
+
+### Importing a multisig account key into a Wallet
+
+In order to manage a stablecoin using a multisig account we will need to, **for every single key _K_** in the multisig account's key list / threshold key, do as follows:
+- Create a single key account _A_ and set _K_ as its admin key
+- Import _A_ into Hashpack/Blade/Metamask/... depending on whether _K_ is an ED25519 or ECDSA key
+- Whenever we want to sign a multisig transaction using _K_, we will log into the wallet we used to import _A_ and carry out the signature.
+
# Architecture
The project is divided in 5 node modules:
diff --git a/backend/package-lock.json b/backend/package-lock.json
index c1de8fa5e..d18d0a111 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/stablecoin-npm-backend",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/stablecoin-npm-backend",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@hashgraph/sdk": "^2.43.0",
diff --git a/backend/package.json b/backend/package.json
index 7f243c00f..25b401dc7 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-backend",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "",
"author": "",
"license": "Apache-2.0",
diff --git a/cli/package-lock.json b/cli/package-lock.json
index bf02bbc7f..8f7ff4871 100644
--- a/cli/package-lock.json
+++ b/cli/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/stablecoin-npm-cli",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/stablecoin-npm-cli",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@hashgraph/stablecoin-npm-sdk": "file:./../sdk",
@@ -55,7 +55,7 @@
},
"../sdk": {
"name": "@hashgraph/stablecoin-npm-sdk",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@bladelabs/blade-web3.js": "^1.2.0",
diff --git a/cli/package.json b/cli/package.json
index 8317a75ec..e814a14b4 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-cli",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "CLI for Hedera Stablecoin",
"main": "./build/src/index.js",
"bin": {
diff --git a/contracts/package-lock.json b/contracts/package-lock.json
index c6e1fb408..a35b9c2e4 100644
--- a/contracts/package-lock.json
+++ b/contracts/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/stablecoin-npm-contracts",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/stablecoin-npm-contracts",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@chainlink/contracts": "^0.5.1",
diff --git a/contracts/package.json b/contracts/package.json
index 8707d900f..c0a027e65 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-contracts",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "",
"main": "./build/typechain-types/index.js",
"module": "./build/typechain-types/index.js",
diff --git a/defenders/package.json b/defenders/package.json
index 1cfc30af4..70c98bb09 100644
--- a/defenders/package.json
+++ b/defenders/package.json
@@ -1,6 +1,6 @@
{
"name": "accelerator-service",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "Accelerator integration with OZ Defenders",
"license": "Apache-2.0",
"devDependencies": {
diff --git a/hashconnect/lib/package-lock.json b/hashconnect/lib/package-lock.json
index 4900c566c..0e80aeada 100644
--- a/hashconnect/lib/package-lock.json
+++ b/hashconnect/lib/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/hashconnect",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/hashconnect",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@hashgraph/cryptography": "1.4.3",
diff --git a/hashconnect/lib/package.json b/hashconnect/lib/package.json
index 2e7628c19..c575d380a 100644
--- a/hashconnect/lib/package.json
+++ b/hashconnect/lib/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/hashconnect",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "hashconnect interoperability library",
"author": "Tyler Coté , Nick Hanna ",
"license": "Apache-2.0",
diff --git a/package.json b/package.json
index 3aaf433a1..6891e3121 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "hedera-stable-coin",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "stablecoin studio",
"scripts": {
"install": "node install.js && npm run build:cli:full && npm run prepare",
diff --git a/sdk/package-lock.json b/sdk/package-lock.json
index b025c5058..9eef78461 100644
--- a/sdk/package-lock.json
+++ b/sdk/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/stablecoin-npm-sdk",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/stablecoin-npm-sdk",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@bladelabs/blade-web3.js": "^1.2.0",
@@ -66,7 +66,7 @@
},
"../contracts": {
"name": "@hashgraph/stablecoin-npm-contracts",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@chainlink/contracts": "^0.5.1",
@@ -114,7 +114,7 @@
},
"../hashconnect/lib": {
"name": "@hashgraph/hashconnect",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@hashgraph/cryptography": "1.4.3",
diff --git a/sdk/package.json b/sdk/package.json
index 0157dc12b..5d80e5e73 100644
--- a/sdk/package.json
+++ b/sdk/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-npm-sdk",
- "version": "1.18.0",
+ "version": "1.19.0",
"description": "stablecoin studio SDK",
"main": "./build/cjs/src/index.js",
"module": "./build/esm/src/index.js",
@@ -45,6 +45,7 @@
"typescript": "^4.9.4"
},
"scripts": {
+ "execute:createMultisig": "node build/cjs/scripts/CreateMultisigAccount.js",
"start": "node build/src/index.js",
"clean": "rimraf coverage build",
"prebuild": "npm run lint",
diff --git a/sdk/scripts/CreateMultisigAccount.ts b/sdk/scripts/CreateMultisigAccount.ts
new file mode 100644
index 000000000..b28e6f3e0
--- /dev/null
+++ b/sdk/scripts/CreateMultisigAccount.ts
@@ -0,0 +1,97 @@
+/*
+ *
+ * Hedera Stablecoin SDK
+ *
+ * Copyright (C) 2023 Hedera Hashgraph, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * DESCRIPTION
+ * This script will deploy a multi-key account with a key list made of 2 keys:
+ * - one ED25519 key
+ * - one EDCSA key
+ *
+ * HOW TO RUN IT
+ * 1- Fill in the following constants : Multisig_ED25519_privateKey, Multisig_ECDSA_privateKey, deployingAccount
+ * 2- Compile the script : npm run build (this command will actually build all the typescript files in the module)
+ * 3- Run the compiled script : npm run execute:createMultisig
+ * 4- the multisig account id will be displayed in the console.
+ */
+
+import {
+ AccountCreateTransaction,
+ KeyList,
+ Client,
+ PrivateKey,
+ AccountId,
+} from '@hashgraph/sdk';
+
+// Hex encoded private key of the ED25519 key that will be added to the multisig account's key
+const Multisig_ED25519_privateKey = '';
+
+// Hex encoded private key of the ECDSA key that will be added to the multisig account's key
+const Multisig_ECDSA_privateKey = '';
+
+// Account Id and Hex encoded ECDSA private key of the single key account that will be used to deploy the multisig account.
+// MAKE SURE this account has funds as it will pay for the account creation fees !!!!!!!!!!!
+const deployingAccount = {
+ id: '',
+ ECDSA_privateKey: '',
+};
+
+const delay = async (seconds = 5): Promise => {
+ seconds = seconds * 1000;
+ await new Promise((r) => setTimeout(r, seconds));
+};
+
+async function createMultisigAccount(): Promise {
+ const signerKeys = [
+ PrivateKey.fromStringED25519(Multisig_ED25519_privateKey),
+ PrivateKey.fromStringECDSA(Multisig_ECDSA_privateKey),
+ ];
+
+ const keyList = KeyList.of(
+ signerKeys[0].publicKey,
+ signerKeys[1].publicKey,
+ );
+
+ const newAccountTx = new AccountCreateTransaction().setKey(keyList);
+
+ const client = Client.forTestnet().setOperator(
+ AccountId.fromString(deployingAccount.id),
+ PrivateKey.fromStringECDSA(deployingAccount.ECDSA_privateKey),
+ );
+
+ const newAccountResponse = await newAccountTx.execute(client);
+
+ await delay();
+
+ const newAccountReceipt = await newAccountResponse.getReceipt(client);
+ const newAccountId = newAccountReceipt.accountId;
+
+ const multisigAccountId = newAccountId!.toString();
+
+ return multisigAccountId;
+}
+
+// Main
+createMultisigAccount()
+ .then((events) => {
+ console.log(events);
+ })
+ .catch((error) => {
+ console.error(error);
+ });
diff --git a/sdk/tsconfig.json b/sdk/tsconfig.json
index e50895a72..21f9dff5b 100644
--- a/sdk/tsconfig.json
+++ b/sdk/tsconfig.json
@@ -18,5 +18,5 @@
"resolveJsonModule": true
},
"exclude": ["build/**/*", "node_modules", "example/**/*"],
- "include": ["src/**/*", "__tests__/**/*"]
+ "include": ["src/**/*", "__tests__/**/*", "scripts/**/*"]
}
diff --git a/web/README.md b/web/README.md
index 4a470ad43..7e9380e5d 100644
--- a/web/README.md
+++ b/web/README.md
@@ -67,7 +67,8 @@ The ENV file contains the following parameters:
- **REACT_APP_FACTORIES**: This var is only required if you want to create a new stablecoin. The var must be a JSON array with a factory proxy id in Hedera format `0.0.XXXXX` per environment. Regarding this, your can find the factories proxy's contract ids depending on the Stablecoin Studio versión [here](./../FACTORY_VERSION.md).
- **REACT_APP_MIRROR_NODE**: This var is required if you want to create a new stablecoin. The var must be a unique mirror node service for each Hedera network, and this is the service which would be used when the UI starts. The service is configured by the environment and the base url properties, and, optionally, can also have an api key and a http header through which the api key is provided.
- **REACT_APP_RPC_NODE**: This var is required if you want to create a new stablecoin. The var must be a unique rpc node service for Hedera network, and this is the service which would be used when the UI starts. The service is configured using the same properties than the mirror node. You can check the available JSON-RPC relays [here](https://github.com/hashgraph/stablecoin-studio/blob/main/README.md#JSON-RPC-Relays).
-- **REACT_APP_BACKEND_URL**: This var is only required if you want to enable multisignature functionality. It is the backend rest api endpoint.
+- **REACT_APP_BACKEND_URL**: This variable is only required if you want to enable multisignature functionality. It corresponds to the backend REST API endpoint.
+ > **Important:** If **REACT_APP_BACKEND_URL** is not set, the multisignature option will not be activated and therefore will not be displayed on the web interface.
- **REACT_APP_CONSENSUS_NODES**: This var is only required if you want to enable multisignature functionality. It is a list of consensus nodes per environment. When generating a multisignature transaction the first consensus node of the environment will be added to the transaction.
```bash
diff --git a/web/package-lock.json b/web/package-lock.json
index 54599e15e..79b254576 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@hashgraph/stablecoin-dapp",
- "version": "1.18.0",
+ "version": "1.19.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@hashgraph/stablecoin-dapp",
- "version": "1.18.0",
+ "version": "1.19.0",
"dependencies": {
"@chakra-ui/icons": "~2.0.17",
"@chakra-ui/react": "~2.6.1",
@@ -80,7 +80,7 @@
},
"../contracts": {
"name": "@hashgraph/stablecoin-npm-contracts",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@chainlink/contracts": "^0.5.1",
@@ -13175,7 +13175,7 @@
},
"../hashconnect/lib": {
"name": "@hashgraph/hashconnect",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@hashgraph/cryptography": "1.4.3",
@@ -21620,7 +21620,7 @@
},
"../sdk": {
"name": "@hashgraph/stablecoin-npm-sdk",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "Apache-2.0",
"dependencies": {
"@bladelabs/blade-web3.js": "^1.2.0",
diff --git a/web/package.json b/web/package.json
index 576154939..ebcc1045c 100644
--- a/web/package.json
+++ b/web/package.json
@@ -1,6 +1,6 @@
{
"name": "@hashgraph/stablecoin-dapp",
- "version": "1.18.0",
+ "version": "1.19.0",
"files": [
"build/"
],
@@ -9,10 +9,11 @@
"build": "react-app-rewired build",
"test": "react-app-rewired test --maxWorkers=50% --watchAll=false",
"test:watch": "react-app-rewired test --maxWorkers=50% --watchAll=true",
+ "test:update": "react-app-rewired test -u --maxWorkers=50% --watchAll=false",
"cleanCache": "react-app-rewired test --clearCache",
"eject": "react-app-rewired eject",
"lint": "eslint . --ext .ts --ext .mts",
- "prettier": "prettier --config .prettierrc --write .",
+ "prettier": "prettier --config .prettierrc --write . --fix",
"prettierCheck": "prettier --config .prettierrc --check",
"pre-commit": "npm run lint && npm run prettier",
"prepack": "npm run build"
diff --git a/web/src/Router/__test__/__snapshots__/Router.test.tsx.snap b/web/src/Router/__test__/__snapshots__/Router.test.tsx.snap
new file mode 100644
index 000000000..fb6041557
--- /dev/null
+++ b/web/src/Router/__test__/__snapshots__/Router.test.tsx.snap
@@ -0,0 +1,628 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` should render correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.0.49319786 - TEST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose a stablecoin to start operating!
+
+
+ You have not chosen a stablecoin yet.
+
+
+ Choose an item to operate.
+
+
+
+
+
+
+
+
+`;
diff --git a/web/src/app/__test__/__snapshots__/App.test.tsx.snap b/web/src/app/__test__/__snapshots__/App.test.tsx.snap
new file mode 100644
index 000000000..8ccbf6cc1
--- /dev/null
+++ b/web/src/app/__test__/__snapshots__/App.test.tsx.snap
@@ -0,0 +1,728 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` should render correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose stablecoin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose a stablecoin to start operating!
+
+
+ You have not chosen a stablecoin yet.
+
+
+ Choose an item to operate.
+
+
+
+
+
+
+
+
+`;
diff --git a/web/src/components/Form/__test__/__snapshots__/SelectController.test.tsx.snap b/web/src/components/Form/__test__/__snapshots__/SelectController.test.tsx.snap
new file mode 100644
index 000000000..00e3cf9ab
--- /dev/null
+++ b/web/src/components/Form/__test__/__snapshots__/SelectController.test.tsx.snap
@@ -0,0 +1,487 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` doesn't show error with showError=false: NotShowingError 1`] = `
+
+