914
vendor/github.com/status-im/status-go/services/communitytokens/api.go
generated
vendored
Normal file
914
vendor/github.com/status-im/status-go/services/communitytokens/api.go
generated
vendored
Normal file
@@ -0,0 +1,914 @@
|
||||
package communitytokens
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/assets"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/collectibles"
|
||||
communitytokendeployer "github.com/status-im/status-go/contracts/community-tokens/deployer"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/mastertoken"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/ownertoken"
|
||||
communityownertokenregistry "github.com/status-im/status-go/contracts/community-tokens/registry"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/services/utils"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
wcommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
||||
func NewAPI(s *Service) *API {
|
||||
return &API{
|
||||
s: s,
|
||||
}
|
||||
}
|
||||
|
||||
type API struct {
|
||||
s *Service
|
||||
}
|
||||
|
||||
type DeploymentDetails struct {
|
||||
ContractAddress string `json:"contractAddress"`
|
||||
TransactionHash string `json:"transactionHash"`
|
||||
}
|
||||
|
||||
const maxSupply = 999999999
|
||||
|
||||
type DeploymentParameters struct {
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
Supply *bigint.BigInt `json:"supply"`
|
||||
InfiniteSupply bool `json:"infiniteSupply"`
|
||||
Transferable bool `json:"transferable"`
|
||||
RemoteSelfDestruct bool `json:"remoteSelfDestruct"`
|
||||
TokenURI string `json:"tokenUri"`
|
||||
OwnerTokenAddress string `json:"ownerTokenAddress"`
|
||||
MasterTokenAddress string `json:"masterTokenAddress"`
|
||||
}
|
||||
|
||||
func (d *DeploymentParameters) GetSupply() *big.Int {
|
||||
if d.InfiniteSupply {
|
||||
return d.GetInfiniteSupply()
|
||||
}
|
||||
return d.Supply.Int
|
||||
}
|
||||
|
||||
// infinite supply for ERC721 is 2^256-1
|
||||
func (d *DeploymentParameters) GetInfiniteSupply() *big.Int {
|
||||
return GetInfiniteSupply()
|
||||
}
|
||||
|
||||
func GetInfiniteSupply() *big.Int {
|
||||
max := new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil)
|
||||
max.Sub(max, big.NewInt(1))
|
||||
return max
|
||||
}
|
||||
|
||||
func (d *DeploymentParameters) Validate(isAsset bool) error {
|
||||
if len(d.Name) <= 0 {
|
||||
return errors.New("empty collectible name")
|
||||
}
|
||||
if len(d.Symbol) <= 0 {
|
||||
return errors.New("empty collectible symbol")
|
||||
}
|
||||
var maxForType = big.NewInt(maxSupply)
|
||||
if isAsset {
|
||||
assetMultiplier, _ := big.NewInt(0).SetString("1000000000000000000", 10)
|
||||
maxForType = maxForType.Mul(maxForType, assetMultiplier)
|
||||
}
|
||||
if !d.InfiniteSupply && (d.Supply.Cmp(big.NewInt(0)) < 0 || d.Supply.Cmp(maxForType) > 0) {
|
||||
return fmt.Errorf("wrong supply value: %v", d.Supply)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) DeployCollectibles(ctx context.Context, chainID uint64, deploymentParameters DeploymentParameters, txArgs transactions.SendTxArgs, password string) (DeploymentDetails, error) {
|
||||
|
||||
err := deploymentParameters.Validate(false)
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
address, tx, _, err := collectibles.DeployCollectibles(transactOpts, ethClient, deploymentParameters.Name,
|
||||
deploymentParameters.Symbol, deploymentParameters.GetSupply(),
|
||||
deploymentParameters.RemoteSelfDestruct, deploymentParameters.Transferable,
|
||||
deploymentParameters.TokenURI, common.HexToAddress(deploymentParameters.OwnerTokenAddress),
|
||||
common.HexToAddress(deploymentParameters.MasterTokenAddress))
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.DeployCommunityToken,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
return DeploymentDetails{address.Hex(), tx.Hash().Hex()}, nil
|
||||
}
|
||||
|
||||
func decodeSignature(sig []byte) (r [32]byte, s [32]byte, v uint8, err error) {
|
||||
if len(sig) != crypto.SignatureLength {
|
||||
return [32]byte{}, [32]byte{}, 0, fmt.Errorf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength)
|
||||
}
|
||||
copy(r[:], sig[:32])
|
||||
copy(s[:], sig[32:64])
|
||||
v = sig[64] + 27
|
||||
return r, s, v, nil
|
||||
}
|
||||
|
||||
func prepareDeploymentSignatureStruct(signature string, communityID string, addressFrom common.Address) (communitytokendeployer.CommunityTokenDeployerDeploymentSignature, error) {
|
||||
r, s, v, err := decodeSignature(common.FromHex(signature))
|
||||
if err != nil {
|
||||
return communitytokendeployer.CommunityTokenDeployerDeploymentSignature{}, err
|
||||
}
|
||||
communityEthAddress, err := convert33BytesPubKeyToEthAddress(communityID)
|
||||
if err != nil {
|
||||
return communitytokendeployer.CommunityTokenDeployerDeploymentSignature{}, err
|
||||
}
|
||||
communitySignature := communitytokendeployer.CommunityTokenDeployerDeploymentSignature{
|
||||
V: v,
|
||||
R: r,
|
||||
S: s,
|
||||
Deployer: addressFrom,
|
||||
Signer: communityEthAddress,
|
||||
}
|
||||
return communitySignature, nil
|
||||
}
|
||||
|
||||
func (api *API) DeployOwnerToken(ctx context.Context, chainID uint64,
|
||||
ownerTokenParameters DeploymentParameters, masterTokenParameters DeploymentParameters,
|
||||
signature string, communityID string, signerPubKey string,
|
||||
txArgs transactions.SendTxArgs, password string) (DeploymentDetails, error) {
|
||||
err := ownerTokenParameters.Validate(false)
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
if len(signerPubKey) <= 0 {
|
||||
return DeploymentDetails{}, fmt.Errorf("signerPubKey is empty")
|
||||
}
|
||||
|
||||
err = masterTokenParameters.Validate(false)
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
deployerContractInst, err := api.NewCommunityTokenDeployerInstance(chainID)
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
ownerTokenConfig := communitytokendeployer.CommunityTokenDeployerTokenConfig{
|
||||
Name: ownerTokenParameters.Name,
|
||||
Symbol: ownerTokenParameters.Symbol,
|
||||
BaseURI: ownerTokenParameters.TokenURI,
|
||||
}
|
||||
|
||||
masterTokenConfig := communitytokendeployer.CommunityTokenDeployerTokenConfig{
|
||||
Name: masterTokenParameters.Name,
|
||||
Symbol: masterTokenParameters.Symbol,
|
||||
BaseURI: masterTokenParameters.TokenURI,
|
||||
}
|
||||
|
||||
communitySignature, err := prepareDeploymentSignatureStruct(signature, communityID, common.Address(txArgs.From))
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
log.Debug("Signature:", communitySignature)
|
||||
|
||||
tx, err := deployerContractInst.Deploy(transactOpts, ownerTokenConfig, masterTokenConfig, communitySignature, common.FromHex(signerPubKey))
|
||||
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.DeployOwnerToken,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
return DeploymentDetails{"", tx.Hash().Hex()}, nil
|
||||
}
|
||||
|
||||
func (api *API) GetMasterTokenContractAddressFromHash(ctx context.Context, chainID uint64, txHash string) (string, error) {
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
receipt, err := ethClient.TransactionReceipt(ctx, common.HexToHash(txHash))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deployerContractInst, err := api.NewCommunityTokenDeployerInstance(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
logMasterTokenCreatedSig := []byte("DeployMasterToken(address)")
|
||||
logMasterTokenCreatedSigHash := crypto.Keccak256Hash(logMasterTokenCreatedSig)
|
||||
|
||||
for _, vLog := range receipt.Logs {
|
||||
if vLog.Topics[0].Hex() == logMasterTokenCreatedSigHash.Hex() {
|
||||
event, err := deployerContractInst.ParseDeployMasterToken(*vLog)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return event.Arg0.Hex(), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("can't find master token address in transaction: %v", txHash)
|
||||
}
|
||||
|
||||
func (api *API) GetOwnerTokenContractAddressFromHash(ctx context.Context, chainID uint64, txHash string) (string, error) {
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
receipt, err := ethClient.TransactionReceipt(ctx, common.HexToHash(txHash))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deployerContractInst, err := api.NewCommunityTokenDeployerInstance(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
logOwnerTokenCreatedSig := []byte("DeployOwnerToken(address)")
|
||||
logOwnerTokenCreatedSigHash := crypto.Keccak256Hash(logOwnerTokenCreatedSig)
|
||||
|
||||
for _, vLog := range receipt.Logs {
|
||||
if vLog.Topics[0].Hex() == logOwnerTokenCreatedSigHash.Hex() {
|
||||
event, err := deployerContractInst.ParseDeployOwnerToken(*vLog)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return event.Arg0.Hex(), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("can't find owner token address in transaction: %v", txHash)
|
||||
}
|
||||
|
||||
func (api *API) DeployAssets(ctx context.Context, chainID uint64, deploymentParameters DeploymentParameters, txArgs transactions.SendTxArgs, password string) (DeploymentDetails, error) {
|
||||
|
||||
err := deploymentParameters.Validate(true)
|
||||
if err != nil {
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
const decimals = 18
|
||||
address, tx, _, err := assets.DeployAssets(transactOpts, ethClient, deploymentParameters.Name,
|
||||
deploymentParameters.Symbol, decimals, deploymentParameters.GetSupply(),
|
||||
deploymentParameters.TokenURI,
|
||||
common.HexToAddress(deploymentParameters.OwnerTokenAddress),
|
||||
common.HexToAddress(deploymentParameters.MasterTokenAddress))
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.DeployCommunityToken,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return DeploymentDetails{}, err
|
||||
}
|
||||
|
||||
return DeploymentDetails{address.Hex(), tx.Hash().Hex()}, nil
|
||||
}
|
||||
|
||||
// Returns gas units + 10%
|
||||
func (api *API) DeployCollectiblesEstimate(ctx context.Context) (uint64, error) {
|
||||
// TODO investigate why the code below does not return correct values
|
||||
/*ethClient, err := api.s.manager.rpcClient.EthClient(420)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
||||
collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
data, err := collectiblesABI.Pack("", "name", "SYMBOL", big.NewInt(20), true, false, "tokenUriwhcih is very long asdkfjlsdkjflk",
|
||||
common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"), common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
callMsg := ethereum.CallMsg{
|
||||
From: common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"),
|
||||
To: nil,
|
||||
Value: big.NewInt(0),
|
||||
Data: data,
|
||||
}
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + uint64(float32(estimate)*0.1), nil*/
|
||||
|
||||
// TODO compute fee dynamically
|
||||
// the code above returns too low fees, need to investigate
|
||||
gasAmount := uint64(2500000)
|
||||
return gasAmount + uint64(float32(gasAmount)*0.1), nil
|
||||
}
|
||||
|
||||
// Returns gas units + 10%
|
||||
func (api *API) DeployAssetsEstimate(ctx context.Context) (uint64, error) {
|
||||
// TODO compute fee dynamically
|
||||
gasAmount := uint64(1500000)
|
||||
return gasAmount + uint64(float32(gasAmount)*0.1), nil
|
||||
}
|
||||
|
||||
func (api *API) DeployOwnerTokenEstimate(ctx context.Context, chainID uint64, fromAddress string,
|
||||
ownerTokenParameters DeploymentParameters, masterTokenParameters DeploymentParameters,
|
||||
signature string, communityID string, signerPubKey string) (uint64, error) {
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
||||
deployerAddress, err := communitytokendeployer.ContractAddress(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
deployerABI, err := abi.JSON(strings.NewReader(communitytokendeployer.CommunityTokenDeployerABI))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
ownerTokenConfig := communitytokendeployer.CommunityTokenDeployerTokenConfig{
|
||||
Name: ownerTokenParameters.Name,
|
||||
Symbol: ownerTokenParameters.Symbol,
|
||||
BaseURI: ownerTokenParameters.TokenURI,
|
||||
}
|
||||
|
||||
masterTokenConfig := communitytokendeployer.CommunityTokenDeployerTokenConfig{
|
||||
Name: masterTokenParameters.Name,
|
||||
Symbol: masterTokenParameters.Symbol,
|
||||
BaseURI: masterTokenParameters.TokenURI,
|
||||
}
|
||||
|
||||
communitySignature, err := prepareDeploymentSignatureStruct(signature, communityID, common.HexToAddress(fromAddress))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
data, err := deployerABI.Pack("deploy", ownerTokenConfig, masterTokenConfig, communitySignature, common.FromHex(signerPubKey))
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
toAddr := deployerAddress
|
||||
fromAddr := common.HexToAddress(fromAddress)
|
||||
|
||||
callMsg := ethereum.CallMsg{
|
||||
From: fromAddr,
|
||||
To: &toAddr,
|
||||
Value: big.NewInt(0),
|
||||
Data: data,
|
||||
}
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + uint64(float32(estimate)*0.1), nil
|
||||
}
|
||||
|
||||
func (api *API) NewMasterTokenInstance(chainID uint64, contractAddress string) (*mastertoken.MasterToken, error) {
|
||||
backend, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mastertoken.NewMasterToken(common.HexToAddress(contractAddress), backend)
|
||||
}
|
||||
|
||||
func (api *API) NewOwnerTokenInstance(chainID uint64, contractAddress string) (*ownertoken.OwnerToken, error) {
|
||||
return api.s.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (api *API) NewCommunityTokenDeployerInstance(chainID uint64) (*communitytokendeployer.CommunityTokenDeployer, error) {
|
||||
return api.s.manager.NewCommunityTokenDeployerInstance(chainID)
|
||||
}
|
||||
|
||||
func (api *API) NewCommunityOwnerTokenRegistryInstance(chainID uint64, contractAddress string) (*communityownertokenregistry.CommunityOwnerTokenRegistry, error) {
|
||||
return api.s.NewCommunityOwnerTokenRegistryInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (api *API) NewCollectiblesInstance(chainID uint64, contractAddress string) (*collectibles.Collectibles, error) {
|
||||
return api.s.manager.NewCollectiblesInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (api *API) NewAssetsInstance(chainID uint64, contractAddress string) (*assets.Assets, error) {
|
||||
return api.s.manager.NewAssetsInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
// if we want to mint 2 tokens to addresses ["a", "b"] we need to mint
|
||||
// twice to every address - we need to send to smart contract table ["a", "a", "b", "b"]
|
||||
func (api *API) multiplyWalletAddresses(amount *bigint.BigInt, contractAddresses []string) []string {
|
||||
var totalAddresses []string
|
||||
for i := big.NewInt(1); i.Cmp(amount.Int) <= 0; {
|
||||
totalAddresses = append(totalAddresses, contractAddresses...)
|
||||
i.Add(i, big.NewInt(1))
|
||||
}
|
||||
return totalAddresses
|
||||
}
|
||||
|
||||
func (api *API) PrepareMintCollectiblesData(walletAddresses []string, amount *bigint.BigInt) []common.Address {
|
||||
totalAddresses := api.multiplyWalletAddresses(amount, walletAddresses)
|
||||
var usersAddresses = []common.Address{}
|
||||
for _, k := range totalAddresses {
|
||||
usersAddresses = append(usersAddresses, common.HexToAddress(k))
|
||||
}
|
||||
return usersAddresses
|
||||
}
|
||||
|
||||
// Universal minting function for every type of token.
|
||||
func (api *API) MintTokens(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, walletAddresses []string, amount *bigint.BigInt) (string, error) {
|
||||
|
||||
err := api.ValidateWalletsAndAmounts(walletAddresses, amount)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
contractInst, err := NewTokenInstance(api, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tx, err := contractInst.Mint(transactOpts, walletAddresses, amount)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.AirdropCommunityToken,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tx.Hash().Hex(), nil
|
||||
}
|
||||
|
||||
func (api *API) EstimateMintTokens(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) {
|
||||
tokenType, err := api.s.db.GetTokenType(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch tokenType {
|
||||
case protobuf.CommunityTokenType_ERC721:
|
||||
return api.EstimateMintCollectibles(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount)
|
||||
case protobuf.CommunityTokenType_ERC20:
|
||||
return api.EstimateMintAssets(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount)
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown token type: %v", tokenType)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) EstimateMintCollectibles(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) {
|
||||
err := api.ValidateWalletsAndAmounts(walletAddresses, amount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
usersAddresses := api.PrepareMintCollectiblesData(walletAddresses, amount)
|
||||
return api.estimateMethod(ctx, chainID, contractAddress, fromAddress, "mintTo", usersAddresses)
|
||||
}
|
||||
|
||||
func (api *API) PrepareMintAssetsData(walletAddresses []string, amount *bigint.BigInt) ([]common.Address, []*big.Int) {
|
||||
var usersAddresses = []common.Address{}
|
||||
var amountsList = []*big.Int{}
|
||||
for _, k := range walletAddresses {
|
||||
usersAddresses = append(usersAddresses, common.HexToAddress(k))
|
||||
amountsList = append(amountsList, amount.Int)
|
||||
}
|
||||
return usersAddresses, amountsList
|
||||
}
|
||||
|
||||
// Estimate MintAssets cost.
|
||||
func (api *API) EstimateMintAssets(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) {
|
||||
err := api.ValidateWalletsAndAmounts(walletAddresses, amount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
usersAddresses, amountsList := api.PrepareMintAssetsData(walletAddresses, amount)
|
||||
return api.estimateMethod(ctx, chainID, contractAddress, fromAddress, "mintTo", usersAddresses, amountsList)
|
||||
}
|
||||
|
||||
// This is only ERC721 function
|
||||
func (api *API) RemoteDestructedAmount(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewCollectiblesInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// total supply = airdropped only (w/o burnt)
|
||||
totalSupply, err := contractInst.TotalSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// minted = all created tokens (airdropped and remotely destructed)
|
||||
mintedCount, err := contractInst.MintedCount(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res = new(big.Int)
|
||||
res.Sub(mintedCount, totalSupply)
|
||||
|
||||
return &bigint.BigInt{Int: res}, nil
|
||||
}
|
||||
|
||||
// This is only ERC721 function
|
||||
func (api *API) RemoteBurn(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, tokenIds []*bigint.BigInt) (string, error) {
|
||||
err := api.validateTokens(tokenIds)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
var tempTokenIds []*big.Int
|
||||
for _, v := range tokenIds {
|
||||
tempTokenIds = append(tempTokenIds, v.Int)
|
||||
}
|
||||
|
||||
contractInst, err := NewTokenInstance(api, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tx, err := contractInst.RemoteBurn(transactOpts, tempTokenIds)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.RemoteDestructCollectible,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tx.Hash().Hex(), nil
|
||||
}
|
||||
|
||||
// This is only ERC721 function
|
||||
func (api *API) EstimateRemoteBurn(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, tokenIds []*bigint.BigInt) (uint64, error) {
|
||||
err := api.validateTokens(tokenIds)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var tempTokenIds []*big.Int
|
||||
for _, v := range tokenIds {
|
||||
tempTokenIds = append(tempTokenIds, v.Int)
|
||||
}
|
||||
|
||||
return api.estimateMethod(ctx, chainID, contractAddress, fromAddress, "remoteBurn", tempTokenIds)
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesContractInstance(chainID uint64, contractAddress string) (*collectibles.Collectibles, error) {
|
||||
return api.s.manager.GetCollectiblesContractInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (api *API) GetAssetContractInstance(chainID uint64, contractAddress string) (*assets.Assets, error) {
|
||||
return api.s.manager.GetAssetContractInstance(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (api *API) RemainingSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) {
|
||||
tokenType, err := api.s.db.GetTokenType(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch tokenType {
|
||||
case protobuf.CommunityTokenType_ERC721:
|
||||
return api.remainingCollectiblesSupply(ctx, chainID, contractAddress)
|
||||
case protobuf.CommunityTokenType_ERC20:
|
||||
return api.remainingAssetsSupply(ctx, chainID, contractAddress)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown token type: %v", tokenType)
|
||||
}
|
||||
}
|
||||
|
||||
// RemainingSupply = MaxSupply - MintedCount
|
||||
func (api *API) remainingCollectiblesSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewCollectiblesInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
maxSupply, err := contractInst.MaxSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mintedCount, err := contractInst.MintedCount(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res = new(big.Int)
|
||||
res.Sub(maxSupply, mintedCount)
|
||||
return &bigint.BigInt{Int: res}, nil
|
||||
}
|
||||
|
||||
// RemainingSupply = MaxSupply - TotalSupply
|
||||
func (api *API) remainingAssetsSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewAssetsInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
maxSupply, err := contractInst.MaxSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalSupply, err := contractInst.TotalSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res = new(big.Int)
|
||||
res.Sub(maxSupply, totalSupply)
|
||||
return &bigint.BigInt{Int: res}, nil
|
||||
}
|
||||
|
||||
func (api *API) maxSupplyCollectibles(ctx context.Context, chainID uint64, contractAddress string) (*big.Int, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewCollectiblesInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contractInst.MaxSupply(callOpts)
|
||||
}
|
||||
|
||||
func (api *API) maxSupplyAssets(ctx context.Context, chainID uint64, contractAddress string) (*big.Int, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewAssetsInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contractInst.MaxSupply(callOpts)
|
||||
}
|
||||
|
||||
func (api *API) maxSupply(ctx context.Context, chainID uint64, contractAddress string) (*big.Int, error) {
|
||||
tokenType, err := api.s.db.GetTokenType(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch tokenType {
|
||||
case protobuf.CommunityTokenType_ERC721:
|
||||
return api.maxSupplyCollectibles(ctx, chainID, contractAddress)
|
||||
case protobuf.CommunityTokenType_ERC20:
|
||||
return api.maxSupplyAssets(ctx, chainID, contractAddress)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown token type: %v", tokenType)
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) prepareNewMaxSupply(ctx context.Context, chainID uint64, contractAddress string, burnAmount *bigint.BigInt) (*big.Int, error) {
|
||||
maxSupply, err := api.maxSupply(ctx, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var newMaxSupply = new(big.Int)
|
||||
newMaxSupply.Sub(maxSupply, burnAmount.Int)
|
||||
return newMaxSupply, nil
|
||||
}
|
||||
|
||||
func (api *API) Burn(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, burnAmount *bigint.BigInt) (string, error) {
|
||||
err := api.validateBurnAmount(ctx, burnAmount, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.s.accountsManager, api.s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
newMaxSupply, err := api.prepareNewMaxSupply(ctx, chainID, contractAddress, burnAmount)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
contractInst, err := NewTokenInstance(api, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tx, err := contractInst.SetMaxSupply(transactOpts, newMaxSupply)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = api.s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.BurnCommunityToken,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tx.Hash().Hex(), nil
|
||||
}
|
||||
|
||||
func (api *API) EstimateBurn(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, burnAmount *bigint.BigInt) (uint64, error) {
|
||||
err := api.validateBurnAmount(ctx, burnAmount, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
newMaxSupply, err := api.prepareNewMaxSupply(ctx, chainID, contractAddress, burnAmount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return api.estimateMethod(ctx, chainID, contractAddress, fromAddress, "setMaxSupply", newMaxSupply)
|
||||
}
|
||||
|
||||
func (api *API) ValidateWalletsAndAmounts(walletAddresses []string, amount *bigint.BigInt) error {
|
||||
if len(walletAddresses) == 0 {
|
||||
return errors.New("wallet addresses list is empty")
|
||||
}
|
||||
if amount.Cmp(big.NewInt(0)) <= 0 {
|
||||
return errors.New("amount is <= 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) validateTokens(tokenIds []*bigint.BigInt) error {
|
||||
if len(tokenIds) == 0 {
|
||||
return errors.New("token list is empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) validateBurnAmount(ctx context.Context, burnAmount *bigint.BigInt, chainID uint64, contractAddress string) error {
|
||||
if burnAmount.Cmp(big.NewInt(0)) <= 0 {
|
||||
return errors.New("burnAmount is less than 0")
|
||||
}
|
||||
remainingSupply, err := api.RemainingSupply(ctx, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if burnAmount.Cmp(remainingSupply.Int) > 1 {
|
||||
return errors.New("burnAmount is bigger than remaining amount")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) estimateMethodForTokenInstance(ctx context.Context, contractInstance TokenInstance, chainID uint64, contractAddress string, fromAddress string, methodName string, args ...interface{}) (uint64, error) {
|
||||
ethClient, err := api.s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
||||
data, err := contractInstance.PackMethod(ctx, methodName, args...)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
toAddr := common.HexToAddress(contractAddress)
|
||||
fromAddr := common.HexToAddress(fromAddress)
|
||||
|
||||
callMsg := ethereum.CallMsg{
|
||||
From: fromAddr,
|
||||
To: &toAddr,
|
||||
Value: big.NewInt(0),
|
||||
Data: data,
|
||||
}
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + uint64(float32(estimate)*0.1), nil
|
||||
}
|
||||
|
||||
func (api *API) estimateMethod(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, methodName string, args ...interface{}) (uint64, error) {
|
||||
contractInst, err := NewTokenInstance(api, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return api.estimateMethodForTokenInstance(ctx, contractInst, chainID, contractAddress, fromAddress, methodName, args...)
|
||||
}
|
||||
|
||||
// Gets signer public key from smart contract with a given chainId and address
|
||||
func (api *API) GetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string) (string, error) {
|
||||
return api.s.GetSignerPubKey(ctx, chainID, contractAddress)
|
||||
}
|
||||
|
||||
// Gets signer public key directly from deployer contract
|
||||
func (api *API) SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error) {
|
||||
return api.s.SafeGetSignerPubKey(ctx, chainID, communityID)
|
||||
}
|
||||
|
||||
// Gets owner token contract address from deployer contract
|
||||
func (api *API) SafeGetOwnerTokenAddress(ctx context.Context, chainID uint64, communityID string) (string, error) {
|
||||
return api.s.SafeGetOwnerTokenAddress(ctx, chainID, communityID)
|
||||
}
|
||||
|
||||
func (api *API) SetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, newSignerPubKey string) (string, error) {
|
||||
return api.s.SetSignerPubKey(ctx, chainID, contractAddress, txArgs, password, newSignerPubKey)
|
||||
}
|
||||
|
||||
func (api *API) EstimateSetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, newSignerPubKey string) (uint64, error) {
|
||||
if len(newSignerPubKey) <= 0 {
|
||||
return 0, fmt.Errorf("signerPubKey is empty")
|
||||
}
|
||||
|
||||
contractInst, err := api.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ownerTokenInstance := &OwnerTokenInstance{instance: contractInst}
|
||||
|
||||
return api.estimateMethodForTokenInstance(ctx, ownerTokenInstance, chainID, contractAddress, fromAddress, "setSignerPublicKey", common.FromHex(newSignerPubKey))
|
||||
}
|
||||
|
||||
func (api *API) OwnerTokenOwnerAddress(ctx context.Context, chainID uint64, contractAddress string) (string, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := api.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ownerAddress, err := contractInst.OwnerOf(callOpts, big.NewInt(0))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ownerAddress.Hex(), nil
|
||||
}
|
||||
8
vendor/github.com/status-im/status-go/services/communitytokens/asset_contract_data.go
generated
vendored
Normal file
8
vendor/github.com/status-im/status-go/services/communitytokens/asset_contract_data.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package communitytokens
|
||||
|
||||
import "github.com/status-im/status-go/services/wallet/bigint"
|
||||
|
||||
type AssetContractData struct {
|
||||
TotalSupply *bigint.BigInt
|
||||
InfiniteSupply bool
|
||||
}
|
||||
10
vendor/github.com/status-im/status-go/services/communitytokens/collectible_contract_data.go
generated
vendored
Normal file
10
vendor/github.com/status-im/status-go/services/communitytokens/collectible_contract_data.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package communitytokens
|
||||
|
||||
import "github.com/status-im/status-go/services/wallet/bigint"
|
||||
|
||||
type CollectibleContractData struct {
|
||||
TotalSupply *bigint.BigInt
|
||||
Transferable bool
|
||||
RemoteBurnable bool
|
||||
InfiniteSupply bool
|
||||
}
|
||||
66
vendor/github.com/status-im/status-go/services/communitytokens/database.go
generated
vendored
Normal file
66
vendor/github.com/status-im/status-go/services/communitytokens/database.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package communitytokens
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/status-go/protocol/communities/token"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewCommunityTokensDatabase(db *sql.DB) *Database {
|
||||
return &Database{db: db}
|
||||
}
|
||||
|
||||
func (db *Database) GetTokenType(chainID uint64, contractAddress string) (protobuf.CommunityTokenType, error) {
|
||||
var result = protobuf.CommunityTokenType_UNKNOWN_TOKEN_TYPE
|
||||
rows, err := db.db.Query(`SELECT type FROM community_tokens WHERE chain_id=? AND address=? LIMIT 1`, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
err := rows.Scan(&result)
|
||||
return result, err
|
||||
}
|
||||
return result, fmt.Errorf("can't find token: chainId %v, contractAddress %v", chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (db *Database) GetTokenPrivilegesLevel(chainID uint64, contractAddress string) (token.PrivilegesLevel, error) {
|
||||
var result = token.CommunityLevel
|
||||
rows, err := db.db.Query(`SELECT privileges_level FROM community_tokens WHERE chain_id=? AND address=? LIMIT 1`, chainID, contractAddress)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
err := rows.Scan(&result)
|
||||
return result, err
|
||||
}
|
||||
return result, fmt.Errorf("can't find privileges level: chainId %v, contractAddress %v", chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (db *Database) GetCommunityERC20Metadata() ([]*token.CommunityToken, error) {
|
||||
rows, err := db.db.Query(`SELECT community_id, address, name, symbol, chain_id FROM community_tokens WHERE type = ?`, protobuf.CommunityTokenType_ERC20)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []*token.CommunityToken
|
||||
for rows.Next() {
|
||||
token := token.CommunityToken{}
|
||||
err := rows.Scan(&token.CommunityID, &token.Address, &token.Name, &token.Symbol, &token.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, &token)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
208
vendor/github.com/status-im/status-go/services/communitytokens/manager.go
generated
vendored
Normal file
208
vendor/github.com/status-im/status-go/services/communitytokens/manager.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package communitytokens
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/assets"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/collectibles"
|
||||
communitytokendeployer "github.com/status-im/status-go/contracts/community-tokens/deployer"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
rpcClient *rpc.Client
|
||||
}
|
||||
|
||||
func NewManager(rpcClient *rpc.Client) *Manager {
|
||||
return &Manager{
|
||||
rpcClient: rpcClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) NewCollectiblesInstance(chainID uint64, contractAddress string) (*collectibles.Collectibles, error) {
|
||||
backend, err := m.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return collectibles.NewCollectibles(common.HexToAddress(contractAddress), backend)
|
||||
}
|
||||
|
||||
func (m *Manager) NewCommunityTokenDeployerInstance(chainID uint64) (*communitytokendeployer.CommunityTokenDeployer, error) {
|
||||
backend, err := m.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployerAddr, err := communitytokendeployer.ContractAddress(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return communitytokendeployer.NewCommunityTokenDeployer(deployerAddr, backend)
|
||||
}
|
||||
|
||||
func (m *Manager) GetCollectiblesContractInstance(chainID uint64, contractAddress string) (*collectibles.Collectibles, error) {
|
||||
contractInst, err := m.NewCollectiblesInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contractInst, nil
|
||||
}
|
||||
|
||||
func (m *Manager) NewAssetsInstance(chainID uint64, contractAddress string) (*assets.Assets, error) {
|
||||
backend, err := m.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return assets.NewAssets(common.HexToAddress(contractAddress), backend)
|
||||
}
|
||||
|
||||
func (m *Manager) GetAssetContractInstance(chainID uint64, contractAddress string) (*assets.Assets, error) {
|
||||
contractInst, err := m.NewAssetsInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contractInst, nil
|
||||
}
|
||||
|
||||
func (m *Manager) GetCollectibleContractData(chainID uint64, contractAddress string) (*CollectibleContractData, error) {
|
||||
callOpts := &bind.CallOpts{Context: context.Background(), Pending: false}
|
||||
|
||||
contract, err := m.GetCollectiblesContractInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalSupply, err := contract.MaxSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transferable, err := contract.Transferable(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteBurnable, err := contract.RemoteBurnable(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CollectibleContractData{
|
||||
TotalSupply: &bigint.BigInt{Int: totalSupply},
|
||||
Transferable: transferable,
|
||||
RemoteBurnable: remoteBurnable,
|
||||
InfiniteSupply: GetInfiniteSupply().Cmp(totalSupply) == 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Manager) GetAssetContractData(chainID uint64, contractAddress string) (*AssetContractData, error) {
|
||||
callOpts := &bind.CallOpts{Context: context.Background(), Pending: false}
|
||||
contract, err := m.GetAssetContractInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalSupply, err := contract.MaxSupply(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AssetContractData{
|
||||
TotalSupply: &bigint.BigInt{Int: totalSupply},
|
||||
InfiniteSupply: GetInfiniteSupply().Cmp(totalSupply) == 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convert33BytesPubKeyToEthAddress(pubKey string) (common.Address, error) {
|
||||
decoded, err := types.DecodeHex(pubKey)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
communityPubKey, err := crypto.DecompressPubkey(decoded)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
return common.Address(crypto.PubkeyToAddress(*communityPubKey)), nil
|
||||
}
|
||||
|
||||
// Simpler version of hashing typed structured data alternative to typedStructuredDataHash. Keeping this for reference.
|
||||
func customTypedStructuredDataHash(domainSeparator []byte, signatureTypedHash []byte, signer string, deployer string) types.Hash {
|
||||
// every field should be 32 bytes, eth address is 20 bytes so padding should be added
|
||||
emptyOffset := [12]byte{}
|
||||
hashedEncoded := crypto.Keccak256Hash(signatureTypedHash, emptyOffset[:], common.HexToAddress(signer).Bytes(),
|
||||
emptyOffset[:], common.HexToAddress(deployer).Bytes())
|
||||
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", domainSeparator, hashedEncoded.Bytes()))
|
||||
return crypto.Keccak256Hash(rawData)
|
||||
}
|
||||
|
||||
// Returns a typed structured hash according to https://eips.ethereum.org/EIPS/eip-712
|
||||
// Domain separator from smart contract is used.
|
||||
func typedStructuredDataHash(domainSeparator []byte, signer string, addressFrom string, deployerContractAddress string, chainID uint64) (types.Hash, error) {
|
||||
myTypedData := apitypes.TypedData{
|
||||
Types: apitypes.Types{
|
||||
"Deploy": []apitypes.Type{
|
||||
{Name: "signer", Type: "address"},
|
||||
{Name: "deployer", Type: "address"},
|
||||
},
|
||||
"EIP712Domain": []apitypes.Type{
|
||||
{Name: "name", Type: "string"},
|
||||
{Name: "version", Type: "string"},
|
||||
{Name: "chainId", Type: "uint256"},
|
||||
{Name: "verifyingContract", Type: "address"},
|
||||
},
|
||||
},
|
||||
PrimaryType: "Deploy",
|
||||
// Domain field should be here to keep correct structure but
|
||||
// domainSeparator from smart contract is used.
|
||||
Domain: apitypes.TypedDataDomain{
|
||||
Name: "CommunityTokenDeployer", // name from Deployer smart contract
|
||||
Version: "1", // version from Deployer smart contract
|
||||
ChainId: math.NewHexOrDecimal256(int64(chainID)),
|
||||
VerifyingContract: deployerContractAddress,
|
||||
},
|
||||
Message: apitypes.TypedDataMessage{
|
||||
"signer": signer,
|
||||
"deployer": addressFrom,
|
||||
},
|
||||
}
|
||||
|
||||
typedDataHash, err := myTypedData.HashStruct(myTypedData.PrimaryType, myTypedData.Message)
|
||||
if err != nil {
|
||||
return types.Hash{}, err
|
||||
}
|
||||
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", domainSeparator, string(typedDataHash)))
|
||||
return crypto.Keccak256Hash(rawData), nil
|
||||
}
|
||||
|
||||
// Creates
|
||||
func (m *Manager) DeploymentSignatureDigest(chainID uint64, addressFrom string, communityID string) ([]byte, error) {
|
||||
callOpts := &bind.CallOpts{Pending: false}
|
||||
communityEthAddr, err := convert33BytesPubKeyToEthAddress(communityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deployerAddr, err := communitytokendeployer.ContractAddress(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployerContractInst, err := m.NewCommunityTokenDeployerInstance(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainSeparator, err := deployerContractInst.DOMAINSEPARATOR(callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
structedHash, err := typedStructuredDataHash(domainSeparator[:], communityEthAddr.Hex(), addressFrom, deployerAddr.Hex(), chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return structedHash.Bytes(), nil
|
||||
}
|
||||
188
vendor/github.com/status-im/status-go/services/communitytokens/service.go
generated
vendored
Normal file
188
vendor/github.com/status-im/status-go/services/communitytokens/service.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
package communitytokens
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
ethRpc "github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/status-im/status-go/account"
|
||||
"github.com/status-im/status-go/contracts/community-tokens/ownertoken"
|
||||
communityownertokenregistry "github.com/status-im/status-go/contracts/community-tokens/registry"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/utils"
|
||||
wcommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
||||
type ServiceInterface interface {
|
||||
GetCollectibleContractData(chainID uint64, contractAddress string) (*CollectibleContractData, error)
|
||||
SetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, newSignerPubKey string) (string, error)
|
||||
GetAssetContractData(chainID uint64, contractAddress string) (*AssetContractData, error)
|
||||
SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error)
|
||||
DeploymentSignatureDigest(chainID uint64, addressFrom string, communityID string) ([]byte, error)
|
||||
}
|
||||
|
||||
// Collectibles service
|
||||
type Service struct {
|
||||
manager *Manager
|
||||
accountsManager *account.GethManager
|
||||
pendingTracker *transactions.PendingTxTracker
|
||||
config *params.NodeConfig
|
||||
db *Database
|
||||
}
|
||||
|
||||
// Returns a new Collectibles Service.
|
||||
func NewService(rpcClient *rpc.Client, accountsManager *account.GethManager, pendingTracker *transactions.PendingTxTracker, config *params.NodeConfig, appDb *sql.DB) *Service {
|
||||
return &Service{
|
||||
manager: &Manager{rpcClient: rpcClient},
|
||||
accountsManager: accountsManager,
|
||||
pendingTracker: pendingTracker,
|
||||
config: config,
|
||||
db: NewCommunityTokensDatabase(appDb),
|
||||
}
|
||||
}
|
||||
|
||||
// Protocols returns a new protocols list. In this case, there are none.
|
||||
func (s *Service) Protocols() []p2p.Protocol {
|
||||
return []p2p.Protocol{}
|
||||
}
|
||||
|
||||
// APIs returns a list of new APIs.
|
||||
func (s *Service) APIs() []ethRpc.API {
|
||||
return []ethRpc.API{
|
||||
{
|
||||
Namespace: "communitytokens",
|
||||
Version: "0.1.0",
|
||||
Service: NewAPI(s),
|
||||
Public: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Start is run when a service is started.
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop is run when a service is stopped.
|
||||
func (s *Service) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) NewCommunityOwnerTokenRegistryInstance(chainID uint64, contractAddress string) (*communityownertokenregistry.CommunityOwnerTokenRegistry, error) {
|
||||
backend, err := s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return communityownertokenregistry.NewCommunityOwnerTokenRegistry(common.HexToAddress(contractAddress), backend)
|
||||
}
|
||||
|
||||
func (s *Service) NewOwnerTokenInstance(chainID uint64, contractAddress string) (*ownertoken.OwnerToken, error) {
|
||||
|
||||
backend, err := s.manager.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ownertoken.NewOwnerToken(common.HexToAddress(contractAddress), backend)
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) GetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string) (string, error) {
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contractInst, err := s.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signerPubKey, err := contractInst.SignerPublicKey(callOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return types.ToHex(signerPubKey), nil
|
||||
}
|
||||
|
||||
func (s *Service) SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error) {
|
||||
// 1. Get Owner Token contract address from deployer contract - SafeGetOwnerTokenAddress()
|
||||
ownerTokenAddr, err := s.SafeGetOwnerTokenAddress(ctx, chainID, communityID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 2. Get Signer from owner token contract - GetSignerPubKey()
|
||||
return s.GetSignerPubKey(ctx, chainID, ownerTokenAddr)
|
||||
}
|
||||
|
||||
func (s *Service) SafeGetOwnerTokenAddress(ctx context.Context, chainID uint64, communityID string) (string, error) {
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
deployerContractInst, err := s.manager.NewCommunityTokenDeployerInstance(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
registryAddr, err := deployerContractInst.DeploymentRegistry(callOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
registryContractInst, err := s.NewCommunityOwnerTokenRegistryInstance(chainID, registryAddr.Hex())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
communityEthAddress, err := convert33BytesPubKeyToEthAddress(communityID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ownerTokenAddress, err := registryContractInst.GetEntry(callOpts, communityEthAddress)
|
||||
|
||||
return ownerTokenAddress.Hex(), err
|
||||
}
|
||||
|
||||
func (s *Service) GetCollectibleContractData(chainID uint64, contractAddress string) (*CollectibleContractData, error) {
|
||||
return s.manager.GetCollectibleContractData(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (s *Service) GetAssetContractData(chainID uint64, contractAddress string) (*AssetContractData, error) {
|
||||
return s.manager.GetAssetContractData(chainID, contractAddress)
|
||||
}
|
||||
|
||||
func (s *Service) DeploymentSignatureDigest(chainID uint64, addressFrom string, communityID string) ([]byte, error) {
|
||||
return s.manager.DeploymentSignatureDigest(chainID, addressFrom, communityID)
|
||||
}
|
||||
|
||||
func (s *Service) SetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, newSignerPubKey string) (string, error) {
|
||||
|
||||
if len(newSignerPubKey) <= 0 {
|
||||
return "", fmt.Errorf("signerPubKey is empty")
|
||||
}
|
||||
|
||||
transactOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, s.accountsManager, s.config.KeyStoreDir, txArgs.From, password))
|
||||
|
||||
contractInst, err := s.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tx, err := contractInst.SetSignerPublicKey(transactOpts, common.FromHex(newSignerPubKey))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = s.pendingTracker.TrackPendingTransaction(
|
||||
wcommon.ChainID(chainID),
|
||||
tx.Hash(),
|
||||
common.Address(txArgs.From),
|
||||
transactions.SetSignerPublicKey,
|
||||
transactions.AutoDelete,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("TrackPendingTransaction error", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tx.Hash().Hex(), nil
|
||||
}
|
||||
179
vendor/github.com/status-im/status-go/services/communitytokens/token_instances.go
generated
vendored
Normal file
179
vendor/github.com/status-im/status-go/services/communitytokens/token_instances.go
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
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
|
||||
api *API
|
||||
}
|
||||
|
||||
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 := t.api.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
|
||||
api *API
|
||||
}
|
||||
|
||||
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 := t.api.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
|
||||
api *API
|
||||
}
|
||||
|
||||
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 := t.api.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(api *API, chainID uint64, contractAddress string) (TokenInstance, error) {
|
||||
tokenType, err := api.s.db.GetTokenType(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privLevel, err := api.s.db.GetTokenPrivilegesLevel(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case privLevel == token.OwnerLevel:
|
||||
contractInst, err := api.NewOwnerTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &OwnerTokenInstance{instance: contractInst}, nil
|
||||
case privLevel == token.MasterLevel:
|
||||
contractInst, err := api.NewMasterTokenInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MasterTokenInstance{instance: contractInst}, nil
|
||||
case tokenType == protobuf.CommunityTokenType_ERC721:
|
||||
contractInst, err := api.NewCollectiblesInstance(chainID, contractAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CollectibleInstance{instance: contractInst}, nil
|
||||
case tokenType == protobuf.CommunityTokenType_ERC20:
|
||||
contractInst, err := api.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)
|
||||
}
|
||||
Reference in New Issue
Block a user