github.com/gagliardetto/solana-go@v1.11.0/programs/tokenregistry/instruction.go (about) 1 // Copyright 2021 github.com/gagliardetto 2 // This file has been modified by github.com/gagliardetto 3 // 4 // Copyright 2020 dfuse Platform Inc. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package tokenregistry 19 20 import ( 21 "bytes" 22 "encoding/binary" 23 "fmt" 24 25 "github.com/gagliardetto/solana-go/text" 26 27 bin "github.com/gagliardetto/binary" 28 "github.com/gagliardetto/solana-go" 29 ) 30 31 func init() { 32 solana.RegisterInstructionDecoder(ProgramID(), registryDecodeInstruction) 33 } 34 35 func registryDecodeInstruction(accounts []*solana.AccountMeta, data []byte) (interface{}, error) { 36 inst, err := DecodeInstruction(accounts, data) 37 if err != nil { 38 return nil, err 39 } 40 return inst, nil 41 } 42 43 func DecodeInstruction(accounts []*solana.AccountMeta, data []byte) (*Instruction, error) { 44 var inst Instruction 45 if err := bin.NewBinDecoder(data).Decode(&inst); err != nil { 46 return nil, fmt.Errorf("unable to decode instruction for serum program: %w", err) 47 } 48 49 if v, ok := inst.Impl.(solana.AccountsSettable); ok { 50 err := v.SetAccounts(accounts) 51 if err != nil { 52 return nil, fmt.Errorf("unable to set accounts for instruction: %w", err) 53 } 54 } 55 56 return &inst, nil 57 } 58 59 func NewRegisterTokenInstruction(logo Logo, name Name, symbol Symbol, website Website, tokenMetaKey, ownerKey, tokenKey solana.PublicKey) *Instruction { 60 return &Instruction{ 61 BaseVariant: bin.BaseVariant{ 62 TypeID: bin.TypeIDFromUint32(0, bin.LE), 63 Impl: &RegisterToken{ 64 Logo: logo, 65 Name: name, 66 Website: website, 67 Symbol: symbol, 68 Accounts: &RegisterTokenAccounts{ 69 TokenMeta: &solana.AccountMeta{tokenMetaKey, false, true}, 70 Owner: &solana.AccountMeta{ownerKey, true, false}, 71 Token: &solana.AccountMeta{tokenKey, false, false}, 72 }, 73 }, 74 }, 75 } 76 } 77 78 type Instruction struct { 79 bin.BaseVariant 80 } 81 82 var _ bin.EncoderDecoder = &Instruction{} 83 84 func (i *Instruction) Accounts() (out []*solana.AccountMeta) { 85 switch i.TypeID { 86 case bin.TypeIDFromUint32(0, bin.LE): 87 accounts := i.Impl.(*RegisterToken).Accounts 88 out = []*solana.AccountMeta{accounts.TokenMeta, accounts.Owner, accounts.Token} 89 } 90 return 91 } 92 93 func (i *Instruction) ProgramID() solana.PublicKey { 94 return ProgramID() 95 } 96 97 func (i *Instruction) Data() ([]byte, error) { 98 buf := new(bytes.Buffer) 99 if err := bin.NewBinEncoder(buf).Encode(i); err != nil { 100 return nil, fmt.Errorf("unable to encode instruction: %w", err) 101 } 102 return buf.Bytes(), nil 103 } 104 105 var InstructionDefVariant = bin.NewVariantDefinition(bin.Uint32TypeIDEncoding, []bin.VariantType{ 106 {"register_token", (*RegisterToken)(nil)}, 107 }) 108 109 func (i *Instruction) TextEncode(encoder *text.Encoder, option *text.Option) error { 110 return encoder.Encode(i.Impl, option) 111 } 112 113 func (i *Instruction) UnmarshalWithDecoder(decoder *bin.Decoder) (err error) { 114 return i.BaseVariant.UnmarshalBinaryVariant(decoder, InstructionDefVariant) 115 } 116 117 func (i Instruction) MarshalWithEncoder(encoder *bin.Encoder) error { 118 err := encoder.WriteUint32(i.TypeID.Uint32(), binary.LittleEndian) 119 if err != nil { 120 return fmt.Errorf("unable to write variant type: %w", err) 121 } 122 return encoder.Encode(i.Impl) 123 } 124 125 type RegisterTokenAccounts struct { 126 TokenMeta *solana.AccountMeta `text:"linear,notype"` 127 Owner *solana.AccountMeta `text:"linear,notype"` 128 Token *solana.AccountMeta `text:"linear,notype"` 129 } 130 131 type RegisterToken struct { 132 Logo Logo 133 Name Name 134 Website Website 135 Symbol Symbol 136 Accounts *RegisterTokenAccounts `bin:"-"` 137 } 138 139 func (i *RegisterToken) SetAccounts(accounts []*solana.AccountMeta) error { 140 if len(accounts) < 9 { 141 return fmt.Errorf("insufficient account") 142 } 143 i.Accounts = &RegisterTokenAccounts{ 144 TokenMeta: accounts[0], 145 Owner: accounts[1], 146 Token: accounts[2], 147 } 148 149 return nil 150 }