github.com/gagliardetto/solana-go@v1.11.0/programs/token/BurnChecked.go (about)

     1  // Copyright 2021 github.com/gagliardetto
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package token
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  
    21  	ag_binary "github.com/gagliardetto/binary"
    22  	ag_solanago "github.com/gagliardetto/solana-go"
    23  	ag_format "github.com/gagliardetto/solana-go/text/format"
    24  	ag_treeout "github.com/gagliardetto/treeout"
    25  )
    26  
    27  // Burns tokens by removing them from an account.  `BurnChecked` does not
    28  // support accounts associated with the native mint, use `CloseAccount`
    29  // instead.
    30  //
    31  // This instruction differs from Burn in that the decimals value is checked
    32  // by the caller. This may be useful when creating transactions offline or
    33  // within a hardware wallet.
    34  type BurnChecked struct {
    35  	// The amount of tokens to burn.
    36  	Amount *uint64
    37  
    38  	// Expected number of base 10 digits to the right of the decimal place.
    39  	Decimals *uint8
    40  
    41  	// [0] = [WRITE] source
    42  	// ··········· The account to burn from.
    43  	//
    44  	// [1] = [WRITE] mint
    45  	// ··········· The token mint.
    46  	//
    47  	// [2] = [] owner
    48  	// ··········· The account's owner/delegate.
    49  	//
    50  	// [3...] = [SIGNER] signers
    51  	// ··········· M signer accounts.
    52  	Accounts ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
    53  	Signers  ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
    54  }
    55  
    56  func (obj *BurnChecked) SetAccounts(accounts []*ag_solanago.AccountMeta) error {
    57  	obj.Accounts, obj.Signers = ag_solanago.AccountMetaSlice(accounts).SplitFrom(3)
    58  	return nil
    59  }
    60  
    61  func (slice BurnChecked) GetAccounts() (accounts []*ag_solanago.AccountMeta) {
    62  	accounts = append(accounts, slice.Accounts...)
    63  	accounts = append(accounts, slice.Signers...)
    64  	return
    65  }
    66  
    67  // NewBurnCheckedInstructionBuilder creates a new `BurnChecked` instruction builder.
    68  func NewBurnCheckedInstructionBuilder() *BurnChecked {
    69  	nd := &BurnChecked{
    70  		Accounts: make(ag_solanago.AccountMetaSlice, 3),
    71  		Signers:  make(ag_solanago.AccountMetaSlice, 0),
    72  	}
    73  	return nd
    74  }
    75  
    76  // SetAmount sets the "amount" parameter.
    77  // The amount of tokens to burn.
    78  func (inst *BurnChecked) SetAmount(amount uint64) *BurnChecked {
    79  	inst.Amount = &amount
    80  	return inst
    81  }
    82  
    83  // SetDecimals sets the "decimals" parameter.
    84  // Expected number of base 10 digits to the right of the decimal place.
    85  func (inst *BurnChecked) SetDecimals(decimals uint8) *BurnChecked {
    86  	inst.Decimals = &decimals
    87  	return inst
    88  }
    89  
    90  // SetSourceAccount sets the "source" account.
    91  // The account to burn from.
    92  func (inst *BurnChecked) SetSourceAccount(source ag_solanago.PublicKey) *BurnChecked {
    93  	inst.Accounts[0] = ag_solanago.Meta(source).WRITE()
    94  	return inst
    95  }
    96  
    97  // GetSourceAccount gets the "source" account.
    98  // The account to burn from.
    99  func (inst *BurnChecked) GetSourceAccount() *ag_solanago.AccountMeta {
   100  	return inst.Accounts[0]
   101  }
   102  
   103  // SetMintAccount sets the "mint" account.
   104  // The token mint.
   105  func (inst *BurnChecked) SetMintAccount(mint ag_solanago.PublicKey) *BurnChecked {
   106  	inst.Accounts[1] = ag_solanago.Meta(mint).WRITE()
   107  	return inst
   108  }
   109  
   110  // GetMintAccount gets the "mint" account.
   111  // The token mint.
   112  func (inst *BurnChecked) GetMintAccount() *ag_solanago.AccountMeta {
   113  	return inst.Accounts[1]
   114  }
   115  
   116  // SetOwnerAccount sets the "owner" account.
   117  // The account's owner/delegate.
   118  func (inst *BurnChecked) SetOwnerAccount(owner ag_solanago.PublicKey, multisigSigners ...ag_solanago.PublicKey) *BurnChecked {
   119  	inst.Accounts[2] = ag_solanago.Meta(owner)
   120  	if len(multisigSigners) == 0 {
   121  		inst.Accounts[2].SIGNER()
   122  	}
   123  	for _, signer := range multisigSigners {
   124  		inst.Signers = append(inst.Signers, ag_solanago.Meta(signer).SIGNER())
   125  	}
   126  	return inst
   127  }
   128  
   129  // GetOwnerAccount gets the "owner" account.
   130  // The account's owner/delegate.
   131  func (inst *BurnChecked) GetOwnerAccount() *ag_solanago.AccountMeta {
   132  	return inst.Accounts[2]
   133  }
   134  
   135  func (inst BurnChecked) Build() *Instruction {
   136  	return &Instruction{BaseVariant: ag_binary.BaseVariant{
   137  		Impl:   inst,
   138  		TypeID: ag_binary.TypeIDFromUint8(Instruction_BurnChecked),
   139  	}}
   140  }
   141  
   142  // ValidateAndBuild validates the instruction parameters and accounts;
   143  // if there is a validation error, it returns the error.
   144  // Otherwise, it builds and returns the instruction.
   145  func (inst BurnChecked) ValidateAndBuild() (*Instruction, error) {
   146  	if err := inst.Validate(); err != nil {
   147  		return nil, err
   148  	}
   149  	return inst.Build(), nil
   150  }
   151  
   152  func (inst *BurnChecked) Validate() error {
   153  	// Check whether all (required) parameters are set:
   154  	{
   155  		if inst.Amount == nil {
   156  			return errors.New("Amount parameter is not set")
   157  		}
   158  		if inst.Decimals == nil {
   159  			return errors.New("Decimals parameter is not set")
   160  		}
   161  	}
   162  
   163  	// Check whether all (required) accounts are set:
   164  	{
   165  		if inst.Accounts[0] == nil {
   166  			return errors.New("accounts.Source is not set")
   167  		}
   168  		if inst.Accounts[1] == nil {
   169  			return errors.New("accounts.Mint is not set")
   170  		}
   171  		if inst.Accounts[2] == nil {
   172  			return errors.New("accounts.Owner is not set")
   173  		}
   174  		if !inst.Accounts[2].IsSigner && len(inst.Signers) == 0 {
   175  			return fmt.Errorf("accounts.Signers is not set")
   176  		}
   177  		if len(inst.Signers) > MAX_SIGNERS {
   178  			return fmt.Errorf("too many signers; got %v, but max is 11", len(inst.Signers))
   179  		}
   180  	}
   181  	return nil
   182  }
   183  
   184  func (inst *BurnChecked) EncodeToTree(parent ag_treeout.Branches) {
   185  	parent.Child(ag_format.Program(ProgramName, ProgramID)).
   186  		//
   187  		ParentFunc(func(programBranch ag_treeout.Branches) {
   188  			programBranch.Child(ag_format.Instruction("BurnChecked")).
   189  				//
   190  				ParentFunc(func(instructionBranch ag_treeout.Branches) {
   191  
   192  					// Parameters of the instruction:
   193  					instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) {
   194  						paramsBranch.Child(ag_format.Param("  Amount", *inst.Amount))
   195  						paramsBranch.Child(ag_format.Param("Decimals", *inst.Decimals))
   196  					})
   197  
   198  					// Accounts of the instruction:
   199  					instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch ag_treeout.Branches) {
   200  						accountsBranch.Child(ag_format.Meta("source", inst.Accounts[0]))
   201  						accountsBranch.Child(ag_format.Meta("  mint", inst.Accounts[1]))
   202  						accountsBranch.Child(ag_format.Meta(" owner", inst.Accounts[2]))
   203  
   204  						signersBranch := accountsBranch.Child(fmt.Sprintf("signers[len=%v]", len(inst.Signers)))
   205  						for i, v := range inst.Signers {
   206  							if len(inst.Signers) > 9 && i < 10 {
   207  								signersBranch.Child(ag_format.Meta(fmt.Sprintf(" [%v]", i), v))
   208  							} else {
   209  								signersBranch.Child(ag_format.Meta(fmt.Sprintf("[%v]", i), v))
   210  							}
   211  						}
   212  					})
   213  				})
   214  		})
   215  }
   216  
   217  func (obj BurnChecked) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) {
   218  	// Serialize `Amount` param:
   219  	err = encoder.Encode(obj.Amount)
   220  	if err != nil {
   221  		return err
   222  	}
   223  	// Serialize `Decimals` param:
   224  	err = encoder.Encode(obj.Decimals)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	return nil
   229  }
   230  func (obj *BurnChecked) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) {
   231  	// Deserialize `Amount`:
   232  	err = decoder.Decode(&obj.Amount)
   233  	if err != nil {
   234  		return err
   235  	}
   236  	// Deserialize `Decimals`:
   237  	err = decoder.Decode(&obj.Decimals)
   238  	if err != nil {
   239  		return err
   240  	}
   241  	return nil
   242  }
   243  
   244  // NewBurnCheckedInstruction declares a new BurnChecked instruction with the provided parameters and accounts.
   245  func NewBurnCheckedInstruction(
   246  	// Parameters:
   247  	amount uint64,
   248  	decimals uint8,
   249  	// Accounts:
   250  	source ag_solanago.PublicKey,
   251  	mint ag_solanago.PublicKey,
   252  	owner ag_solanago.PublicKey,
   253  	multisigSigners []ag_solanago.PublicKey,
   254  ) *BurnChecked {
   255  	return NewBurnCheckedInstructionBuilder().
   256  		SetAmount(amount).
   257  		SetDecimals(decimals).
   258  		SetSourceAccount(source).
   259  		SetMintAccount(mint).
   260  		SetOwnerAccount(owner, multisigSigners...)
   261  }