status-im/status-go

View on GitHub
services/communitytokens/token_instances.go

Summary

Maintainability
A
0 mins
Test Coverage
F
0%
package communitytokens

import (
    "context"
    "fmt"
    "math/big"
    "strings"

    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/status-im/status-go/contracts/community-tokens/assets"
    "github.com/status-im/status-go/contracts/community-tokens/collectibles"
    "github.com/status-im/status-go/contracts/community-tokens/mastertoken"
    "github.com/status-im/status-go/contracts/community-tokens/ownertoken"
    "github.com/status-im/status-go/protocol/communities/token"
    "github.com/status-im/status-go/protocol/protobuf"
    "github.com/status-im/status-go/services/wallet/bigint"
)

type TokenInstance interface {
    RemoteBurn(*bind.TransactOpts, []*big.Int) (*types.Transaction, error)
    Mint(*bind.TransactOpts, []string, *bigint.BigInt) (*types.Transaction, error)
    SetMaxSupply(*bind.TransactOpts, *big.Int) (*types.Transaction, error)
    PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error)
}

// Owner Token
type OwnerTokenInstance struct {
    TokenInstance
    instance *ownertoken.OwnerToken
}

func (t OwnerTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    return nil, fmt.Errorf("remote destruction for owner token not implemented")
}

func (t OwnerTokenInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    return nil, fmt.Errorf("minting for owner token not implemented")
}

func (t OwnerTokenInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    return nil, fmt.Errorf("setting max supply for owner token not implemented")
}

func (t OwnerTokenInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    ownerTokenABI, err := abi.JSON(strings.NewReader(ownertoken.OwnerTokenABI))
    if err != nil {
        return []byte{}, err
    }
    return ownerTokenABI.Pack(methodName, args...)
}

// Master Token
type MasterTokenInstance struct {
    TokenInstance
    instance *mastertoken.MasterToken
}

func (t MasterTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    return t.instance.RemoteBurn(transactOpts, tokenIds)
}

func (t MasterTokenInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    usersAddresses := prepareMintCollectiblesData(walletAddresses, amount)
    return t.instance.MintTo(transactOpts, usersAddresses)
}

func (t MasterTokenInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    return t.instance.SetMaxSupply(transactOpts, maxSupply)
}

func (t MasterTokenInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    masterTokenABI, err := abi.JSON(strings.NewReader(mastertoken.MasterTokenABI))
    if err != nil {
        return []byte{}, err
    }
    return masterTokenABI.Pack(methodName, args...)
}

// Collectible
type CollectibleInstance struct {
    TokenInstance
    instance *collectibles.Collectibles
}

func (t CollectibleInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    return t.instance.RemoteBurn(transactOpts, tokenIds)
}

func (t CollectibleInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    usersAddresses := prepareMintCollectiblesData(walletAddresses, amount)
    return t.instance.MintTo(transactOpts, usersAddresses)
}

func (t CollectibleInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    return t.instance.SetMaxSupply(transactOpts, maxSupply)
}

func (t CollectibleInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI))
    if err != nil {
        return []byte{}, err
    }
    return collectiblesABI.Pack(methodName, args...)
}

// Asset
type AssetInstance struct {
    TokenInstance
    instance *assets.Assets
}

func (t AssetInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    return nil, fmt.Errorf("remote destruction for assets not implemented")
}

// The amount should be in smallest denomination of the asset (like wei) with decimal = 18, eg.
// if we want to mint 2.34 of the token, then amount should be 234{16 zeros}.
func (t AssetInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    usersAddresses, amountsList := prepareMintAssetsData(walletAddresses, amount)
    return t.instance.MintTo(transactOpts, usersAddresses, amountsList)
}

func (t AssetInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    return t.instance.SetMaxSupply(transactOpts, maxSupply)
}

func (t AssetInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    assetsABI, err := abi.JSON(strings.NewReader(assets.AssetsABI))
    if err != nil {
        return []byte{}, err
    }
    return assetsABI.Pack(methodName, args...)
}

// creator

func NewTokenInstance(s *Service, chainID uint64, contractAddress string) (TokenInstance, error) {
    tokenType, err := s.db.GetTokenType(chainID, contractAddress)
    if err != nil {
        return nil, err
    }
    privLevel, err := s.db.GetTokenPrivilegesLevel(chainID, contractAddress)
    if err != nil {
        return nil, err
    }
    switch {
    case privLevel == token.OwnerLevel:
        contractInst, err := s.NewOwnerTokenInstance(chainID, contractAddress)
        if err != nil {
            return nil, err
        }
        return &OwnerTokenInstance{instance: contractInst}, nil
    case privLevel == token.MasterLevel:
        contractInst, err := s.NewMasterTokenInstance(chainID, contractAddress)
        if err != nil {
            return nil, err
        }
        return &MasterTokenInstance{instance: contractInst}, nil
    case tokenType == protobuf.CommunityTokenType_ERC721:
        contractInst, err := s.manager.NewCollectiblesInstance(chainID, contractAddress)
        if err != nil {
            return nil, err
        }
        return &CollectibleInstance{instance: contractInst}, nil
    case tokenType == protobuf.CommunityTokenType_ERC20:
        contractInst, err := s.manager.NewAssetsInstance(chainID, contractAddress)
        if err != nil {
            return nil, err
        }
        return &AssetInstance{instance: contractInst}, nil
    }

    return nil, fmt.Errorf("unknown type of contract: chain=%v, address=%v", chainID, contractAddress)
}