Skip to content

Commit

Permalink
Merge pull request #10 from avianlabs/create-associated-token-account…
Browse files Browse the repository at this point in the history
…-idempotent

Add associatedtokenaccount CreateIdempotent option
  • Loading branch information
jamesroutley authored Jul 12, 2024
2 parents f3ef1f3 + 396c912 commit 4ee8efb
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 5 deletions.
30 changes: 26 additions & 4 deletions programs/associated-token-account/Create.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"errors"
"fmt"

ag_format "github.com/gagliardetto/solana-go/text/format"

bin "github.com/gagliardetto/binary"
solana "github.com/gagliardetto/solana-go"
format "github.com/gagliardetto/solana-go/text/format"
Expand Down Expand Up @@ -51,6 +53,7 @@ type Create struct {
// [6] = [] SysVarRent
// ··········· SysVarRentPubkey
solana.AccountMetaSlice `bin:"-" borsh_skip:"true"`
Idempotent bool `bin:"-" borsh_skip:"true"`
}

// NewCreateInstructionBuilder creates a new `Create` instruction builder.
Expand Down Expand Up @@ -79,6 +82,11 @@ func (inst *Create) SetTokenProgramID(tokenProgramID solana.PublicKey) *Create {
return inst
}

func (inst *Create) SetIdempotent(idempotent bool) *Create {
inst.Idempotent = idempotent
return inst
}

func (inst Create) Build() *Instruction {

// Find the associatedTokenAddress;
Expand Down Expand Up @@ -174,10 +182,12 @@ func (inst *Create) EncodeToTree(parent treeout.Branches) {
ParentFunc(func(instructionBranch treeout.Branches) {

// Parameters of the instruction:
instructionBranch.Child("Params[len=0]").ParentFunc(func(paramsBranch treeout.Branches) {})
instructionBranch.Child("Params").ParentFunc(func(paramsBranch treeout.Branches) {
paramsBranch.Child(ag_format.Param("Idempotent", inst.Idempotent))
})

// Accounts of the instruction:
instructionBranch.Child("Accounts[len=7").ParentFunc(func(accountsBranch treeout.Branches) {
instructionBranch.Child("Accounts[len=7]").ParentFunc(func(accountsBranch treeout.Branches) {
accountsBranch.Child(format.Meta(" payer", inst.AccountMetaSlice.Get(0)))
accountsBranch.Child(format.Meta("associatedTokenAddress", inst.AccountMetaSlice.Get(1)))
accountsBranch.Child(format.Meta(" wallet", inst.AccountMetaSlice.Get(2)))
Expand All @@ -191,10 +201,20 @@ func (inst *Create) EncodeToTree(parent treeout.Branches) {
}

func (inst Create) MarshalWithEncoder(encoder *bin.Encoder) error {
return encoder.WriteBytes([]byte{}, false)
if inst.Idempotent {
if err := encoder.Encode(inst.Idempotent); err != nil {
return err
}
}
return nil
}

func (inst *Create) UnmarshalWithDecoder(decoder *bin.Decoder) error {
if decoder.HasRemaining() {
if err := decoder.Decode(&inst.Idempotent); err != nil {
return err
}
}
return nil
}

Expand All @@ -214,10 +234,12 @@ func NewCreateInstruction(
walletAddress solana.PublicKey,
splTokenMintAddress solana.PublicKey,
tokenProgramID solana.PublicKey,
idempotent bool,
) *Create {
return NewCreateInstructionBuilder().
SetPayer(payer).
SetWallet(walletAddress).
SetMint(splTokenMintAddress).
SetTokenProgramID(tokenProgramID)
SetTokenProgramID(tokenProgramID).
SetIdempotent(idempotent)
}
76 changes: 76 additions & 0 deletions programs/associated-token-account/Create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package associatedtokenaccount

import (
"testing"

bin "github.com/gagliardetto/binary"
solana "github.com/gagliardetto/solana-go"
"github.com/test-go/testify/assert"
"github.com/test-go/testify/require"
)

func TestCreateNonIdempotentData(t *testing.T) {
t.Parallel()
wallet, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

c := NewCreateInstruction(
wallet.PublicKey(),
wallet.PublicKey(),
solana.MPK("G8iheDY9bGix5qCXEitCExLcgZzZrEemngk9cbTR3CQs"),
solana.MustPublicKeyFromBase58("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
false,
)

data, err := c.Build().Data()
require.NoError(t, err)

assert.Len(t, data, 0)
}

func TestCreateIdempotentData(t *testing.T) {
t.Parallel()
wallet, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

c := NewCreateInstruction(
wallet.PublicKey(),
wallet.PublicKey(),
solana.MPK("G8iheDY9bGix5qCXEitCExLcgZzZrEemngk9cbTR3CQs"),
solana.MustPublicKeyFromBase58("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
true,
)

data, err := c.Build().Data()
require.NoError(t, err)

assert.Equal(t, []byte{1}, data)
}

func TestEncodeRoundtrip(t *testing.T) {
t.Parallel()
wallet, err := solana.NewRandomPrivateKey()
require.NoError(t, err)

c := NewCreateInstruction(
wallet.PublicKey(),
wallet.PublicKey(),
solana.MPK("G8iheDY9bGix5qCXEitCExLcgZzZrEemngk9cbTR3CQs"),
solana.MustPublicKeyFromBase58("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
true,
).Build()

blockhash := solana.MustHashFromBase58("AnL7vVGidfdxZBFqkxLvVwXgW9pDSZC5kK6d5kyRaXEa")
tx, err := solana.NewTransaction([]solana.Instruction{c}, blockhash)
require.NoError(t, err)

data, err := tx.MarshalBinary()
require.NoError(t, err)

decoded := &solana.Transaction{}
err = decoded.UnmarshalWithDecoder(bin.NewCompactU16Decoder(data))
require.NoError(t, err)

err = tx.Message.AssertEquivalent(decoded.Message)
require.NoError(t, err)
}
8 changes: 7 additions & 1 deletion programs/associated-token-account/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
package associatedtokenaccount

import (
"bytes"
"fmt"

spew "github.com/davecgh/go-spew/spew"
ag_binary "github.com/gagliardetto/binary"
bin "github.com/gagliardetto/binary"
solana "github.com/gagliardetto/solana-go"
text "github.com/gagliardetto/solana-go/text"
Expand Down Expand Up @@ -67,7 +69,11 @@ func (inst *Instruction) Accounts() (out []*solana.AccountMeta) {
}

func (inst *Instruction) Data() ([]byte, error) {
return []byte{}, nil
buf := new(bytes.Buffer)
if err := ag_binary.NewBinEncoder(buf).Encode(inst); err != nil {
return nil, fmt.Errorf("unable to encode instruction: %w", err)
}
return buf.Bytes(), nil
}

func (a *Instruction) AssertEquivalent(in solana.Instruction) error {
Expand Down

0 comments on commit 4ee8efb

Please sign in to comment.