
Security News
Crates.io Users Targeted by Phishing Emails
The Rust Security Response WG is warning of phishing emails from rustfoundation.dev targeting crates.io users.
@hashgraph/stablecoin-npm-contracts
Advanced tools
[](../LICENSE.md)
This module contains the solidity smart contracts used in the Hedera stablecoin project.
The Hedera Token Service (HTS) functionality required in this project is exposed through an HTS precompiled smart contract
implemented, deployed and managed by Hedera.
The smart contracts located in the hts-precompile
folder are used to interact with the HTS precompiled smart contract mentioned above, and have also been implemented and provided by Hedera. For more information about these contracts check the Hedera Service Solidity Library and the Hedera hts precompiled contracts gitHub repository:
HederaRespondeCodes.sol
: Contains the list of response codes the HTS precompiled smart contract methods return.IHederaTokenService.sol
: Interface implemented by the HTS precompiled smart contract. In order to execute an HTS operation, our smart contracts will need to instantiate this interface with the HTS precompiled smart contract address.The remaining smart contracts have been implemented for this project:
Contracts within the extensions
folder: one contract for each stablecoin operation.
BurnableFacet.sol
: implements the burn operation (burns tokens from the treasury account. Decreases the total supply).CashInFacet.sol
: implements the cash-in operation (mints new tokens and transfers them to an account. Increases the total supply).DeletableFacet.sol
: implements the delete operation (deletes the stablecoin's underlying token).FreezableFacet.sol
: implements the freeze and unfreeze operations (if the token is frozen for an account, this account will not be able to operate with the stablecoin until unfrozen).KYCFacet.sol
: implements the grantKyc and revokeKyc operations to grant or revoke the KYC flag to a Hedera account for the stablecoin.PausableFacet.sol
: implements the pause and unpause operations (if a token is paused, no one will be able to operate with it until unpaused).RescatableFacet.sol
: implements the rescue and rescueHBAR operations (transfers tokens and HBAR, respectively, from the treasury account—being the stablecoin’s smart contract—to another account).ReserveFacet.sol
: implements the reserve logic for the stablecoin (checks against the current reserve before minting, allows updating the reserve data feed, etc.).0.0.0
(zero address) to disable the reserve mechanism.RoleManagementFacet.sol
: implements the grantRoles and revokeRoles operations (grants and revokes multiple roles to/from multiple accounts in a single transaction).RolesFacet.sol
: contains the definition of the roles that can be assigned to each stablecoin.SupplierAdminFacet.sol
: implements the management of the cash-in role (assigning/removing the role and setting, increasing, or decreasing the cash-in limit).TokenOwnerFacet.sol
: stores the addresses of the HTS precompiled smart contract and the underlying token related to the stablecoin. All other facets rely on this.WipeableFacet.sol
: implements the wipe operation (burns tokens from any account. Decreases the total supply).HoldManagementFacet.sol
: implements the hold functionality, enabling temporary locking of tokens under the control of an escrow address. This is used in scenarios like secondary market trades or regulatory compliance.Important contracts within the resolver
folder:
BusinessLogicResolver.sol
: central contract that maps function selectors to facet addresses. All stablecoin proxies delegate the selector resolution to this resolver, enabling centralized upgradeability across all stablecoins.ResolverProxy.sol
: lightweight diamond clone that delegates execution to the correct facet based on the mapping returned by the BusinessLogicResolver
.BusinessLogicResolverWrapper.sol
: helper contract to simplify interaction with the resolver.HederaReserveFacet.sol
: implements the ChainLink AggregatorV3Interface to provide the current data about the stablecoin's reserve.
HederaTokenManagerFacet.sol
: defines the main logic to initialize and manage a stablecoin. It exposes key ERC-20-like read functions (name
, symbol
, decimals
, totalSupply
, balanceOf
) and supports on-chain metadata and token updates via HTS.
StableCoinFactoryFacet.sol
: implements the flow to create a new stablecoin. Every time a new stablecoin is created, several smart contracts must be deployed and initialized and an underlying token must be created through the HTS precompiled smart contract
. this multi-transaction process is encapsulated in this contract so that users can create new stablecoins in a single transaction. IMPORTANT : a factory contract will be deployed in tesnet for anybody to use. Users are also free to deploy and use their own factory contract.
These last three contracts have their own interfaces in the Interfaces
folder.
💡 Each stablecoin is deployed as a diamond clone (via
ResolverProxy
) and uses a sharedBusinessLogicResolver
to dynamically delegate logic calls. This enables centralized logic upgrades across all stablecoins with a single transaction.
These are the folders and files you can find in this project:
contracts
: The folder with the solidity files. Inside this folder you can also find the hts-precompile and the extensions folders, including this last one an interface folder, presented in the Overview section.docs
: Detailed documentation for each smart contract in the "contracts" folder.scripts
: Typescript files used to create new stablecoins and deploy required smart contracts. These files are used when testing.test
: Typescript tests files.typechain-types
: the most important thing in this folder are contract factories which are used not only for testing, but also by any other project importing the stablecoin solution. The content of this folder is autogenerated by hardhat-abi-exporter
plugin whenever the user compiles the contracts..env
: environment file used in tests execution..eslintrc.json
: ESLint tool configuration file for linting JavaScript code..solhint.json
: Solhint tool configuration file for linting solidity code.hardhat.SignatureServiceConfig.ts
: hardhat configuration file.package.json
: Node project configuration file.prettier.config.js
: several languages code formatter configuration file.README.md
Slither
: folder containing everything related to the slither analysis.tsconfig.json
: TypeScript configuration file.tslint.json
: TSLint tool configuration file for linting TypeScript code.The IDE we use in this project is Hardhat, in order to use it you must have:
The smart contract programming language is Solidity version 0.8.16.
First download and install the project dependencies :
cd contracts
. This will change your current working directory to the contracts
folder.npm install
. This will create and populate node_modules
.Then compile and build the contracts, you can choose one of the following options:
npm run compile
to compile the contracts that were modified after the last compilation (This will NOT build the package, you need to run step 3)npm run compile:force
to compile all the contracts (even those that were not modified after the last compilation) and build the package (you can skip step 3).npm run build
to build the package without compiling the contracts.The first two commands will generate a build
folder that contains a typechain-types
folder. This folder contains the contracts wrappers that allows us to access contracts abi importing the wrappers as shown below:
import { hederaTokenManager__factory } from '@hashgraph/stablecoin-npm-contracts/typechain-types';
Each test follows the arrange, act, assert pattern and is self-contained, ensuring full independence and allowing them to run in parallel and in any order.
Typescript test files are located in the test
folder and are organized into two parallel execution threads:
Thread0/
Thread1/
You need to create the .env
file cloning the content of .env.sample
and add two Hedera accounts that will be used for testing.
These accounts must be existing valid accounts in the Hedera network you are using to test the smart contracts, they must also have a positive balance large enough to run all the contract deployments, invocations and token creations executed in the tests.
For each account you must provide the Private Key (7647657eerr65....878)
Example for the Hedera testnet (fake data):
# * Accounts and Keys
# Private keys in RAW Format (Not DER)
# local
LOCAL_PRIVATE_KEY_0='0xEXAMPLEPRIVATEKEY0'
LOCAL_PRIVATE_KEY_1='0xEXAMPLEPRIVATEKEY1'
# testnet
TESTNET_PRIVATE_KEY_0='0xEXAMPLEPRIVATEKEY4'
TESTNET_PRIVATE_KEY_1='0xEXAMPLEPRIVATEKEY5'
# ... add more keys as needed
All tests will use the two above mentioned accounts.
Operator Account (PRIVATE_KEY_0)
: This is the account that will deploy the stablecoin used for testing. It will have full rights.Non Operator Account (PRIVATE_KEY_1)
: This is the account that will NOT deploy the stablecoin used for testing. It will have no rights to the stablecoin unless explicitly granted during the test.This project includes a suite of automated tests to validate stablecoin functionality. You can run all tests at once, in parallel, or focus on a specific test file.
Run all test files using the default configuration:
npm run test
To speed up the process, you can run all tests concurrently:
npm run test:parallel
Useful for CI environments or large test suites.
You can also run a single test file. For example, to run only the KYC-related tests:
npm run test:kyc
You can customize this command or create more aliases in package.json as needed.
To deploy the entire infrastructure required to support stablecoins, including all core facets, the factory, and the business logic resolver, use the provided programmatic setup via Hardhat.
This includes:
npx hardhat deployAll --network <network>
This deployment process:
HederaTokenManagerFacet
, ReserveFacet
, KYCFacet
, BurnableFacet
, RolesFacet
, and more.stableCoin
, reserve
, factory
), including selectors and interface IDs.ResolverProxy
is deployed and linked to the StableCoinFactory
, allowing it to dynamically use the registered logic.Flag | Description |
---|---|
--useDeployed | Reuse already deployed contracts if their addresses are known (default: true ). |
--privateKey | Use a raw private key as signer instead of local Hardhat account. |
--signerAddress | Specify signer by address from Hardhat signers array. |
--signerPosition | Specify signer by index in Hardhat signers array. |
The deployment of a stablecoin is managed through a custom Hardhat task: deployStableCoin. This command interacts with the StableCoinFactory and BusinessLogicResolver to initialize and deploy a fully functional stablecoin with optional metadata, roles, reserve configuration, and KYC settings.
npx hardhat deployStableCoin \
--businessLogicResolverProxyAddress <resolverProxy> \
--stableCoinFactoryProxyAddress <factoryProxy> \
--network <network>
Parameter | Description |
---|---|
--businessLogicResolverProxyAddress | Address of the deployed BusinessLogicResolver proxy |
--stableCoinFactoryProxyAddress | Address of the deployed StableCoinFactory proxy |
--network | Network where deploy the SC |
Note: If --useEnvironment is passed, many of the required addresses and defaults will be pulled from the internal Environment.ts.
npx hardhat deployStableCoin \
--tokenName "USD Token" \
--tokenSymbol "USDT" \
--tokenDecimals 6 \
--tokenInitialSupply 1000000 \
--tokenMaxSupply 10000000 \
--createReserve true \
--addKyc true \
--grantKYCToOriginalSender true \
--stableCoinConfigurationIdKey "" \
--stableCoinConfigurationIdVersion 1 \
--businessLogicResolverProxyAddress 0x123...abc \
--stableCoinFactoryProxyAddress 0x456...def \
--network testnet
This system uses a modular Diamond + Resolver pattern for managing upgradeable logic. Smart contracts delegate calls through a ResolverProxy, which dynamically fetches the latest logic version for a given component (e.g., stablecoin, reserve) from a centralized BusinessLogicResolver.
The BusinessLogicResolver:
To register a new list of logic contracts (facets) for any configuration key, use the following Hardhat task:
npx hardhat updateBusinessLogicKeys \
--resolverAddress <businessLogicResolverAddress> \
--implementationAddressList <commaSeparatedFacetAddresses> \
--privateKey <yourPrivateKey> \
--network <network>
Flag | Description |
---|---|
--resolverAddress | Address of the BusinessLogicResolver contract |
--implementationAddressList | Comma-separated list of facet contract addresses |
--privateKey | Private key of the account with permissions to update the resolver |
--network | Hardhat network to use |
Use this approach whenever:
For this to work, the BusinessLogicResolver must be initialized. If it's not yet initialized, use the initializeBusinessLogicResolver task first.
In order to migrate V1 Stablecoins to V2 you need to :
npm run install:all
cd contracts
npx hardhat deployAll --network NETWORK
owner
in your Stablecoin's Proxy admin
in the MAINNET_PRIVATE_KEY_0
, PREVIEWNET_PRIVATE_KEY_0
or TESTNET_PRIVATE_KEY_0
field of the contracts/.env
file.npx hardhat migrateStableCoinToV2 --network NETWORK --stablecoinconfigurationidkey CONFIG_ID --stablecoinconfigurationidversion CONFIG_VERSION --businesslogicresolverproxyaddress BLR --stablecoinaddress SC_PROXY --stablecoinproxyadminaddress SC_PROXY_ADMIN
Where
- NETWORK: the network you want to deploy the contracts (testnet, mainnet)
- CONFIG_ID: config id of the stablecoin (bytes32) you can use 0x0000000000000000000000000000000000000000000000000000000000000002 by default.
- CONFIG_VERSION: config version of the stablecoin (integer) you can use 1 by default.
- BLR: Business logic resolver proxy address (evm address) you can find it in contracts/contractAddresses_v2.txt file as "Business Logic Resolver Proxy"
- SC_PROXY: address of the stablecoin's proxy (evm address) You can find it in your StableCoin details (CLI or WEB) as "evmProxyAddress"
- SC_PROXY_ADMIN: address of the stablecoin's admin proxy (evm address) You can find it in your StableCoin (CLI or WEB) details as "evmProxyAdminAddress"
Example:
npx hardhat migrateStableCoinToV2 --network testnet --stablecoinconfigurationidkey 0x0000000000000000000000000000000000000000000000000000000000000002 --stablecoinconfigurationidversion 1 --businesslogicresolverproxyaddress 0x842760dE0dA78543d6C3df7874156450227694Fc --stablecoinaddress 0x26d43efe6c2064f4f39c508778d76204af5d967a --stablecoinproxyadminaddress 0x9a56d9a73c3073496604d85824ab7646ef1f2098
Migrating StableCoin on testnet ...
✓ Migration Proxy has been deployed successfully
--> Transaction Hash: 0xf4a5070b8d631773712debf3418f64fecad2c06d3aeef53256a9c5369665d50b
--> Contract Address: 0x773769BBeCf92Db959EFb8C99A86E9411391810d
✓ StableCoin Proxy implementation upgraded
--> Transaction Hash: 0x8b642c3519a581afe3f133f5f6f4765afddc4c358422aa73b3c05bdde982221e
🟢 Stable Coin migrated successfully
Previous implementation : 0x1f9e7ABcbF50e51EA47A17e48E1f90Dc9cB0F5dD
New implementation : 0x773769BBeCf92Db959EFb8C99A86E9411391810d
To use V2 within the web project you'll need to adjust the web/.env configuration file
REACT_APP_FACTORIES
with the "Stable Coin Factory Facet Proxy" address of the new deployed contracts that you can find the hex address in contracts/contractAddresses_v2.txt file and you can find the hedera id of this address in the hedera explorer (https://hashscan.io) for each environment that you are using.REACT_APP_RESOLVERS
constant with the "Business Logic Resolver Proxy" address of the new deployed contracts that you can find the hex address in contracts/contractAddresses_v2.txt file and you can find the hedera id of this address in the hedera explorer (https://hashscan.io) for each environment that you are using.REACT_APP_FACTORIES='[{"Environment":"mainnet","STABLE_COIN_FACTORY_ADDRESS":"0.0.6349500"}, {"Environment":"testnet","STABLE_COIN_FACTORY_ADDRESS":"0.0.6349500"}]'
REACT_APP_RESOLVERS='[{"Environment":"mainnet","STABLE_COIN_RESOLVER_ADDRESS":"0.0.6349477"}, {"Environment":"testnet","STABLE_COIN_RESOLVER_ADDRESS":"0.0.6349477"}]'
Then you can start the web project with:
npm start
To use V2 within the CLI project you'll need to adjust the /cli/hsca-config.yaml configuration file.
factories
with the "Stable Coin Factory Facet Proxy" address of the new deployed contracts that you can find the hex address in contracts/contractAddresses_v2.txt file and you can find the hedera id of this address in the hedera explorer (https://hashscan.io) for each environment that you are using.resolvers
with the "Business Logic Resolver Proxy" address of the new deployed contracts that you can find the hex address in contracts/contractAddresses_v2.txt file and you can find the hedera id of this address in the hedera explorer (https://hashscan.io) for each environment that you are using.: factories:
- id: 0.0.6349500
network: testnet
- id: 0.0.0
network: previewnet
resolvers:
- id: 0.0.6349477
network: testnet
- id: 0.0.0
network: previewnet
Then you can start the CLI project with:
npm run start:wizard
Documentation files of all contracts, in Markdown format, can be generated using the following command:
npm run doc
Generated files will be stored in the docs
folder.
In addition to the compilation, build, test and documentation scripts we have already covered, there are other scripts configured in package.json
file:
Checks the contracts size in KiB.
npm run size
Lints Solidity code.
npm run lint:sol
Lints TypeScript code.
npm run lint:ts
Lints Solidity and TypeScript code.
npm run lint
Formats TypeScript, JavaScript and Solidity files code.
npm run prettier
Executes prettier and lint commands.
npm run pre-commit
Launches slither security report.
npm run slither
Contributions are welcome. Please see the contributing guide to see how you can get involved.
This project is governed by the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to oss@hedera.com.
FAQs
[](../LICENSE.md)
We found that @hashgraph/stablecoin-npm-contracts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 15 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The Rust Security Response WG is warning of phishing emails from rustfoundation.dev targeting crates.io users.
Product
Socket now lets you customize pull request alert headers, helping security teams share clear guidance right in PRs to speed reviews and reduce back-and-forth.
Product
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.