diff --git a/client/rpc/types.go b/client/rpc/types.go index 9f7279e6..9488e396 100644 --- a/client/rpc/types.go +++ b/client/rpc/types.go @@ -45,7 +45,7 @@ type TransactionMeta struct { PostBalances []int64 `json:"postBalances"` PreTokenBalances []TransactionMetaTokenBalance `json:"preTokenBalances"` PostTokenBalances []TransactionMetaTokenBalance `json:"postTokenBalances"` - LogMessages []string `json:"logMesssages"` + LogMessages []string `json:"logMessages"` InnerInstructions []struct { Index uint64 `json:"index"` Instructions []Instruction `json:"instructions"` diff --git a/common/public_key.go b/common/public_key.go index 7907d938..ea1ad7d1 100644 --- a/common/public_key.go +++ b/common/public_key.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/json" "errors" + "fmt" "filippo.io/edwards25519" "github.com/mr-tron/base58" @@ -17,6 +18,21 @@ const ( type PublicKey [PublicKeyLength]byte +func (pk *PublicKey) UnmarshalJSON(b []byte) error { + buf, err := base58.Decode(string(b[1 : len(b)-1])) + if err != nil { + return fmt.Errorf("invalid public key: %w", err) + } + + if len(buf) != PublicKeyLength { + return errors.New("invalid public key length") + } + + copy(pk[:], buf) + + return nil +} + func (p PublicKey) String() string { return p.ToBase58() } diff --git a/program/tokenprog/state.go b/program/tokenprog/state.go index d6bb44ae..43aecae0 100644 --- a/program/tokenprog/state.go +++ b/program/tokenprog/state.go @@ -13,13 +13,52 @@ const MultisigAccountSize uint64 = 355 const MintAccountSize = 82 type MintAccount struct { - MintAuthorityOption uint32 - MintAuthority common.PublicKey - Supply uint64 - Decimals uint8 - IsInitialized bool - FreezeAuthorityOption uint32 - FreezeAuthority common.PublicKey + // MintAuthorityOption uint32 + MintAuthority *common.PublicKey + Supply uint64 + Decimals uint8 + IsInitialized bool + // FreezeAuthorityOption uint32 + FreezeAuthority *common.PublicKey +} + +const ( + mintMintAuthorityOptionOffset = 0 + mintMintAuthorityOffset = mintMintAuthorityOptionOffset + 4 + mintSupplyOffset = mintMintAuthorityOffset + 32 + mintDecimalsOffset = mintSupplyOffset + 8 + mintIsInitializedOffset = mintDecimalsOffset + 1 + mintFreezeAuthorityOptionOffset = mintIsInitializedOffset + 1 + mintFreezeAuthorityOffset = mintFreezeAuthorityOptionOffset + 4 +) + +func isSome(option []byte) bool { + return bytes.Equal(option, Some) +} + +func MintAccountFromData(data []byte) (*MintAccount, error) { + if len(data) != MintAccountSize { + return nil, fmt.Errorf("mint account data length mismatch") + } + + var mint MintAccount + + mintAuthorityOption := data[0:4] + if isSome(mintAuthorityOption) { + key := common.PublicKeyFromBytes(data[mintMintAuthorityOffset : mintSupplyOffset+32]) + mint.MintAuthority = &key + } + + mint.Supply = binary.LittleEndian.Uint64(data[mintSupplyOffset : mintSupplyOffset+8]) + mint.Decimals = uint8(data[mintDecimalsOffset]) + mint.IsInitialized = data[mintIsInitializedOffset] == 1 + + if isSome(data[mintFreezeAuthorityOptionOffset:mintFreezeAuthorityOptionOffset+4]) { + key := common.PublicKeyFromBytes(data[mintFreezeAuthorityOffset : mintFreezeAuthorityOffset+32]) + mint.FreezeAuthority = &key + } + + return &mint, nil } const TokenAccountSize = 165 diff --git a/types/account.go b/types/account.go index 343c1064..51dd0d60 100644 --- a/types/account.go +++ b/types/account.go @@ -2,6 +2,9 @@ package types import ( "crypto/ed25519" + "encoding/hex" + "errors" + "fmt" "github.com/portto/solana-go-sdk/common" ) @@ -12,7 +15,10 @@ type Account struct { } func NewAccount() Account { - _, X, _ := ed25519.GenerateKey(nil) + _, X, err := ed25519.GenerateKey(nil) + if err != nil { + panic(fmt.Sprintf("ed25519 genkey error: %s", err)) + } return AccountFromPrivateKeyBytes(X) } @@ -23,3 +29,19 @@ func AccountFromPrivateKeyBytes(privateKey []byte) Account { PrivateKey: sk, } } + +func (a *Account) UnmarshalText(b []byte) error { + // hex.Decode(dst []byte, src []byte) + key, err := hex.DecodeString(string(b)) + if err != nil { + return fmt.Errorf("decode private key: %w", err) + } + + if len(key) != ed25519.PrivateKeySize { + return errors.New("invalid private key size") + } + + *a = AccountFromPrivateKeyBytes(key) + + return nil +}