github.com/gagliardetto/solana-go@v1.11.0/programs/token/Transfer.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 // Transfers tokens from one account to another either directly or via a 28 // delegate. If this account is associated with the native mint then equal 29 // amounts of SOL and Tokens will be transferred to the destination 30 // account. 31 type Transfer struct { 32 // The amount of tokens to transfer. 33 Amount *uint64 34 35 // [0] = [WRITE] source 36 // ··········· The source account. 37 // 38 // [1] = [WRITE] destination 39 // ··········· The destination account. 40 // 41 // [2] = [] owner 42 // ··········· The source account owner/delegate. 43 // 44 // [3...] = [SIGNER] signers 45 // ··········· M signer accounts. 46 Accounts ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"` 47 Signers ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"` 48 } 49 50 func (obj *Transfer) SetAccounts(accounts []*ag_solanago.AccountMeta) error { 51 obj.Accounts, obj.Signers = ag_solanago.AccountMetaSlice(accounts).SplitFrom(3) 52 return nil 53 } 54 55 func (slice Transfer) GetAccounts() (accounts []*ag_solanago.AccountMeta) { 56 accounts = append(accounts, slice.Accounts...) 57 accounts = append(accounts, slice.Signers...) 58 return 59 } 60 61 // NewTransferInstructionBuilder creates a new `Transfer` instruction builder. 62 func NewTransferInstructionBuilder() *Transfer { 63 nd := &Transfer{ 64 Accounts: make(ag_solanago.AccountMetaSlice, 3), 65 Signers: make(ag_solanago.AccountMetaSlice, 0), 66 } 67 return nd 68 } 69 70 // SetAmount sets the "amount" parameter. 71 // The amount of tokens to transfer. 72 func (inst *Transfer) SetAmount(amount uint64) *Transfer { 73 inst.Amount = &amount 74 return inst 75 } 76 77 // SetSourceAccount sets the "source" account. 78 // The source account. 79 func (inst *Transfer) SetSourceAccount(source ag_solanago.PublicKey) *Transfer { 80 inst.Accounts[0] = ag_solanago.Meta(source).WRITE() 81 return inst 82 } 83 84 // GetSourceAccount gets the "source" account. 85 // The source account. 86 func (inst *Transfer) GetSourceAccount() *ag_solanago.AccountMeta { 87 return inst.Accounts[0] 88 } 89 90 // SetDestinationAccount sets the "destination" account. 91 // The destination account. 92 func (inst *Transfer) SetDestinationAccount(destination ag_solanago.PublicKey) *Transfer { 93 inst.Accounts[1] = ag_solanago.Meta(destination).WRITE() 94 return inst 95 } 96 97 // GetDestinationAccount gets the "destination" account. 98 // The destination account. 99 func (inst *Transfer) GetDestinationAccount() *ag_solanago.AccountMeta { 100 return inst.Accounts[1] 101 } 102 103 // SetOwnerAccount sets the "owner" account. 104 // The source account owner/delegate. 105 func (inst *Transfer) SetOwnerAccount(owner ag_solanago.PublicKey, multisigSigners ...ag_solanago.PublicKey) *Transfer { 106 inst.Accounts[2] = ag_solanago.Meta(owner) 107 if len(multisigSigners) == 0 { 108 inst.Accounts[2].SIGNER() 109 } 110 for _, signer := range multisigSigners { 111 inst.Signers = append(inst.Signers, ag_solanago.Meta(signer).SIGNER()) 112 } 113 return inst 114 } 115 116 // GetOwnerAccount gets the "owner" account. 117 // The source account owner/delegate. 118 func (inst *Transfer) GetOwnerAccount() *ag_solanago.AccountMeta { 119 return inst.Accounts[2] 120 } 121 122 func (inst Transfer) Build() *Instruction { 123 return &Instruction{BaseVariant: ag_binary.BaseVariant{ 124 Impl: inst, 125 TypeID: ag_binary.TypeIDFromUint8(Instruction_Transfer), 126 }} 127 } 128 129 // ValidateAndBuild validates the instruction parameters and accounts; 130 // if there is a validation error, it returns the error. 131 // Otherwise, it builds and returns the instruction. 132 func (inst Transfer) ValidateAndBuild() (*Instruction, error) { 133 if err := inst.Validate(); err != nil { 134 return nil, err 135 } 136 return inst.Build(), nil 137 } 138 139 func (inst *Transfer) Validate() error { 140 // Check whether all (required) parameters are set: 141 { 142 if inst.Amount == nil { 143 return errors.New("Amount parameter is not set") 144 } 145 } 146 147 // Check whether all (required) accounts are set: 148 { 149 if inst.Accounts[0] == nil { 150 return fmt.Errorf("accounts.Source is not set") 151 } 152 if inst.Accounts[1] == nil { 153 return fmt.Errorf("accounts.Destination is not set") 154 } 155 if inst.Accounts[2] == nil { 156 return fmt.Errorf("accounts.Owner is not set") 157 } 158 if !inst.Accounts[2].IsSigner && len(inst.Signers) == 0 { 159 return fmt.Errorf("accounts.Signers is not set") 160 } 161 if len(inst.Signers) > MAX_SIGNERS { 162 return fmt.Errorf("too many signers; got %v, but max is 11", len(inst.Signers)) 163 } 164 } 165 return nil 166 } 167 168 func (inst *Transfer) EncodeToTree(parent ag_treeout.Branches) { 169 parent.Child(ag_format.Program(ProgramName, ProgramID)). 170 // 171 ParentFunc(func(programBranch ag_treeout.Branches) { 172 programBranch.Child(ag_format.Instruction("Transfer")). 173 // 174 ParentFunc(func(instructionBranch ag_treeout.Branches) { 175 176 // Parameters of the instruction: 177 instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) { 178 paramsBranch.Child(ag_format.Param("Amount", *inst.Amount)) 179 }) 180 181 // Accounts of the instruction: 182 instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch ag_treeout.Branches) { 183 accountsBranch.Child(ag_format.Meta(" source", inst.Accounts[0])) 184 accountsBranch.Child(ag_format.Meta("destination", inst.Accounts[1])) 185 accountsBranch.Child(ag_format.Meta(" owner", inst.Accounts[2])) 186 187 signersBranch := accountsBranch.Child(fmt.Sprintf("signers[len=%v]", len(inst.Signers))) 188 for i, v := range inst.Signers { 189 if len(inst.Signers) > 9 && i < 10 { 190 signersBranch.Child(ag_format.Meta(fmt.Sprintf(" [%v]", i), v)) 191 } else { 192 signersBranch.Child(ag_format.Meta(fmt.Sprintf("[%v]", i), v)) 193 } 194 } 195 }) 196 }) 197 }) 198 } 199 200 func (obj Transfer) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { 201 // Serialize `Amount` param: 202 err = encoder.Encode(obj.Amount) 203 if err != nil { 204 return err 205 } 206 return nil 207 } 208 func (obj *Transfer) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { 209 // Deserialize `Amount`: 210 err = decoder.Decode(&obj.Amount) 211 if err != nil { 212 return err 213 } 214 return nil 215 } 216 217 // NewTransferInstruction declares a new Transfer instruction with the provided parameters and accounts. 218 func NewTransferInstruction( 219 // Parameters: 220 amount uint64, 221 // Accounts: 222 source ag_solanago.PublicKey, 223 destination ag_solanago.PublicKey, 224 owner ag_solanago.PublicKey, 225 multisigSigners []ag_solanago.PublicKey) *Transfer { 226 return NewTransferInstructionBuilder(). 227 SetAmount(amount). 228 SetSourceAccount(source). 229 SetDestinationAccount(destination). 230 SetOwnerAccount(owner, multisigSigners...) 231 }