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  }