UNPKG

@stratosphere-network/token

Version:

Token module for StratoSphere SDK - ERC20 token minting and factory functionality

286 lines (224 loc) 11.8 kB
# @stratosphere-network/token This package provides a `Token` class to deploy and manage upgradeable ERC20 tokens on supported blockchains using the UUPS proxy pattern. ## Features - **Upgradeable Tokens**: Deploy tokens as UUPS proxies, allowing you to upgrade the underlying contract logic later without requiring users to migrate. - **Role-Based Access Control**: Manage permissions with distinct roles (`MINTER_ROLE`, `BURNER_ROLE`, `PAUSER_ROLE`, `UPGRADER_ROLE`) instead of a single owner. - **Factory-Based Deployment**: A central factory contract deploys lightweight proxy contracts, saving significant gas fees for your users. - **Comprehensive SDK**: A simple SDK to handle deployment, role management, feature toggling, and upgrades. ## Installation To install the package, you can use npm or yarn: ```bash npm install @stratosphere-network/token # or yarn add @stratosphere-network/token ``` ## Usage # First, import the `Token` class and the necessary types from the package. If you plan to use an existing `ethers.Wallet` instance for deployment, you'll also need to import `ethers`: First, import the `Token` class and the necessary types from the package. If you plan to use an existing `ethers.Wallet` instance, you'll also need to import `ethers`: ```typescript import Token, { TokenConfig, Chain } from "@stratosphere-network/token"; import { ethers } from "ethers"; // Required if providing your own ethers.Wallet instance ``` Next, create an instance of the `Token` class: ```typescript const tokenClient = new Token(); ``` ### Deploying a Token To deploy a new token, you'll need to provide a `tokenConfig` object. The deployer's credentials for the `deployToken` method can be supplied in one of the following ways: 1. `deployerPrivateKey` (string, optional): The private key of the deployer's account. 2. `walletInstance` (`ethers.Wallet`, optional): An existing `ethers.Wallet` object from the `ethers` library. You must provide at least one of these to the `deployToken` method. - If only `deployerPrivateKey` is provided, a new `ethers.Wallet` is created internally using a default provider for the specified chain. - If only `walletInstance` is provided, that instance is used directly for deploying. - # If both `deployerPrivateKey` and `walletInstance` are provided, a new `ethers.Wallet` is created using the `deployerPrivateKey` and the provider from the supplied `walletInstance`. const sdk = new Token(); ```` ### 1. Deploying an Upgradeable Token To deploy a new token, provide a `tokenConfig` object. The `deployToken` method returns an object containing the `transactionHash` and the `tokenAddress` of the newly created proxy contract. The address that deploys the token will automatically be granted the `DEFAULT_ADMIN_ROLE`, as well as the `MINTER_ROLE`, `BURNER_ROLE`, `PAUSER_ROLE`, and `UPGRADER_ROLE`. Currently, token deployment is **only supported on Berachain Mainnet**. ```typescript // Ensure tokenClient is instantiated as shown in the "Usage" section: // import Token from "@stratosphere-network/token"; // const tokenClient = new Token(); async function deployMyToken() { const tokenConfig: TokenConfig = { name: "My Awesome Token", symbol: "MAT", totalSupply: "1000000000000000000000000", // 1 million tokens with 18 decimals decimals: 18, chain: Chain.BERACHAIN_MAINNET, // Ensure this matches supported chains isMintable: true, // Optional: Can the token supply be increased after deployment? Defaults to false. isBurnable: true, // Optional: Can tokens be burned to reduce supply? Defaults to false. isPausable: false, // Optional: Can token transfers be paused? Defaults to false. }; // --- Option 1: Using deployerPrivateKey (simplest for quick start) --- const deployerPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; // Replace with actual private key try { console.log("Attempting to deploy with private key..."); const txHashPk = await tokenClient.deployToken( tokenConfig, deployerPrivateKey // walletInstance is omitted or undefined here ); console.log( "Token deployment with private key successful! Transaction Hash:", txHashPk ); } catch (error) { console.error("Error deploying token with private key:", error); } // --- Option 2: Using an existing ethers.Wallet instance --- // This requires 'ethers' to be imported and a wallet instance prepared. // Example setup (replace with your actual provider and private key/mnemonic): /* // Ensure ethers is imported: import { ethers } from "ethers"; // const BERACHAIN_RPC_URL = "https://mainnet.rpc.berachain.com/"; // Replace with actual official RPC for Berachain // const provider = new ethers.JsonRpcProvider(BERACHAIN_RPC_URL); // const existingWallet = new ethers.Wallet(deployerPrivateKey, provider); // Or from a connected wallet like MetaMask try { console.log("Attempting to deploy with wallet instance..."); // Note: Pass undefined for deployerPrivateKey if primarily using walletInstance const txHashWallet = await tokenClient.deployToken( tokenConfig, undefined, existingWallet ); console.log( "Token deployment with wallet instance successful! Transaction Hash:", txHashWallet ); } catch (error) { console.error("Error deploying token with wallet instance:", error); } */ } deployMyToken(); ```` **Note:** Ensure your deployer account has enough native currency (e.g., BERA on Berachain) to cover the gas fees for the deployment transaction. ### TokenConfig Parameters - `name` (string): The name of your token (e.g., "My Awesome Token"). - `symbol` (string): The symbol for your token (e.g., "MAT"). - `totalSupply` (string): The total supply of your token, expressed as a string in its smallest unit (e.g., wei for an 18-decimal token). - `decimals` (number): The number of decimal places your token will have (typically 18). - `chain` (Chain): The chain to deploy the token on. Currently, only `Chain.BERACHAIN_MAINNET` is supported. - `isMintable` (boolean, optional): Determines if new tokens can be minted after initial deployment. Defaults to `false` if not specified. - `isBurnable` (boolean, optional): Determines if tokens can be burned (destroyed) after deployment. Defaults to `false` if not specified. - # `isPausable` (boolean, optional): Determines if token transfers and other operations can be paused. Defaults to `false` if not specified. // Ensure sdk is instantiated as shown above. async function deployNewToken() { const tokenConfig: TokenConfig = { name: "My Upgradeable Token", symbol: "MUT", totalSupply: "1000000000000000000000000", // 1 million tokens with 18 decimals decimals: 18, chain: Chain.BERACHAIN_MAINNET, }; // Provide the private key of the deployer's account. // Ensure this account has enough native currency (e.g., BERA) to pay for gas. const deployerPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; try { console.log("Attempting to deploy token..."); const { transactionHash, tokenAddress } = await sdk.deployToken( tokenConfig, deployerPrivateKey ); console.log("Token deployment successful!"); console.log(` - Transaction Hash: ${transactionHash}`); console.log(` - Token Proxy Address: ${tokenAddress}`); // This is the address to interact with return tokenAddress; } catch (error) { console.error("Error deploying token:", error); } } ```` ### 2. Managing the Token Once deployed, you can manage the token using its proxy address. #### Role Management You can grant and revoke roles to other addresses. ```typescript // You need the token's address from the deployment step. const tokenAddress = "0xYourTokenProxyAddress"; const anotherAddress = "0x...someOtherAddress"; const adminPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; // The key of an address with DEFAULT_ADMIN_ROLE // Grant the MINTER_ROLE await sdk.grantRole( Chain.BERACHAIN_MAINNET, tokenAddress, "MINTER_ROLE", anotherAddress, adminPrivateKey ); console.log("MINTER_ROLE granted."); // Check if an address has a role const hasRole = await sdk.hasRole( Chain.BERACHAIN_MAINNET, tokenAddress, "MINTER_ROLE", anotherAddress ); console.log(`Does the address have MINTER_ROLE? ${hasRole}`); // true // Revoke the MINTER_ROLE await sdk.revokeRole( Chain.BERACHAIN_MAINNET, tokenAddress, "MINTER_ROLE", anotherAddress, adminPrivateKey ); console.log("MINTER_ROLE revoked."); ```` #### Feature Control Enable or disable token transfers, and pause or unpause the contract. ```typescript const tokenAddress = "0xYourTokenProxyAddress"; const pauserPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; // The key of an address with PAUSER_ROLE const adminPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; // The key of an address with DEFAULT_ADMIN_ROLE // Enable token transfers for all users await sdk.setTransferable( Chain.BERACHAIN_MAINNET, tokenAddress, true, adminPrivateKey ); console.log("Token transfers are now enabled for everyone."); // Pause the contract await sdk.pause(Chain.BERACHAIN_MAINNET, tokenAddress, pauserPrivateKey); console.log("Contract is paused."); // Unpause the contract await sdk.unpause(Chain.BERACHAIN_MAINNET, tokenAddress, pauserPrivateKey); console.log("Contract is unpaused."); ``` ### 3. Upgrading the Token If you deploy a new version of the `Token.sol` implementation contract, you can upgrade your proxies to point to the new logic. ```typescript const tokenAddress = "0xYourTokenProxyAddress"; const newImplementationAddress = "0x...addressOfNewTokenImplementation"; const upgraderPrivateKey = "YOUR_DEPLOYER_PRIVATE_KEY"; // The key of an address with UPGRADER_ROLE await sdk.upgradeTo( Chain.BERACHAIN_MAINNET, tokenAddress, newImplementationAddress, upgraderPrivateKey ); console.log("Token proxy has been upgraded to the new implementation!"); ``` ## API Reference ### `TokenConfig` Parameters - `name` (string): The name of your token (e.g., "My Upgradeable Token"). - `symbol` (string): The symbol for your token (e.g., "MUT"). - `totalSupply` (string): The initial supply of your token, expressed as a string in its smallest unit (e.g., wei for an 18-decimal token). This supply is minted to the deployer. - `decimals` (number): The number of decimal places your token will have (typically 18). - `chain` (Chain): The chain to deploy the token on. Currently, only `Chain.BERACHAIN_MAINNET` is supported. ### SDK Methods All methods that perform on-chain transactions require either a `deployerPrivateKey` or a `walletInstance` to be passed as the final argument. - `deployToken(config, privateKey?, wallet?)`: Deploys a new token proxy. Returns `{ transactionHash, tokenAddress }`. - `grantRole(chain, tokenAddress, role, toAddress, ...)`: Grants a role to an address. - `revokeRole(chain, tokenAddress, role, fromAddress, ...)`: Revokes a role from an address. - `hasRole(chain, tokenAddress, role, address)`: Checks if an address has a specific role. Returns a boolean. - `setTransferable(chain, tokenAddress, isTransferable, ...)`: Enables or disables token transfers for non-admins. - `pause(chain, tokenAddress, ...)`: Pauses all token transfers, mints, and burns. - `unpause(chain, tokenAddress, ...)`: Resumes a paused contract. - `upgradeTo(chain, tokenAddress, newImplementation, ...)`: Upgrades the token proxy to a new implementation contract. `role` parameter must be one of: `"MINTER_ROLE"`, `"BURNER_ROLE"`, `"PAUSER_ROLE"`, `"UPGRADER_ROLE"`. > > > > > > > 5efa2a7fe3f1a6bd0d3e705d1dd6bdc7f677cdb2