A token util based on ethers.js to help developers code in a semantic manner.
$ npm install ethers-token
Use Factory
to create token constructor:
import { Factory } from "ethers-token"
// Use provider to create factory instance
const factory = Factory.use(provider)
// Create native token (e.g., ETH) constructor
const ETH = factory.createNativeCtor({
// Address is served as placeholder for native token
address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
decimals: 18,
symbol: "ETH",
})
// Access metadata on native token constructor
ETH.address // 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
ETH.decimals // 18
ETH.symbol // ETH
// Create ERC20 token constructor
const DAI = factory.createERC20Ctor({
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
decimals: 18,
symbol: "DAI",
})
// Access metadata on ERC20 token constructor
DAI.abi // ERC20 abi (conforming to [ERC20](https://eips.ethereum.org/EIPS/eip-20))
DAI.address // 0x6B175474E89094C44Da98b954EedeAC495271d0F
DAI.decimals // 18
DAI.symbol // DAI
DAI.contract // DAI contract (with abi conforming to [ERC20](https://eips.ethereum.org/EIPS/eip-20))
Token constructor is a functional constructor, which means it can be instantiated without new
. The instance created by token constructor represents specific amount of token, and you can directly treat it as a BigNumber
. For example:
// Auto translate decimals
DAI(100).eq(ethers.utils.parseUnits("100", 18))
// Support arithmetic
DAI(100).add(DAI(50)) // DAI(150)
DAI(100).sub(DAI(50)) // DAI(50)
DAI(100).mul(2) // DAI(200)
DAI(100).div(2) // DAI(50)
// Interact with contract directly
// Quote 100 USDC for DAI on UniswapV2
const USDC = factory.createERC20Ctor({
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
decimals: 6,
symbol: "USDC",
})
const [, daiAmountOut] = await UniswapV2Router.getAmountsOut(USDC(100), [
USDC.address,
DAI.address,
])
// Be careful that amount received from contract will be plain BigNumber
// Use `raw` on token constructor to convert plain BigNumber to token instance
DAI.raw(daiAmountOut)
// `raw` will not translate decimals
DAI.raw(1).eq(BigNumber.from(1))
Moreover, there are some helpful utils on token constructor and instance. Amounts returned from these utils are all wrapped as token instances:
All the arguments related to address are typed as Addressable, which accepts address string, object with address property, or instance implements
getAddress
method.
// Utils on native token constructor
await ETH.balanceOf(owner)
// Utils on native token instance
await ETH(100).from(owner).transfer(spender)
// Utils on ERC20 token constructor
await DAI.allowanceOf(owner, spender)
await DAI.approveMax(owner, spender)
await DAI.balanceOf(owner)
// Utils on ERC20 token instance
await DAI(100).from(owner).approve(spender)
await DAI(100).from(owner).transfer(spender)
await DAI(100).from(spender).transferFrom(owner, spender)
Some ERC20 tokens implement additional methods to extend the ERC20 specification, ethers-token
also supports token customization:
import { ERC20 } from "ethers-token"
// Define custom ERC20 token class
class DAIMintable extends ERC20 {
// Extend abi at need
public static abi = [
...ERC20.abi,
{
name: "mint",
type: "function",
inputs: [
// usr, wad
],
},
]
// Extend utils on token constructor by static function
public static async mint(owner: Signer, amount: BigNumberish) {
return this.contract
.connect(owner)
.mint(await owner.getAddress(), amount)
}
// Extend utils on token instance by class function
public async mint() {
// Access class static props and utils by `this.static<T>(): T`
const { contract } = this.static<typeof ERC20>()
const owner = this.mustGetOwner()
// Token instance itself is a BigNumber
// We can directly pass `this` as amount argument to contract method
return contract.connect(owner).mint(owner.address, this)
}
}
// Specify custom ERC20 token class at the first argument
const DAI = factory.createERC20Ctor(DAIMintable, {
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
decimals: 18,
symbol: "DAI",
})
// Use extended utils on token constructor and instance
await DAI.mint(owner, DAI(100))
await DAI(100).from(owner).mint()
© Cyan Ho (pilagod), 2022-NOW
Released under the MIT License