github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/erc20/types/proposal.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/ethereum/go-ethereum/common"
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	govtypes "github.com/fibonacci-chain/fbc/x/gov/types"
    10  )
    11  
    12  const (
    13  	// proposalTypeTokenMapping defines the type for a TokenMappingProposal
    14  
    15  	proposalTypeTokenMapping          = "TokenMapping"
    16  	proposalTypeProxyContractRedirect = "ProxyContractRedirect"
    17  
    18  	proposalTypeContractTemplate = "ContractTemplate"
    19  
    20  	ProposalTypeContextTemplateProxy = "proxy"
    21  	ProposalTypeContextTemplateImpl  = "implement"
    22  )
    23  
    24  func init() {
    25  	govtypes.RegisterProposalType(proposalTypeTokenMapping)
    26  	govtypes.RegisterProposalType(proposalTypeProxyContractRedirect)
    27  	govtypes.RegisterProposalType(proposalTypeContractTemplate)
    28  	govtypes.RegisterProposalTypeCodec(TokenMappingProposal{}, "fbexchain/erc20/TokenMappingProposal")
    29  	govtypes.RegisterProposalTypeCodec(ProxyContractRedirectProposal{}, "fbexchain/erc20/ProxyContractRedirectProposal")
    30  	govtypes.RegisterProposalTypeCodec(ContractTemplateProposal{}, "fbexchain/erc20/ContractTemplateProposal")
    31  }
    32  
    33  var (
    34  	_ govtypes.Content = (*TokenMappingProposal)(nil)
    35  	_ govtypes.Content = (*ContractTemplateProposal)(nil)
    36  	_ govtypes.Content = (*ProxyContractRedirectProposal)(nil)
    37  )
    38  
    39  type TokenMappingProposal struct {
    40  	Title       string `json:"title" yaml:"title"`
    41  	Description string `json:"description" yaml:"description"`
    42  	Denom       string `json:"denom" yaml:"denom"`
    43  	Contract    string `json:"contract" yaml:"contract"`
    44  }
    45  
    46  func NewTokenMappingProposal(title, description, denom string, contractAddr *common.Address) TokenMappingProposal {
    47  	contract := ""
    48  	if contractAddr != nil {
    49  		contract = contractAddr.Hex()
    50  	}
    51  	return TokenMappingProposal{title, description, denom, contract}
    52  }
    53  
    54  func (tp TokenMappingProposal) GetTitle() string       { return tp.Title }
    55  func (tp TokenMappingProposal) GetDescription() string { return tp.Description }
    56  func (tp TokenMappingProposal) ProposalRoute() string  { return RouterKey }
    57  func (tp TokenMappingProposal) ProposalType() string   { return proposalTypeTokenMapping }
    58  func (tp TokenMappingProposal) ValidateBasic() sdk.Error {
    59  	if len(strings.TrimSpace(tp.Title)) == 0 {
    60  		return govtypes.ErrInvalidProposalContent("title is required")
    61  	}
    62  	if len(tp.Title) > govtypes.MaxTitleLength {
    63  		return govtypes.ErrInvalidProposalContent("title length is longer than the max")
    64  	}
    65  
    66  	if len(tp.Description) == 0 {
    67  		return govtypes.ErrInvalidProposalContent("description is required")
    68  	}
    69  
    70  	if len(tp.Description) > govtypes.MaxDescriptionLength {
    71  		return govtypes.ErrInvalidProposalContent("description length is longer than the max")
    72  	}
    73  
    74  	if tp.ProposalType() != proposalTypeTokenMapping {
    75  		return govtypes.ErrInvalidProposalType(tp.ProposalType())
    76  	}
    77  
    78  	if len(strings.TrimSpace(tp.Denom)) == 0 {
    79  		return govtypes.ErrInvalidProposalContent("denom is required")
    80  	}
    81  
    82  	if err := sdk.ValidateDenom(tp.Denom); err != nil {
    83  		return govtypes.ErrInvalidProposalContent("invalid denom")
    84  	}
    85  
    86  	if len(strings.TrimSpace(tp.Contract)) > 0 && !common.IsHexAddress(tp.Contract) {
    87  		return govtypes.ErrInvalidProposalContent("invalid contract")
    88  	}
    89  
    90  	return nil
    91  }
    92  
    93  func (tp TokenMappingProposal) String() string {
    94  	var b strings.Builder
    95  
    96  	b.WriteString(fmt.Sprintf(`Token Mapping Proposal:
    97    Title:       %s
    98    Description: %s
    99    Denom:       %s
   100    Contract:    %s
   101  `, tp.Title, tp.Description, tp.Denom, tp.Contract))
   102  
   103  	return b.String()
   104  }
   105  
   106  type RedirectType int
   107  
   108  const (
   109  	RedirectImplementation = iota
   110  	RedirectOwner
   111  )
   112  
   113  var RedirectMap = map[RedirectType]string{
   114  	RedirectImplementation: "ImplementationAddr",
   115  	RedirectOwner:          "OwnerAddr",
   116  }
   117  
   118  type ProxyContractRedirectProposal struct {
   119  	Title       string       `json:"title" yaml:"title"`
   120  	Description string       `json:"description" yaml:"description"`
   121  	Denom       string       `json:"denom" yaml:"denom"`
   122  	Tp          RedirectType `json:"type" yaml:"type"`
   123  	Addr        string       `json:"addr" yaml:"addr"`
   124  }
   125  
   126  func NewProxyContractRedirectProposal(title, description, denom string, tp RedirectType, addr *common.Address) ProxyContractRedirectProposal {
   127  	address := ""
   128  	if addr != nil {
   129  		address = addr.Hex()
   130  	}
   131  	return ProxyContractRedirectProposal{title, description, denom, tp, address}
   132  }
   133  
   134  func (tp ProxyContractRedirectProposal) GetTitle() string {
   135  	return tp.Title
   136  }
   137  
   138  func (tp ProxyContractRedirectProposal) GetDescription() string {
   139  	return tp.Description
   140  }
   141  
   142  func (tp ProxyContractRedirectProposal) ProposalRoute() string {
   143  	return RouterKey
   144  }
   145  
   146  func (tp ProxyContractRedirectProposal) ProposalType() string {
   147  	return proposalTypeProxyContractRedirect
   148  }
   149  
   150  func (tp ProxyContractRedirectProposal) ValidateBasic() sdk.Error {
   151  	if len(strings.TrimSpace(tp.Title)) == 0 {
   152  		return govtypes.ErrInvalidProposalContent("title is required")
   153  	}
   154  	if len(tp.Title) > govtypes.MaxTitleLength {
   155  		return govtypes.ErrInvalidProposalContent("title length is longer than the max")
   156  	}
   157  
   158  	if len(tp.Description) == 0 {
   159  		return govtypes.ErrInvalidProposalContent("description is required")
   160  	}
   161  
   162  	if len(tp.Description) > govtypes.MaxDescriptionLength {
   163  		return govtypes.ErrInvalidProposalContent("description length is longer than the max")
   164  	}
   165  
   166  	if tp.ProposalType() != proposalTypeProxyContractRedirect {
   167  		return govtypes.ErrInvalidProposalType(tp.ProposalType())
   168  	}
   169  
   170  	if len(strings.TrimSpace(tp.Denom)) == 0 {
   171  		return govtypes.ErrInvalidProposalContent("denom is required")
   172  	}
   173  
   174  	if err := sdk.ValidateDenom(tp.Denom); err != nil {
   175  		return govtypes.ErrInvalidProposalContent("invalid denom")
   176  	}
   177  	switch tp.Tp {
   178  	case RedirectImplementation, RedirectOwner:
   179  	default:
   180  		return govtypes.ErrInvalidProposer()
   181  	}
   182  	if len(strings.TrimSpace(tp.Addr)) > 0 && !common.IsHexAddress(tp.Addr) {
   183  		return govtypes.ErrInvalidProposalContent("invalid contract")
   184  	}
   185  	return nil
   186  }
   187  
   188  func (tp ProxyContractRedirectProposal) String() string {
   189  	var b strings.Builder
   190  
   191  	b.WriteString(fmt.Sprintf(`Proxy Contract Redirect Proposal:
   192    		Title:       %s
   193    		Description: %s
   194  		Denom:       %s
   195  		Tp:          %s
   196    		Addr:        %s
   197  	`, tp.Title, tp.Description, tp.Denom, RedirectMap[tp.Tp], tp.Addr))
   198  
   199  	return b.String()
   200  }
   201  
   202  type ContractTemplateProposal struct {
   203  	Title        string `json:"title" yaml:"title"`
   204  	Description  string `json:"description" yaml:"description"`
   205  	ContractType string `json:"contract_type"`
   206  	Contract     string `json:"contract"`
   207  }
   208  
   209  func NewContractTemplateProposal(title string, description string, contractType string, contract string) ContractTemplateProposal {
   210  	return ContractTemplateProposal{Title: title, Description: description, ContractType: contractType, Contract: contract}
   211  }
   212  
   213  func (b ContractTemplateProposal) GetTitle() string { return b.Title }
   214  
   215  func (b ContractTemplateProposal) GetDescription() string { return b.Description }
   216  
   217  func (b ContractTemplateProposal) ProposalRoute() string { return RouterKey }
   218  
   219  func (b ContractTemplateProposal) ProposalType() string { return proposalTypeContractTemplate }
   220  
   221  func (b ContractTemplateProposal) ValidateBasic() sdk.Error {
   222  	if len(strings.TrimSpace(b.Title)) == 0 {
   223  		return govtypes.ErrInvalidProposalContent("title is required")
   224  	}
   225  	if len(b.Title) > govtypes.MaxTitleLength {
   226  		return govtypes.ErrInvalidProposalContent("title length is longer than the max")
   227  	}
   228  
   229  	if len(b.Description) == 0 {
   230  		return govtypes.ErrInvalidProposalContent("description is required")
   231  	}
   232  
   233  	if len(b.Description) > govtypes.MaxDescriptionLength {
   234  		return govtypes.ErrInvalidProposalContent("description length is longer than the max")
   235  	}
   236  	if len(b.ContractType) == 0 || b.ContractType != ProposalTypeContextTemplateProxy && b.ContractType != ProposalTypeContextTemplateImpl {
   237  		return govtypes.ErrInvalidProposalContent("invalid type , should be proxy or implement")
   238  	}
   239  
   240  	if b.ProposalType() != proposalTypeContractTemplate {
   241  		return govtypes.ErrInvalidProposalType(b.ProposalType())
   242  	}
   243  	con, err := UnmarshalCompileContract([]byte(b.Contract))
   244  	if nil != err {
   245  		return err
   246  	}
   247  	if err := con.ValidBasic(); nil != err {
   248  		return err
   249  	}
   250  	return nil
   251  }
   252  
   253  func (b ContractTemplateProposal) String() string {
   254  	return ""
   255  }