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 }