@stratosphere-network/token
Version:
Token module for StratoSphere SDK - ERC20 token minting and factory functionality
286 lines (224 loc) • 11.8 kB
Markdown
# -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 -network/token
# or
yarn add -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