diff --git a/node/status_node_services.go b/node/status_node_services.go index 468b45400..d55dcea6c 100644 --- a/node/status_node_services.go +++ b/node/status_node_services.go @@ -487,7 +487,7 @@ func (b *StatusNode) pendingTrackerService(walletFeed *event.Feed) *transactions func (b *StatusNode) CommunityTokensService() *communitytokens.Service { if b.communityTokensSrvc == nil { - b.communityTokensSrvc = communitytokens.NewService(b.rpcClient, b.gethAccountManager, b.pendingTracker, b.config, b.appDB, &b.walletFeed) + b.communityTokensSrvc = communitytokens.NewService(b.rpcClient, b.gethAccountManager, b.pendingTracker, b.config, b.appDB, &b.walletFeed, b.transactor) } return b.communityTokensSrvc } diff --git a/services/communitytokens/api.go b/services/communitytokens/api.go index 6c7a3004c..8ff6e1837 100644 --- a/services/communitytokens/api.go +++ b/services/communitytokens/api.go @@ -4,19 +4,16 @@ import ( "context" "fmt" "math/big" - "strings" "github.com/pkg/errors" - "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" @@ -321,147 +318,35 @@ func (api *API) DeployAssets(ctx context.Context, chainID uint64, deploymentPara CommunityToken: savedCommunityToken}, nil } -// Returns gas units + 10% -func (api *API) DeployCollectiblesEstimate(ctx context.Context, chainID uint64, fromAddress string) (uint64, error) { - ethClient, err := api.s.manager.rpcClient.EthClient(chainID) - if err != nil { - log.Error(err.Error()) - return 0, err - } - - collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI)) - if err != nil { - return 0, err - } - - // use random parameters, they will not have impact on deployment results - data, err := collectiblesABI.Pack("" /*constructor name is empty*/, "name", "SYMBOL", big.NewInt(20), true, false, "tokenUri", - common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"), common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110")) - if err != nil { - return 0, err - } - - callMsg := ethereum.CallMsg{ - From: common.HexToAddress(fromAddress), - To: nil, - Value: big.NewInt(0), - Data: append(common.FromHex(collectibles.CollectiblesBin), data...), - } - estimate, err := ethClient.EstimateGas(ctx, callMsg) - if err != nil { - return 0, err - } - - finalEstimation := estimate + uint64(float32(estimate)*0.1) - log.Debug("Collectibles deployment gas estimation: ", finalEstimation) - return finalEstimation, nil +func (api *API) DeployCollectiblesEstimate(ctx context.Context, chainID uint64, fromAddress string) (*CommunityTokenFees, error) { + return api.s.deployCollectiblesEstimate(ctx, chainID, fromAddress) } -// Returns gas units + 10% -func (api *API) DeployAssetsEstimate(ctx context.Context, chainID uint64, fromAddress string) (uint64, error) { - ethClient, err := api.s.manager.rpcClient.EthClient(chainID) - if err != nil { - log.Error(err.Error()) - return 0, err - } - - assetsABI, err := abi.JSON(strings.NewReader(assets.AssetsABI)) - if err != nil { - return 0, err - } - - // use random parameters, they will not have impact on deployment results - data, err := assetsABI.Pack("" /*constructor name is empty*/, "name", "SYMBOL", uint8(18), big.NewInt(20), "tokenUri", - common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"), common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110")) - if err != nil { - return 0, err - } - - callMsg := ethereum.CallMsg{ - From: common.HexToAddress(fromAddress), - To: nil, - Value: big.NewInt(0), - Data: append(common.FromHex(assets.AssetsBin), data...), - } - estimate, err := ethClient.EstimateGas(ctx, callMsg) - if err != nil { - return 0, err - } - - finalEstimation := estimate + uint64(float32(estimate)*0.1) - log.Debug("Assets deployment gas estimation: ", finalEstimation) - return finalEstimation, nil +func (api *API) DeployAssetsEstimate(ctx context.Context, chainID uint64, fromAddress string) (*CommunityTokenFees, error) { + return api.s.deployAssetsEstimate(ctx, chainID, fromAddress) } func (api *API) DeployOwnerTokenEstimate(ctx context.Context, chainID uint64, fromAddress string, ownerTokenParameters DeploymentParameters, masterTokenParameters DeploymentParameters, - 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, - } - - signature, err := api.s.Messenger.CreateCommunityTokenDeploymentSignature(ctx, chainID, fromAddress, communityID) - if err != nil { - return 0, err - } - - communitySignature, err := prepareDeploymentSignatureStruct(types.HexBytes(signature).String(), 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 + communityID string, signerPubKey string) (*CommunityTokenFees, error) { + return api.s.deployOwnerTokenEstimate(ctx, chainID, fromAddress, ownerTokenParameters, masterTokenParameters, communityID, signerPubKey) } -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) EstimateMintTokens(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (*CommunityTokenFees, error) { + return api.s.mintTokensEstimate(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount) +} + +// This is only ERC721 function +func (api *API) EstimateRemoteBurn(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, tokenIds []*bigint.BigInt) (*CommunityTokenFees, error) { + return api.s.remoteBurnEstimate(ctx, chainID, contractAddress, fromAddress, tokenIds) +} + +func (api *API) EstimateBurn(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, burnAmount *bigint.BigInt) (*CommunityTokenFees, error) { + return api.s.burnEstimate(ctx, chainID, contractAddress, fromAddress, burnAmount) +} + +func (api *API) EstimateSetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, newSignerPubKey string) (*CommunityTokenFees, error) { + return api.s.setSignerPubKeyEstimate(ctx, chainID, contractAddress, fromAddress, newSignerPubKey) } func (api *API) NewOwnerTokenInstance(chainID uint64, contractAddress string) (*ownertoken.OwnerToken, error) { @@ -484,37 +369,17 @@ func (api *API) NewAssetsInstance(chainID uint64, contractAddress string) (*asse 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) + err := api.s.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) + contractInst, err := NewTokenInstance(api.s, chainID, contractAddress) if err != nil { return "", err } @@ -541,51 +406,6 @@ func (api *API) MintTokens(ctx context.Context, chainID uint64, contractAddress 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} @@ -614,7 +434,7 @@ func (api *API) RemoteDestructedAmount(ctx context.Context, chainID uint64, cont // This is only ERC721 function func (api *API) RemoteBurn(ctx context.Context, chainID uint64, contractAddress string, txArgs transactions.SendTxArgs, password string, tokenIds []*bigint.BigInt, additionalData string) (string, error) { - err := api.validateTokens(tokenIds) + err := api.s.validateTokens(tokenIds) if err != nil { return "", err } @@ -626,7 +446,7 @@ func (api *API) RemoteBurn(ctx context.Context, chainID uint64, contractAddress tempTokenIds = append(tempTokenIds, v.Int) } - contractInst, err := NewTokenInstance(api, chainID, contractAddress) + contractInst, err := NewTokenInstance(api.s, chainID, contractAddress) if err != nil { return "", err } @@ -653,21 +473,6 @@ func (api *API) RemoteBurn(ctx context.Context, chainID uint64, contractAddress 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) } @@ -677,84 +482,23 @@ func (api *API) GetAssetContractInstance(chainID uint64, contractAddress string) } 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) prepareNewMaxSupply(ctx context.Context, chainID uint64, contractAddress string, burnAmount *bigint.BigInt) (*big.Int, error) { - maxSupply, err := api.s.maxSupply(ctx, chainID, contractAddress) - if err != nil { - return nil, err - } - var newMaxSupply = new(big.Int) - newMaxSupply.Sub(maxSupply, burnAmount.Int) - return newMaxSupply, nil + return api.s.remainingSupply(ctx, chainID, contractAddress) } 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) + err := api.s.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) + newMaxSupply, err := api.s.prepareNewMaxSupply(ctx, chainID, contractAddress, burnAmount) if err != nil { return "", err } - contractInst, err := NewTokenInstance(api, chainID, contractAddress) + contractInst, err := NewTokenInstance(api.s, chainID, contractAddress) if err != nil { return "", err } @@ -781,88 +525,6 @@ func (api *API) Burn(ctx context.Context, chainID uint64, contractAddress string 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) @@ -882,20 +544,6 @@ func (api *API) SetSignerPubKey(ctx context.Context, chainID uint64, contractAdd 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) diff --git a/services/communitytokens/estimations.go b/services/communitytokens/estimations.go new file mode 100644 index 000000000..0bb82ef96 --- /dev/null +++ b/services/communitytokens/estimations.go @@ -0,0 +1,435 @@ +package communitytokens + +import ( + "context" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "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/types" + "github.com/status-im/status-go/protocol/protobuf" + "github.com/status-im/status-go/services/wallet" + "github.com/status-im/status-go/services/wallet/bigint" + "github.com/status-im/status-go/transactions" +) + +type CommunityTokenFees struct { + GasUnits uint64 `json:"gasUnits"` + SuggestedFees *wallet.SuggestedFees `json:"suggestedFees"` +} + +func weiToGwei(val *big.Int) *big.Float { + result := new(big.Float) + result.SetInt(val) + + unit := new(big.Int) + unit.SetInt64(params.GWei) + + return result.Quo(result, new(big.Float).SetInt(unit)) +} + +func gweiToWei(val *big.Float) *big.Int { + res, _ := new(big.Float).Mul(val, big.NewFloat(1000000000)).Int(nil) + return res +} + +func (s *Service) deployOwnerTokenEstimate(ctx context.Context, chainID uint64, fromAddress string, + ownerTokenParameters DeploymentParameters, masterTokenParameters DeploymentParameters, + communityID string, signerPubKey string) (*CommunityTokenFees, error) { + + gasUnits, err := s.deployOwnerTokenGasUnits(ctx, chainID, fromAddress, ownerTokenParameters, masterTokenParameters, + communityID, signerPubKey) + if err != nil { + return nil, err + } + + deployerAddress, err := communitytokendeployer.ContractAddress(chainID) + if err != nil { + return nil, err + } + + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), &deployerAddress, gasUnits, chainID) +} + +func (s *Service) deployCollectiblesEstimate(ctx context.Context, chainID uint64, fromAddress string) (*CommunityTokenFees, error) { + gasUnits, err := s.deployCollectiblesGasUnits(ctx, chainID, fromAddress) + if err != nil { + return nil, err + } + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), nil, gasUnits, chainID) +} + +func (s *Service) deployAssetsEstimate(ctx context.Context, chainID uint64, fromAddress string) (*CommunityTokenFees, error) { + gasUnits, err := s.deployAssetsGasUnits(ctx, chainID, fromAddress) + if err != nil { + return nil, err + } + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), nil, gasUnits, chainID) +} + +func (s *Service) mintTokensEstimate(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (*CommunityTokenFees, error) { + gasUnits, err := s.mintTokensGasUnits(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount) + if err != nil { + return nil, err + } + toAddress := common.HexToAddress(contractAddress) + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), &toAddress, gasUnits, chainID) +} + +func (s *Service) remoteBurnEstimate(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, tokenIds []*bigint.BigInt) (*CommunityTokenFees, error) { + gasUnits, err := s.remoteBurnGasUnits(ctx, chainID, contractAddress, fromAddress, tokenIds) + if err != nil { + return nil, err + } + toAddress := common.HexToAddress(contractAddress) + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), &toAddress, gasUnits, chainID) +} + +func (s *Service) burnEstimate(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, burnAmount *bigint.BigInt) (*CommunityTokenFees, error) { + gasUnits, err := s.burnGasUnits(ctx, chainID, contractAddress, fromAddress, burnAmount) + if err != nil { + return nil, err + } + toAddress := common.HexToAddress(contractAddress) + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), &toAddress, gasUnits, chainID) +} + +func (s *Service) setSignerPubKeyEstimate(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, newSignerPubKey string) (*CommunityTokenFees, error) { + gasUnits, err := s.setSignerPubKeyGasUnits(ctx, chainID, contractAddress, fromAddress, newSignerPubKey) + if err != nil { + return nil, err + } + toAddress := common.HexToAddress(contractAddress) + return s.prepareCommunityTokenFees(ctx, common.HexToAddress(fromAddress), &toAddress, gasUnits, chainID) +} + +func (s *Service) setSignerPubKeyGasUnits(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 := s.NewOwnerTokenInstance(chainID, contractAddress) + if err != nil { + return 0, err + } + ownerTokenInstance := &OwnerTokenInstance{instance: contractInst} + + return s.estimateMethodForTokenInstance(ctx, ownerTokenInstance, chainID, contractAddress, fromAddress, "setSignerPublicKey", common.FromHex(newSignerPubKey)) +} + +func (s *Service) burnGasUnits(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, burnAmount *bigint.BigInt) (uint64, error) { + err := s.validateBurnAmount(ctx, burnAmount, chainID, contractAddress) + if err != nil { + return 0, err + } + + newMaxSupply, err := s.prepareNewMaxSupply(ctx, chainID, contractAddress, burnAmount) + if err != nil { + return 0, err + } + + return s.estimateMethod(ctx, chainID, contractAddress, fromAddress, "setMaxSupply", newMaxSupply) +} + +func (s *Service) remoteBurnGasUnits(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, tokenIds []*bigint.BigInt) (uint64, error) { + err := s.validateTokens(tokenIds) + if err != nil { + return 0, err + } + + var tempTokenIds []*big.Int + for _, v := range tokenIds { + tempTokenIds = append(tempTokenIds, v.Int) + } + + return s.estimateMethod(ctx, chainID, contractAddress, fromAddress, "remoteBurn", tempTokenIds) +} + +func (s *Service) deployOwnerTokenGasUnits(ctx context.Context, chainID uint64, fromAddress string, + ownerTokenParameters DeploymentParameters, masterTokenParameters DeploymentParameters, + communityID string, signerPubKey string) (uint64, error) { + ethClient, err := 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, + } + + signature, err := s.Messenger.CreateCommunityTokenDeploymentSignature(ctx, chainID, fromAddress, communityID) + if err != nil { + return 0, err + } + + communitySignature, err := prepareDeploymentSignatureStruct(types.HexBytes(signature).String(), 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 + } + + finalEstimation := estimate + uint64(float32(estimate)*0.1) + log.Debug("Owner token deployment gas estimation: ", finalEstimation) + return finalEstimation, nil +} + +func (s *Service) deployCollectiblesGasUnits(ctx context.Context, chainID uint64, fromAddress string) (uint64, error) { + ethClient, err := s.manager.rpcClient.EthClient(chainID) + if err != nil { + log.Error(err.Error()) + return 0, err + } + + collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI)) + if err != nil { + return 0, err + } + + // use random parameters, they will not have impact on deployment results + data, err := collectiblesABI.Pack("" /*constructor name is empty*/, "name", "SYMBOL", big.NewInt(20), true, false, "tokenUri", + common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"), common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110")) + if err != nil { + return 0, err + } + + callMsg := ethereum.CallMsg{ + From: common.HexToAddress(fromAddress), + To: nil, + Value: big.NewInt(0), + Data: append(common.FromHex(collectibles.CollectiblesBin), data...), + } + estimate, err := ethClient.EstimateGas(ctx, callMsg) + if err != nil { + return 0, err + } + + finalEstimation := estimate + uint64(float32(estimate)*0.1) + log.Debug("Collectibles deployment gas estimation: ", finalEstimation) + return finalEstimation, nil +} + +func (s *Service) deployAssetsGasUnits(ctx context.Context, chainID uint64, fromAddress string) (uint64, error) { + ethClient, err := s.manager.rpcClient.EthClient(chainID) + if err != nil { + log.Error(err.Error()) + return 0, err + } + + assetsABI, err := abi.JSON(strings.NewReader(assets.AssetsABI)) + if err != nil { + return 0, err + } + + // use random parameters, they will not have impact on deployment results + data, err := assetsABI.Pack("" /*constructor name is empty*/, "name", "SYMBOL", uint8(18), big.NewInt(20), "tokenUri", + common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110"), common.HexToAddress("0x77b48394c650520012795a1a25696d7eb542d110")) + if err != nil { + return 0, err + } + + callMsg := ethereum.CallMsg{ + From: common.HexToAddress(fromAddress), + To: nil, + Value: big.NewInt(0), + Data: append(common.FromHex(assets.AssetsBin), data...), + } + estimate, err := ethClient.EstimateGas(ctx, callMsg) + if err != nil { + return 0, err + } + + finalEstimation := estimate + uint64(float32(estimate)*0.1) + log.Debug("Assets deployment gas estimation: ", finalEstimation) + return finalEstimation, nil +} + +// 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 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 prepareMintCollectiblesData(walletAddresses []string, amount *bigint.BigInt) []common.Address { + totalAddresses := multiplyWalletAddresses(amount, walletAddresses) + var usersAddresses = []common.Address{} + for _, k := range totalAddresses { + usersAddresses = append(usersAddresses, common.HexToAddress(k)) + } + return usersAddresses +} + +func 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 +} + +func (s *Service) mintCollectiblesGasUnits(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) { + err := s.ValidateWalletsAndAmounts(walletAddresses, amount) + if err != nil { + return 0, err + } + usersAddresses := prepareMintCollectiblesData(walletAddresses, amount) + return s.estimateMethod(ctx, chainID, contractAddress, fromAddress, "mintTo", usersAddresses) +} + +func (s *Service) mintAssetsGasUnits(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) { + err := s.ValidateWalletsAndAmounts(walletAddresses, amount) + if err != nil { + return 0, err + } + usersAddresses, amountsList := prepareMintAssetsData(walletAddresses, amount) + return s.estimateMethod(ctx, chainID, contractAddress, fromAddress, "mintTo", usersAddresses, amountsList) +} + +func (s *Service) mintTokensGasUnits(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, walletAddresses []string, amount *bigint.BigInt) (uint64, error) { + tokenType, err := s.db.GetTokenType(chainID, contractAddress) + if err != nil { + return 0, err + } + + switch tokenType { + case protobuf.CommunityTokenType_ERC721: + return s.mintCollectiblesGasUnits(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount) + case protobuf.CommunityTokenType_ERC20: + return s.mintAssetsGasUnits(ctx, chainID, contractAddress, fromAddress, walletAddresses, amount) + default: + return 0, fmt.Errorf("unknown token type: %v", tokenType) + } +} + +func (s *Service) prepareCommunityTokenFees(ctx context.Context, from common.Address, to *common.Address, gasUnits uint64, chainID uint64) (*CommunityTokenFees, error) { + suggestedFees, err := s.feeManager.SuggestedFees(ctx, chainID) + if err != nil { + return nil, err + } + + txArgs := s.suggestedFeesToSendTxArgs(from, to, gasUnits, suggestedFees) + + l1Fee, err := s.estimateL1Fee(ctx, chainID, txArgs) + if err == nil { + suggestedFees.L1GasFee = weiToGwei(big.NewInt(int64(l1Fee))) + } + return &CommunityTokenFees{ + GasUnits: gasUnits, + SuggestedFees: suggestedFees, + }, nil +} + +func (s *Service) suggestedFeesToSendTxArgs(from common.Address, to *common.Address, gas uint64, suggestedFees *wallet.SuggestedFees) transactions.SendTxArgs { + sendArgs := transactions.SendTxArgs{} + sendArgs.From = types.Address(from) + sendArgs.To = (*types.Address)(to) + sendArgs.Gas = (*hexutil.Uint64)(&gas) + if suggestedFees.EIP1559Enabled { + sendArgs.MaxPriorityFeePerGas = (*hexutil.Big)(gweiToWei(suggestedFees.MaxPriorityFeePerGas)) + sendArgs.MaxFeePerGas = (*hexutil.Big)(gweiToWei(suggestedFees.MaxFeePerGasMedium)) + } else { + sendArgs.GasPrice = (*hexutil.Big)(gweiToWei(suggestedFees.GasPrice)) + } + return sendArgs +} + +func (s *Service) estimateL1Fee(ctx context.Context, chainID uint64, sendArgs transactions.SendTxArgs) (uint64, error) { + transaction, err := s.transactor.ValidateAndBuildTransaction(chainID, sendArgs) + if err != nil { + return 0, err + } + + return s.feeManager.GetL1Fee(ctx, chainID, transaction) +} + +func (s *Service) estimateMethodForTokenInstance(ctx context.Context, contractInstance TokenInstance, chainID uint64, contractAddress string, fromAddress string, methodName string, args ...interface{}) (uint64, error) { + ethClient, err := 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 (s *Service) estimateMethod(ctx context.Context, chainID uint64, contractAddress string, fromAddress string, methodName string, args ...interface{}) (uint64, error) { + contractInst, err := NewTokenInstance(s, chainID, contractAddress) + if err != nil { + return 0, err + } + return s.estimateMethodForTokenInstance(ctx, contractInst, chainID, contractAddress, fromAddress, methodName, args...) +} diff --git a/services/communitytokens/service.go b/services/communitytokens/service.go index 00b8371f7..ccc808e52 100644 --- a/services/communitytokens/service.go +++ b/services/communitytokens/service.go @@ -16,6 +16,7 @@ import ( "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/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" @@ -28,6 +29,7 @@ import ( "github.com/status-im/status-go/rpc" "github.com/status-im/status-go/services/communitytokens/communitytokensdatabase" "github.com/status-im/status-go/services/utils" + "github.com/status-im/status-go/services/wallet" "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/services/wallet/walletevent" @@ -45,11 +47,13 @@ type Service struct { Messenger *protocol.Messenger walletFeed *event.Feed walletWatcher *walletevent.Watcher + transactor *transactions.Transactor + feeManager *wallet.FeeManager } // Returns a new Collectibles Service. func NewService(rpcClient *rpc.Client, accountsManager *account.GethManager, pendingTracker *transactions.PendingTxTracker, - config *params.NodeConfig, appDb *sql.DB, walletFeed *event.Feed) *Service { + config *params.NodeConfig, appDb *sql.DB, walletFeed *event.Feed, transactor *transactions.Transactor) *Service { return &Service{ manager: &Manager{rpcClient: rpcClient}, accountsManager: accountsManager, @@ -57,6 +61,8 @@ func NewService(rpcClient *rpc.Client, accountsManager *account.GethManager, pen config: config, db: communitytokensdatabase.NewCommunityTokensDatabase(appDb), walletFeed: walletFeed, + transactor: transactor, + feeManager: &wallet.FeeManager{RPCClient: rpcClient}, } } @@ -272,6 +278,110 @@ func (s *Service) NewOwnerTokenInstance(chainID uint64, contractAddress string) } +func (s *Service) NewMasterTokenInstance(chainID uint64, contractAddress string) (*mastertoken.MasterToken, error) { + backend, err := s.manager.rpcClient.EthClient(chainID) + if err != nil { + return nil, err + } + return mastertoken.NewMasterToken(common.HexToAddress(contractAddress), backend) +} + +func (s *Service) validateTokens(tokenIds []*bigint.BigInt) error { + if len(tokenIds) == 0 { + return errors.New("token list is empty") + } + return nil +} + +func (s *Service) 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 := s.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 (s *Service) remainingSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) { + tokenType, err := s.db.GetTokenType(chainID, contractAddress) + if err != nil { + return nil, err + } + switch tokenType { + case protobuf.CommunityTokenType_ERC721: + return s.remainingCollectiblesSupply(ctx, chainID, contractAddress) + case protobuf.CommunityTokenType_ERC20: + return s.remainingAssetsSupply(ctx, chainID, contractAddress) + default: + return nil, fmt.Errorf("unknown token type: %v", tokenType) + } +} + +func (s *Service) prepareNewMaxSupply(ctx context.Context, chainID uint64, contractAddress string, burnAmount *bigint.BigInt) (*big.Int, error) { + maxSupply, err := s.maxSupply(ctx, chainID, contractAddress) + if err != nil { + return nil, err + } + var newMaxSupply = new(big.Int) + newMaxSupply.Sub(maxSupply, burnAmount.Int) + return newMaxSupply, nil +} + +// RemainingSupply = MaxSupply - MintedCount +func (s *Service) remainingCollectiblesSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) { + callOpts := &bind.CallOpts{Context: ctx, Pending: false} + contractInst, err := s.manager.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 (s *Service) remainingAssetsSupply(ctx context.Context, chainID uint64, contractAddress string) (*bigint.BigInt, error) { + callOpts := &bind.CallOpts{Context: ctx, Pending: false} + contractInst, err := s.manager.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 (s *Service) 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 (s *Service) GetSignerPubKey(ctx context.Context, chainID uint64, contractAddress string) (string, error) { callOpts := &bind.CallOpts{Context: ctx, Pending: false} diff --git a/services/communitytokens/token_instances.go b/services/communitytokens/token_instances.go index bc6d2fe43..247a49557 100644 --- a/services/communitytokens/token_instances.go +++ b/services/communitytokens/token_instances.go @@ -55,7 +55,6 @@ func (t OwnerTokenInstance) PackMethod(ctx context.Context, methodName string, a type MasterTokenInstance struct { TokenInstance instance *mastertoken.MasterToken - api *API } func (t MasterTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { @@ -63,7 +62,7 @@ func (t MasterTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenId } func (t MasterTokenInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) { - usersAddresses := t.api.PrepareMintCollectiblesData(walletAddresses, amount) + usersAddresses := prepareMintCollectiblesData(walletAddresses, amount) return t.instance.MintTo(transactOpts, usersAddresses) } @@ -83,7 +82,6 @@ func (t MasterTokenInstance) PackMethod(ctx context.Context, methodName string, type CollectibleInstance struct { TokenInstance instance *collectibles.Collectibles - api *API } func (t CollectibleInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { @@ -91,7 +89,7 @@ func (t CollectibleInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenId } func (t CollectibleInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) { - usersAddresses := t.api.PrepareMintCollectiblesData(walletAddresses, amount) + usersAddresses := prepareMintCollectiblesData(walletAddresses, amount) return t.instance.MintTo(transactOpts, usersAddresses) } @@ -111,7 +109,6 @@ func (t CollectibleInstance) PackMethod(ctx context.Context, methodName string, type AssetInstance struct { TokenInstance instance *assets.Assets - api *API } func (t AssetInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) { @@ -121,7 +118,7 @@ func (t AssetInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*b // 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) + usersAddresses, amountsList := prepareMintAssetsData(walletAddresses, amount) return t.instance.MintTo(transactOpts, usersAddresses, amountsList) } @@ -139,36 +136,36 @@ func (t AssetInstance) PackMethod(ctx context.Context, methodName string, args . // creator -func NewTokenInstance(api *API, chainID uint64, contractAddress string) (TokenInstance, error) { - tokenType, err := api.s.db.GetTokenType(chainID, contractAddress) +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 := api.s.db.GetTokenPrivilegesLevel(chainID, contractAddress) + privLevel, err := s.db.GetTokenPrivilegesLevel(chainID, contractAddress) if err != nil { return nil, err } switch { case privLevel == token.OwnerLevel: - contractInst, err := api.NewOwnerTokenInstance(chainID, contractAddress) + contractInst, err := s.NewOwnerTokenInstance(chainID, contractAddress) if err != nil { return nil, err } return &OwnerTokenInstance{instance: contractInst}, nil case privLevel == token.MasterLevel: - contractInst, err := api.NewMasterTokenInstance(chainID, contractAddress) + contractInst, err := s.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) + 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 := api.NewAssetsInstance(chainID, contractAddress) + contractInst, err := s.manager.NewAssetsInstance(chainID, contractAddress) if err != nil { return nil, err } diff --git a/services/wallet/api.go b/services/wallet/api.go index 12ccf0435..3de7c9c2e 100644 --- a/services/wallet/api.go +++ b/services/wallet/api.go @@ -412,7 +412,7 @@ func (api *API) FetchTokenDetails(ctx context.Context, symbols []string) (map[st func (api *API) GetSuggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) { log.Debug("call to GetSuggestedFees") - return api.s.feesManager.suggestedFees(ctx, chainID) + return api.s.feesManager.SuggestedFees(ctx, chainID) } func (api *API) GetEstimatedLatestBlockNumber(ctx context.Context, chainID uint64) (uint64, error) { diff --git a/services/wallet/fees.go b/services/wallet/fees.go index ce0329162..8201eda2b 100644 --- a/services/wallet/fees.go +++ b/services/wallet/fees.go @@ -89,7 +89,7 @@ func gweiToWei(val *big.Float) *big.Int { return res } -func (f *FeeManager) suggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) { +func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) { backend, err := f.RPCClient.EthClient(chainID) if err != nil { return nil, err @@ -256,8 +256,7 @@ func (f *FeeManager) getFeeHistorySorted(chainID uint64) ([]*big.Int, error) { return fees, nil } -func (f *FeeManager) getL1Fee(ctx context.Context, chainID uint64, tx *ethTypes.Transaction) (uint64, error) { - +func (f *FeeManager) GetL1Fee(ctx context.Context, chainID uint64, tx *ethTypes.Transaction) (uint64, error) { ethClient, err := f.RPCClient.EthClient(chainID) if err != nil { return 0, err diff --git a/services/wallet/router.go b/services/wallet/router.go index 7e6998cf1..6f25feabd 100644 --- a/services/wallet/router.go +++ b/services/wallet/router.go @@ -646,7 +646,7 @@ func (r *Router) suggestedRoutes( } group.Add(func(c context.Context) error { - gasFees, err := r.s.feesManager.suggestedFees(ctx, network.ChainID) + gasFees, err := r.s.feesManager.SuggestedFees(ctx, network.ChainID) if err != nil { return err } @@ -747,7 +747,7 @@ func (r *Router) suggestedRoutes( continue } - l1GasFeeWei, _ = r.s.feesManager.getL1Fee(ctx, network.ChainID, tx) + l1GasFeeWei, _ = r.s.feesManager.GetL1Fee(ctx, network.ChainID, tx) l1GasFeeWei += l1ApprovalFee }