diff --git a/go.mod b/go.mod index cceff92..a8fe818 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,18 @@ module gitea.capitan.black/public/gotron go 1.23.1 require ( + github.com/ethereum/go-ethereum v1.14.11 + github.com/mr-tron/base58 v1.2.0 google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f google.golang.org/grpc v1.68.0 google.golang.org/protobuf v1.35.1 ) require ( + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/holiman/uint256 v1.3.1 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/net v0.31.0 // indirect golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.20.0 // indirect diff --git a/go.sum b/go.sum index 4d3f999..e99a00f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,25 @@ +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= +github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= diff --git a/pkg/address/address.go b/pkg/address/address.go new file mode 100644 index 0000000..b925343 --- /dev/null +++ b/pkg/address/address.go @@ -0,0 +1,127 @@ +package address + +import ( + "crypto/ecdsa" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/mr-tron/base58" + "strings" +) + +type Address [21]byte + +func (a *Address) UnmarshalJSON(bytes []byte) error { + s := "" + + if err := json.Unmarshal(bytes, &s); err != nil { + return fmt.Errorf("unmarshal string: %w", err) + } + + addr, err := NewFromBase58(s) + if err != nil { + return fmt.Errorf("parse address: %w", err) + } + + *a = addr + return nil +} + +func (a Address) String() string { + return a.Base58() +} + +func (a Address) Bytes() []byte { + return a[:] +} + +func (a Address) Hex() string { + return hex.EncodeToString(a[:]) +} + +func (a Address) Base58() string { + var tmp []byte + tmp = append(tmp, a[:]...) + + hash := SHA256(SHA256(tmp)) + checksum := hash[:4] + tmp = append(tmp, checksum...) + + return base58.Encode(tmp) +} + +func (a Address) ETH() common.Address { + return common.BytesToAddress(a[1:]) +} + +func NewFromETH(eth common.Address) Address { + return Address(append([]byte{65}, eth.Bytes()...)) +} + +func NewFromBytes(b []byte) (Address, error) { + if len(b) != 21 { + return Address{}, fmt.Errorf("tron address is not 21 bytes but %d", len(b)) + } + return *(*[21]byte)(b), nil +} + +func NewFromHex(s string) (Address, error) { + addrBytes, err := hex.DecodeString(s) + if err != nil { + return Address{}, err + } + return *(*[21]byte)(addrBytes), nil +} + +func NewFromBase58(s string) (Address, error) { + bytes, err := base58.Decode(s) + if err != nil { + return Address{}, err + } + + if len(bytes) != 25 { + return Address{}, fmt.Errorf("tron address is not 25 bytes but %d", len(bytes)) + } + + return *(*[21]byte)(bytes[:21]), nil +} + +func NewFromString(s string) (Address, error) { + if strings.HasPrefix(s, "T") { + return NewFromBase58(s) + } + if strings.HasPrefix(s, "41") { + return NewFromHex(s) + } + return [21]byte{}, fmt.Errorf("%s is not a Tron address", s) +} + +func NewFromKey(k *ecdsa.PrivateKey) Address { + return NewFromETH(crypto.PubkeyToAddress(k.PublicKey)) +} + +func NewFromKeyBytes(k []byte) (Address, error) { + key, err := crypto.ToECDSA(k) + if err != nil { + return Address{}, err + } + return NewFromKey(key), nil +} + +func NewFromKeyHex(k string) (Address, error) { + keyBytes, err := hex.DecodeString(k) + if err != nil { + return Address{}, err + } + return NewFromKeyBytes(keyBytes) +} + +func SHA256(s []byte) []byte { + h := sha256.New() + h.Write(s) + bs := h.Sum(nil) + return bs +}