Posted By : Mudit
A decentralised stablecoin is created using crypto token development services and uses blockchain technology to issue digital assets called stablecoins, which are based on a fixed value, such as $1, and are not controlled by a central authority. Collateralised Debt Positions (CDPs) are a popular method for accomplishing this. These smart contracts control the issuance and liquidation of stablecoins according to collateral.
A CDP is a smart contract that, in exchange for granting a loan in the form of stablecoins, locks up collateral, such as Ether. A CDP's salient characteristics are:
Collateral: The user funds a smart contract with a specific quantity of cryptocurrency (such as ETH).
Debt: Depending on the value of the supplied collateral, the user borrows stablecoins. The collateral ratio (e.g., 150%) restricts the amount of debt that can be borrowed, thus the borrower is not allowed to withdraw more stablecoins than the collateral value.
Collateral Ratio: This is the proportion of money loaned in stablecoins to the amount of collateral needed. The borrower must deposit $1.50 in collateral for every $1 borrowed in stablecoin, for instance, if the collateral ratio is 150%.
Liquidation: The system will sell the collateral to pay off the debt and keep the system from slipping into negative equity if the collateral's value drops below a predetermined level, meaning it is no longer sufficient to cover the borrowed debt.
Repayment: After repaying the debt, the collateral is returned, and the user can do so by returning the stablecoins they borrowed.
Also, Discover | AI-Powered Stablecoin Development | Streamlining Stability
1. Initialize the Project
npm init -y
2. Install Hardhat
npm install --save-dev hardhat
3. Create a Hardhat Project
npx hardhat
4. Install Environment and OpenZeppelin Libraries
npm install dotenv @openzeppelin/contracts
You may also like | Best Blockchain Platforms for Stablecoin Development
In contracts folder add the following three files:
This is a sample ERC20 token acting as a mock USDC, used to mint and burn tokens during borrow/repay operations.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
contract USDC is ERC20, Ownable {
uint8 private immutable _decimals;
address public minter;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 initialSupply
) ERC20(name_, symbol_) Ownable(msg.sender) {
_decimals = decimals_;
_mint(msg.sender, initialSupply);
}
function setMinter(address _minter) external onlyOwner {
minter = _minter;
}
function mint(address to, uint256 amount) external {
require(msg.sender == minter, 'Only minter can mint');
_mint(to, amount);
}
function burn(address from, uint256 amount) external {
require(msg.sender == minter, 'Only minter can burn');
_burn(from, amount);
}
function decimals() public view override returns (uint8) {
return _decimals;
}
}
This is a simple oracle contract that returns a hardcoded ETH/USD price. It can be updated by the owner to simulate live price changes.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Oracle {
uint256 public price = 2000 * 1e18; // $2000 per ETH
address public owner;
constructor() {
owner = msg.sender;
}
function setPrice(uint256 _price) external {
require(msg.sender == owner, 'Only owner can set price');
price = _price;
}
function getPrice() external view returns (uint256) {
return price;
}
}
Also, Check | PayPal Launches its U.S. Dollar Stablecoin PayPal USD (PYUSD)
This contract manages ETH collateral, allows borrowing and repayment in USDC, and handles liquidation if the collateral ratio is violated.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import './Usdc.sol';
import './Oracle.sol';
contract CDPVault {
USDC public stablecoin;
Oracle public oracle;
uint256 public constant COLLATERAL_RATIO = 150;
uint256 public constant PRECISION = 1e18;
mapping(address => uint256) public collateralETH;
mapping(address => uint256) public debt;
constructor(address _stablecoin, address _oracle) {
stablecoin = USDC(_stablecoin);
oracle = Oracle(_oracle);
}
function depositCollateral() external payable {
require(msg.value > 0, 'Must deposit ETH');
collateralETH[msg.sender] += msg.value;
}
function borrow(uint256 amount) external {
require(amount > 0, 'Invalid borrow amount');
uint256 ethPrice = oracle.getPrice();
uint256 collateralValue = (collateralETH[msg.sender] * ethPrice) /
PRECISION;
uint256 maxBorrow = (collateralValue * 100) / COLLATERAL_RATIO;
require(debt[msg.sender] + amount <= maxBorrow, 'Exceeds borrow limit');
debt[msg.sender] += amount;
stablecoin.mint(msg.sender, amount * 1e18);
}
function repay(uint256 amount) external {
require(debt[msg.sender] >= amount, 'Repaying more than owed');
uint256 scaledAmount = amount * 1e18;
stablecoin.transferFrom(msg.sender, address(this), scaledAmount);
stablecoin.burn(address(this), scaledAmount);
debt[msg.sender] -= amount;
}
function withdraw(uint256 amount) external {
require(
amount > 0 && collateralETH[msg.sender] >= amount,
'Invalid amount'
);
uint256 ethPrice = oracle.getPrice();
uint256 newCollateral = collateralETH[msg.sender] - amount;
uint256 newCollateralValue = (newCollateral * ethPrice) / PRECISION;
require(
debt[msg.sender] == 0 ||
(newCollateralValue * 100) / debt[msg.sender] >=
COLLATERAL_RATIO,
'Would become undercollateralized'
);
collateralETH[msg.sender] = newCollateral;
payable(msg.sender).transfer(amount);
}
function liquidate(address user) external {
uint256 ethPrice = oracle.getPrice();
uint256 userCollateral = collateralETH[user];
uint256 userDebt = debt[user];
require(userDebt > 0, 'No debt to liquidate');
uint256 collateralValue = (userCollateral * ethPrice) / PRECISION;
uint256 requiredValue = (userDebt * COLLATERAL_RATIO) / 100;
require(collateralValue < requiredValue, 'Position is healthy');
uint256 scaledDebt = userDebt * 1e18;
stablecoin.transferFrom(msg.sender, address(this), scaledDebt);
stablecoin.burn(address(this), scaledDebt);
collateralETH[user] = 0;
debt[user] = 0;
payable(msg.sender).transfer(userCollateral);
}
}
This deployment script uses Hardhat to build up all required smart contracts for the CDP system. First, a fictitious USDC token with a 6-decimal precision and a 1,000,000 token initial supply is deployed. A straightforward Oracle contract with a hardcoded ETH price is then deployed. The primary CDPVault contract is then deployed utilising the USDC and Oracle addresses. In order to mint and burn tokens during borrow and repay activities, it lastly configures the CDPVault as the USDC token minter.
const hre = require('hardhat');
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log('Deploying contracts with:', deployer.address);
// Deploy USDC with 6 decimals and 1,000,000 initial supply
const USDC = await hre.ethers.getContractFactory('USDC');
const usdc = await USDC.deploy(
'USD Test Coin',
'USDC',
6,
hre.ethers.parseUnits('1000000', 6)
);
await usdc.waitForDeployment();
console.log('USDC deployed at:', usdc.target);
// Deploy Oracle
const Oracle = await hre.ethers.getContractFactory('Oracle');
const oracle = await Oracle.deploy();
await oracle.waitForDeployment();
console.log('Oracle deployed at:', oracle.target);
// Deploy CDPVault
const CDPVault = await hre.ethers.getContractFactory('CDPVault');
const vault = await CDPVault.deploy(usdc.target, oracle.target);
await vault.waitForDeployment();
console.log('CDPVault deployed at:', vault.target);
// Set vault as the minter
const tx = await usdc.setMinter(vault.target);
await tx.wait();
console.log('Vault set as minter on USDC');
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
To deploy the contracts on the Sepolia test network, you can run the following command:
npx hardhat run scripts/deploy.js --network sepolia
The USDC token, Oracle, and CDPVault contracts will be deployed on Sepolia by the script when you execute this command. After that, the CDPVault will be designated as the USDC token minter. Following a successful deployment, the console will display the deployed contract addresses and the deployer's wallet address for your testing and engagement.
Also, Discover | The Ultimate Guide to Stablecoin Development 2025 Edition
This post describes how to use Hardhat to create a basic decentralised stablecoin system. The implementation of a CDPVault contract, a simple price oracle, and a mock USDC token has resulted in a functional prototype that replicates the process of ETH deposits, stablecoin borrowings, and collateralised debt positions. A more reliable DeFi application can be built upon this base with well-defined deployment procedures and a testable configuration on the Sepolia network. If you are planning to build and launch a stablecoin using CDP, connect with our skilled blockchain developers to get started.
May 8, 2025 at 12:10 pm
Your comment is awaiting moderation.