141 lines
3.9 KiB
Go
141 lines
3.9 KiB
Go
package evm
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
|
|
"git.lehouerou.net/laurent/evm/contracts"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/pkg/errors"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
type Token interface {
|
|
Client() Client
|
|
|
|
Address() common.Address
|
|
Name() string
|
|
Symbol() string
|
|
Decimals() uint8
|
|
TotalSupply() (decimal.Decimal, error)
|
|
BalanceOf(common.Address) (decimal.Decimal, error)
|
|
Balance() (decimal.Decimal, error)
|
|
Allowance(owner common.Address, spender common.Address) (decimal.Decimal, error)
|
|
Approve(ctx context.Context, spender common.Address, value decimal.Decimal, opts ...ExecutionOption) (Transaction, error)
|
|
Transfer(ctx context.Context, to common.Address, value decimal.Decimal, opts ...ExecutionOption) (Transaction, error)
|
|
|
|
ValueToBigInt(value decimal.Decimal) *big.Int
|
|
ValueFromBigInt(value *big.Int) decimal.Decimal
|
|
}
|
|
|
|
type baseToken struct {
|
|
client Client
|
|
contract *contracts.Token
|
|
|
|
address common.Address
|
|
name string
|
|
symbol string
|
|
decimals uint8
|
|
}
|
|
|
|
func NewToken(client Client, address common.Address) (Token, error) {
|
|
contract, err := contracts.NewToken(address, client)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
name, err := contract.Name(&bind.CallOpts{})
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
symbol, err := contract.Symbol(&bind.CallOpts{})
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
decimals, err := contract.Decimals(&bind.CallOpts{})
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
return &baseToken{
|
|
address: address,
|
|
name: name,
|
|
symbol: symbol,
|
|
decimals: decimals,
|
|
client: client,
|
|
contract: contract,
|
|
}, nil
|
|
}
|
|
|
|
func (t *baseToken) Client() Client {
|
|
return t.client
|
|
}
|
|
|
|
func (t *baseToken) TotalSupply() (decimal.Decimal, error) {
|
|
s, err := t.contract.TotalSupply(&bind.CallOpts{})
|
|
if err != nil {
|
|
return decimal.Zero, errors.Wrap(err, "calling contract")
|
|
}
|
|
return t.ValueFromBigInt(s), nil
|
|
}
|
|
|
|
func (t *baseToken) BalanceOf(address common.Address) (decimal.Decimal, error) {
|
|
b, err := t.contract.BalanceOf(&bind.CallOpts{}, address)
|
|
if err != nil {
|
|
return decimal.Zero, errors.Wrap(err, "getting balance from contract")
|
|
}
|
|
return t.ValueFromBigInt(b), nil
|
|
}
|
|
|
|
func (t *baseToken) Allowance(owner common.Address, spender common.Address) (decimal.Decimal, error) {
|
|
a, err := t.contract.Allowance(&bind.CallOpts{}, owner, spender)
|
|
if err != nil {
|
|
return decimal.Zero, errors.Wrap(err, "calling contract")
|
|
}
|
|
return t.ValueFromBigInt(a), nil
|
|
}
|
|
|
|
func (t *baseToken) Approve(ctx context.Context, spender common.Address, value decimal.Decimal, opts ...ExecutionOption) (Transaction, error) {
|
|
return t.client.Execute(ctx, func(ctx context.Context, options *TransactOpts) (*types.Transaction, error) {
|
|
return t.contract.Approve(options.TransactOpts, spender, t.ValueToBigInt(value))
|
|
}, opts...)
|
|
}
|
|
|
|
func (t *baseToken) Transfer(ctx context.Context, to common.Address, value decimal.Decimal, opts ...ExecutionOption) (Transaction, error) {
|
|
return t.client.Execute(ctx, func(ctx context.Context, options *TransactOpts) (*types.Transaction, error) {
|
|
return t.contract.Transfer(options.TransactOpts, to, t.ValueToBigInt(value))
|
|
}, opts...)
|
|
}
|
|
|
|
func (t *baseToken) Address() common.Address {
|
|
return t.address
|
|
}
|
|
|
|
func (t *baseToken) Name() string {
|
|
return t.name
|
|
}
|
|
|
|
func (t *baseToken) Symbol() string {
|
|
return t.symbol
|
|
}
|
|
|
|
func (t *baseToken) Decimals() uint8 {
|
|
return t.decimals
|
|
}
|
|
|
|
func (t *baseToken) DecimalsAsInt32() int32 {
|
|
return int32(t.decimals)
|
|
}
|
|
|
|
func (t *baseToken) ValueFromBigInt(val *big.Int) decimal.Decimal {
|
|
return decimal.NewFromBigInt(val, -t.DecimalsAsInt32())
|
|
}
|
|
|
|
func (t *baseToken) ValueToBigInt(val decimal.Decimal) *big.Int {
|
|
return val.Shift(t.DecimalsAsInt32()).BigInt()
|
|
}
|
|
|
|
func (t *baseToken) Balance() (decimal.Decimal, error) {
|
|
return t.BalanceOf(t.client.PublicAddress())
|
|
}
|