Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions heliades-scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ const abi = [
{ "internalType": "string", "name": "denom", "type": "string" },
{ "internalType": "uint256", "name": "totalSupply", "type": "uint256" },
{ "internalType": "uint8", "name": "decimals", "type": "uint8" },
{ "internalType": "string", "name": "logoBase64", "type": "string" }
{ "internalType": "string", "name": "logoBase64", "type": "string" },
{ "internalType": "address", "name": "mintAuthority", "type": "address" },
{ "internalType": "address", "name": "pauseAuthority", "type": "address" },
{ "internalType": "address", "name": "burnAuthority", "type": "address" }
],
"name": "createErc20",
"outputs": [
Expand All @@ -37,6 +40,8 @@ const abi = [
}
];



const delegateAbi = [
{
"inputs": [
Expand Down Expand Up @@ -188,23 +193,38 @@ const contract = new ethers.Contract(PRECOMPILE_CONTRACT_ADDRESS, abi, wallet);
const tokenName = 'BTC2';
const tokenSymbol = 'BTC2';
const tokenDenom = 'uBTC222'; // denomination of one unit of the token
const tokenTotalSupply = ethers.parseUnits('100', 18);
const tokenTotalSupply = ethers.parseUnits('1000', 18);
const tokenDecimals = 18;

async function create(){
try {
console.log('Création du token ERC20...');

const tx = await contract.createErc20(tokenName, tokenSymbol, tokenDenom, tokenTotalSupply, tokenDecimals, "");
console.log('Transaction envoyée, hash :', tx.hash);
const mintAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = non-mintable
const pauseAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = non-pausable
const burnAuthority = "0x0000000000000000000000000000000000000000"; // address(0) = no special burn authority

const receipt = await tx.wait();
console.log('Transaction confirmée dans le bloc :', receipt.blockNumber);


console.log("Contract address :", receipt.logs[0].data);
async function create() {
try {
console.log('Creating ERC20 token...');

// Updated call with 9 parameters instead of 6
const tx = await contract.createErc20(
tokenName,
tokenSymbol,
tokenDenom,
tokenTotalSupply,
tokenDecimals,
"", // logoBase64
mintAuthority, // NEW: Who can mint (address(0) = nobody)
pauseAuthority, // NEW: Who can pause (address(0) = nobody)
burnAuthority // NEW: Who can burn (address(0) = nobody)
);

console.log('Transaction sent, hash:', tx.hash);
const receipt = await tx.wait();
console.log('Transaction confirmed in block:', receipt.blockNumber);
console.log("Contract address:", receipt.logs[0].data);

} catch (error) {
console.error('Une erreur est survenue :', error);
console.error('An error occurred:', error);
}
}

Expand Down Expand Up @@ -718,12 +738,12 @@ async function uploadLogo() {

async function main() {
// await createCronCallBackData();
await createCron();
//await createCron();
// await getEvents();
// await getEventsCronCancelled();
// await cancelCron();
// await getEventsEVMCallScheduled();
// await create();
await create();
//await fetch();
// await delegate();
// await addNewConsensusProposal();
Expand Down
30 changes: 25 additions & 5 deletions helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.json

Large diffs are not rendered by default.

212 changes: 118 additions & 94 deletions helios-chain/contracts/solidity/ERC20MinterBurnerDecimals.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol)

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
Expand All @@ -19,107 +18,132 @@ import "@openzeppelin/contracts/utils/Context.sol";
* This contract uses {AccessControl} to lock permissioned functions using the
* different roles - head to its documentation for details.
*
* The account that deploys the contract will be granted the minter and pauser
* roles, as well as the default admin role, which will let it grant both minter
* and pauser roles to other accounts.
* MODIFICATION: The deploying module can specify who gets the admin/minter/pauser roles
* instead of automatically assigning them to msg.sender. This allows the user who called
* the precompile to become the true owner of the token, following Solana/Ethereum standards.
*/
contract ERC20MinterBurnerDecimals is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
uint8 private _decimals;

/**
* @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
* account that deploys the contract and customizes tokens decimals
*
* See {ERC20-constructor}.
*/
constructor(string memory name, string memory symbol, uint8 decimals_)
ERC20(name, symbol) {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

uint8 private _decimals;

_setupRole(MINTER_ROLE, _msgSender());
_setupRole(PAUSER_ROLE, _msgSender());
_setupRole(BURNER_ROLE, _msgSender());
_setupDecimals(decimals_);
}
/**
* @dev Grants roles to specified addresses instead of msg.sender
* @param name Token name
* @param symbol Token symbol
* @param decimals_ Token decimals
* @param initialOwner Who gets DEFAULT_ADMIN_ROLE (the user who called createErc20)
* @param mintAuthority Who gets MINTER_ROLE (address(0) = no minter)
* @param pauseAuthority Who gets PAUSER_ROLE (address(0) = no pauser)
* @param burnAuthority Who gets BURNER_ROLE (address(0) = no special burner)
*/
constructor(
string memory name,
string memory symbol,
uint8 decimals_,
address initialOwner, // The real owner (user who called createErc20)
address mintAuthority, // Who can mint new tokens
address pauseAuthority, // Who can pause/unpause transfers
address burnAuthority // Who can burn any tokens
) ERC20(name, symbol) {
_decimals = decimals_;

// Grant ownership to the user, not the module
_setupRole(DEFAULT_ADMIN_ROLE, initialOwner);

// Grant specialized roles only if specified (non-zero address)
if (mintAuthority != address(0)) {
_setupRole(MINTER_ROLE, mintAuthority);
}
if (pauseAuthority != address(0)) {
_setupRole(PAUSER_ROLE, pauseAuthority);
}
if (burnAuthority != address(0)) {
_setupRole(BURNER_ROLE, burnAuthority);
}

// IMPORTANT: Module keeps temporary MINTER_ROLE for initial mint
// This will be revoked after initial mint in the keeper
_setupRole(MINTER_ROLE, _msgSender()); // _msgSender() = module temporarily
}

/**
* @dev Sets `_decimals` as `decimals_ once at Deployment'
*/
function _setupDecimals(uint8 decimals_) private {
_decimals = decimals_;
}
/**
* @dev Sets `_decimals` as `decimals_` once at deployment
*/
function _setupDecimals(uint8 decimals_) private {
_decimals = decimals_;
}

/**
* @dev Overrides the `decimals()` method with custom `_decimals`
*/
function decimals() public view virtual override returns (uint8) {
return _decimals;
}
/**
* @dev Overrides the `decimals()` method with custom `_decimals`
*/
function decimals() public view virtual override returns (uint8) {
return _decimals;
}

/**
* @dev Creates `amount` new tokens for `to`.
*
* See {ERC20-_mint}.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
*/
function mint(address to, uint256 amount) public virtual {
require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint");
_mint(to, amount);
}
/**
* @dev Creates `amount` new tokens for `to`.
*
* See {ERC20-_mint}.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
*/
function mint(address to, uint256 amount) public virtual {
require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint");
_mint(to, amount);
}

/**
* @dev Destroys `amount` new tokens for `to`.
*
* See {ERC20-_burn}.
*
* Requirements:
*
* - the caller must have the `BURNER_ROLE`.
*/
function burnCoins(address from, uint256 amount) public virtual {
require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn");
_burn(from, amount);
}
/**
* @dev Destroys `amount` tokens from `from`.
*
* See {ERC20-_burn}.
*
* Requirements:
*
* - the caller must have the `BURNER_ROLE`.
*/
function burnCoins(address from, uint256 amount) public virtual {
require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn");
_burn(from, amount);
}

/**
* @dev Pauses all token transfers.
*
* See {ERC20Pausable} and {Pausable-_pause}.
*
* Requirements:
*
* - the caller must have the `PAUSER_ROLE`.
*/
function pause() public virtual {
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause");
_pause();
}
/**
* @dev Pauses all token transfers.
*
* See {ERC20Pausable} and {Pausable-_pause}.
*
* Requirements:
*
* - the caller must have the `PAUSER_ROLE`.
*/
function pause() public virtual {
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause");
_pause();
}

/**
* @dev Unpauses all token transfers.
*
* See {ERC20Pausable} and {Pausable-_unpause}.
*
* Requirements:
*
* - the caller must have the `PAUSER_ROLE`.
*/
function unpause() public virtual {
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause");
_unpause();
}
/**
* @dev Unpauses all token transfers.
*
* See {ERC20Pausable} and {Pausable-_unpause}.
*
* Requirements:
*
* - the caller must have the `PAUSER_ROLE`.
*/
function unpause() public virtual {
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause");
_unpause();
}

function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override(ERC20, ERC20Pausable) {
super._beforeTokenTransfer(from, to, amount);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override(ERC20, ERC20Pausable) {
super._beforeTokenTransfer(from, to, amount);
}
}
16 changes: 11 additions & 5 deletions helios-chain/precompiles/erc20creator/ERC20Creator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ ERC20Creator constant ERC20CREATOR_CONTRACT = ERC20Creator(ERC20Creator_PRECOMPI

interface ERC20Creator {
/**
* @dev Creates a new ERC20 token with the specified parameters.
* @dev Creates a new ERC20 token with the specified parameters and role authorities.
* Returns the address of the newly created ERC20 token.
* @param name The name of the ERC20 token.
* @param symbol The symbol of the ERC20 token.
* @param denom The denomimation of one unit of the ERC20 token.
* @param denom The denomination of one unit of the ERC20 token.
* @param totalSupply The total supply of the ERC20 token.
* @param decimals The number of decimals of the ERC20 token.
* @param logoBase64 The logo in base64 png 200x200 optionnal "".
* @param logoBase64 The logo in base64 png 200x200 optional "".
* @param mintAuthority Who can mint tokens (address(0) = non-mintable).
* @param pauseAuthority Who can pause/unpause transfers (address(0) = non-pausable).
* @param burnAuthority Who can burn tokens (address(0) = no special burn authority).
* @return tokenAddress The address of the newly created ERC20 token.
*/
function createErc20(
Expand All @@ -25,6 +28,9 @@ interface ERC20Creator {
string memory denom,
uint256 totalSupply,
uint8 decimals,
string memory logoBase64
string memory logoBase64,
address mintAuthority,
address pauseAuthority,
address burnAuthority
) external returns (address tokenAddress);
}
}
7 changes: 5 additions & 2 deletions helios-chain/precompiles/erc20creator/abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
{ "internalType": "string", "name": "denom", "type": "string" },
{ "internalType": "uint256", "name": "totalSupply", "type": "uint256" },
{ "internalType": "uint8", "name": "decimals", "type": "uint8" },
{ "internalType": "string", "name": "logoBase64", "type": "string" }
{ "internalType": "string", "name": "logoBase64", "type": "string" },
{ "internalType": "address", "name": "mintAuthority", "type": "address" },
{ "internalType": "address", "name": "pauseAuthority", "type": "address" },
{ "internalType": "address", "name": "burnAuthority", "type": "address" }
],
"name": "createErc20",
"outputs": [
Expand All @@ -24,4 +27,4 @@
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}
}
Loading