Skip to content

Commit db2fdaa

Browse files
feat: add token-2022 extensions
1 parent 4370b70 commit db2fdaa

24 files changed

Lines changed: 5085 additions & 0 deletions
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package token2022
2+
3+
import (
4+
"errors"
5+
6+
ag_binary "github.com/gagliardetto/binary"
7+
ag_solanago "github.com/gagliardetto/solana-go"
8+
ag_format "github.com/gagliardetto/solana-go/text/format"
9+
ag_treeout "github.com/gagliardetto/treeout"
10+
)
11+
12+
// ConfidentialMintBurn sub-instruction IDs.
13+
const (
14+
ConfidentialMintBurn_InitializeMint uint8 = iota
15+
ConfidentialMintBurn_UpdateDecryptableSupply
16+
ConfidentialMintBurn_RotateSupplyElGamalPubkey
17+
ConfidentialMintBurn_Mint
18+
ConfidentialMintBurn_Burn
19+
)
20+
21+
// ConfidentialMintBurnExtension is the instruction wrapper for the
22+
// ConfidentialMintBurn extension (ID 42).
23+
// This is a complex extension involving encrypted supply and ZK proofs.
24+
type ConfidentialMintBurnExtension struct {
25+
SubInstruction uint8
26+
RawData []byte
27+
28+
Accounts ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
29+
Signers ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
30+
}
31+
32+
func (obj *ConfidentialMintBurnExtension) SetAccounts(accounts []*ag_solanago.AccountMeta) error {
33+
obj.Accounts = ag_solanago.AccountMetaSlice(accounts)
34+
return nil
35+
}
36+
37+
func (slice ConfidentialMintBurnExtension) GetAccounts() (accounts []*ag_solanago.AccountMeta) {
38+
accounts = append(accounts, slice.Accounts...)
39+
accounts = append(accounts, slice.Signers...)
40+
return
41+
}
42+
43+
func (inst ConfidentialMintBurnExtension) Build() *Instruction {
44+
return &Instruction{BaseVariant: ag_binary.BaseVariant{
45+
Impl: inst,
46+
TypeID: ag_binary.TypeIDFromUint8(Instruction_ConfidentialMintBurnExtension),
47+
}}
48+
}
49+
50+
func (inst ConfidentialMintBurnExtension) ValidateAndBuild() (*Instruction, error) {
51+
if err := inst.Validate(); err != nil {
52+
return nil, err
53+
}
54+
return inst.Build(), nil
55+
}
56+
57+
func (inst *ConfidentialMintBurnExtension) Validate() error {
58+
if len(inst.Accounts) == 0 {
59+
return errors.New("accounts is empty")
60+
}
61+
return nil
62+
}
63+
64+
func (inst *ConfidentialMintBurnExtension) EncodeToTree(parent ag_treeout.Branches) {
65+
names := []string{
66+
"InitializeMint", "UpdateDecryptableSupply",
67+
"RotateSupplyElGamalPubkey", "Mint", "Burn",
68+
}
69+
name := "Unknown"
70+
if int(inst.SubInstruction) < len(names) {
71+
name = names[inst.SubInstruction]
72+
}
73+
parent.Child(ag_format.Program(ProgramName, ProgramID)).
74+
ParentFunc(func(programBranch ag_treeout.Branches) {
75+
programBranch.Child(ag_format.Instruction("ConfidentialMintBurn." + name)).
76+
ParentFunc(func(instructionBranch ag_treeout.Branches) {
77+
instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) {
78+
paramsBranch.Child(ag_format.Param("RawData (len)", len(inst.RawData)))
79+
})
80+
})
81+
})
82+
}
83+
84+
func (obj ConfidentialMintBurnExtension) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) {
85+
err = encoder.WriteUint8(obj.SubInstruction)
86+
if err != nil {
87+
return err
88+
}
89+
if len(obj.RawData) > 0 {
90+
err = encoder.WriteBytes(obj.RawData, false)
91+
if err != nil {
92+
return err
93+
}
94+
}
95+
return nil
96+
}
97+
98+
func (obj *ConfidentialMintBurnExtension) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) {
99+
obj.SubInstruction, err = decoder.ReadUint8()
100+
if err != nil {
101+
return err
102+
}
103+
remaining := decoder.Remaining()
104+
if remaining > 0 {
105+
obj.RawData, err = decoder.ReadNBytes(remaining)
106+
if err != nil {
107+
return err
108+
}
109+
}
110+
return nil
111+
}
112+
113+
// NewConfidentialMintBurnInstruction creates a raw confidential mint/burn extension instruction.
114+
func NewConfidentialMintBurnInstruction(
115+
subInstruction uint8,
116+
rawData []byte,
117+
accounts ...ag_solanago.AccountMeta,
118+
) *ConfidentialMintBurnExtension {
119+
inst := &ConfidentialMintBurnExtension{
120+
SubInstruction: subInstruction,
121+
RawData: rawData,
122+
Accounts: make(ag_solanago.AccountMetaSlice, len(accounts)),
123+
Signers: make(ag_solanago.AccountMetaSlice, 0),
124+
}
125+
for i := range accounts {
126+
inst.Accounts[i] = &accounts[i]
127+
}
128+
return inst
129+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package token2022
2+
3+
import (
4+
"errors"
5+
6+
ag_binary "github.com/gagliardetto/binary"
7+
ag_solanago "github.com/gagliardetto/solana-go"
8+
ag_format "github.com/gagliardetto/solana-go/text/format"
9+
ag_treeout "github.com/gagliardetto/treeout"
10+
)
11+
12+
// ConfidentialTransfer sub-instruction IDs.
13+
const (
14+
ConfidentialTransfer_InitializeMint uint8 = iota
15+
ConfidentialTransfer_UpdateMint
16+
ConfidentialTransfer_ConfigureAccount
17+
ConfidentialTransfer_ApproveAccount
18+
ConfidentialTransfer_EmptyAccount
19+
ConfidentialTransfer_Deposit
20+
ConfidentialTransfer_Withdraw
21+
ConfidentialTransfer_Transfer
22+
ConfidentialTransfer_ApplyPendingBalance
23+
ConfidentialTransfer_EnableConfidentialCredits
24+
ConfidentialTransfer_DisableConfidentialCredits
25+
ConfidentialTransfer_EnableNonConfidentialCredits
26+
ConfidentialTransfer_DisableNonConfidentialCredits
27+
ConfidentialTransfer_TransferWithSplitProofs
28+
ConfidentialTransfer_TransferWithSplitProofsInParallel
29+
)
30+
31+
// ConfidentialTransferExtension is the instruction wrapper for the ConfidentialTransfer extension (ID 27).
32+
// This is a complex extension with many sub-instructions involving zero-knowledge proofs.
33+
// The raw sub-instruction data is preserved for encoding/decoding.
34+
type ConfidentialTransferExtension struct {
35+
SubInstruction uint8
36+
// Raw data for the sub-instruction (after the sub-instruction byte).
37+
RawData []byte
38+
39+
Accounts ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
40+
Signers ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"`
41+
}
42+
43+
func (obj *ConfidentialTransferExtension) SetAccounts(accounts []*ag_solanago.AccountMeta) error {
44+
obj.Accounts = ag_solanago.AccountMetaSlice(accounts)
45+
return nil
46+
}
47+
48+
func (slice ConfidentialTransferExtension) GetAccounts() (accounts []*ag_solanago.AccountMeta) {
49+
accounts = append(accounts, slice.Accounts...)
50+
accounts = append(accounts, slice.Signers...)
51+
return
52+
}
53+
54+
func (inst ConfidentialTransferExtension) Build() *Instruction {
55+
return &Instruction{BaseVariant: ag_binary.BaseVariant{
56+
Impl: inst,
57+
TypeID: ag_binary.TypeIDFromUint8(Instruction_ConfidentialTransferExtension),
58+
}}
59+
}
60+
61+
func (inst ConfidentialTransferExtension) ValidateAndBuild() (*Instruction, error) {
62+
if err := inst.Validate(); err != nil {
63+
return nil, err
64+
}
65+
return inst.Build(), nil
66+
}
67+
68+
func (inst *ConfidentialTransferExtension) Validate() error {
69+
if len(inst.Accounts) == 0 {
70+
return errors.New("accounts is empty")
71+
}
72+
return nil
73+
}
74+
75+
func (inst *ConfidentialTransferExtension) EncodeToTree(parent ag_treeout.Branches) {
76+
names := []string{
77+
"InitializeMint", "UpdateMint", "ConfigureAccount", "ApproveAccount",
78+
"EmptyAccount", "Deposit", "Withdraw", "Transfer",
79+
"ApplyPendingBalance", "EnableConfidentialCredits", "DisableConfidentialCredits",
80+
"EnableNonConfidentialCredits", "DisableNonConfidentialCredits",
81+
"TransferWithSplitProofs", "TransferWithSplitProofsInParallel",
82+
}
83+
name := "Unknown"
84+
if int(inst.SubInstruction) < len(names) {
85+
name = names[inst.SubInstruction]
86+
}
87+
parent.Child(ag_format.Program(ProgramName, ProgramID)).
88+
ParentFunc(func(programBranch ag_treeout.Branches) {
89+
programBranch.Child(ag_format.Instruction("ConfidentialTransfer." + name)).
90+
ParentFunc(func(instructionBranch ag_treeout.Branches) {
91+
instructionBranch.Child("Params").ParentFunc(func(paramsBranch ag_treeout.Branches) {
92+
paramsBranch.Child(ag_format.Param("RawData (len)", len(inst.RawData)))
93+
})
94+
})
95+
})
96+
}
97+
98+
func (obj ConfidentialTransferExtension) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) {
99+
err = encoder.WriteUint8(obj.SubInstruction)
100+
if err != nil {
101+
return err
102+
}
103+
if len(obj.RawData) > 0 {
104+
err = encoder.WriteBytes(obj.RawData, false)
105+
if err != nil {
106+
return err
107+
}
108+
}
109+
return nil
110+
}
111+
112+
func (obj *ConfidentialTransferExtension) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) {
113+
obj.SubInstruction, err = decoder.ReadUint8()
114+
if err != nil {
115+
return err
116+
}
117+
remaining := decoder.Remaining()
118+
if remaining > 0 {
119+
obj.RawData, err = decoder.ReadNBytes(remaining)
120+
if err != nil {
121+
return err
122+
}
123+
}
124+
return nil
125+
}
126+
127+
// NewConfidentialTransferInstruction creates a raw confidential transfer extension instruction.
128+
// Due to the complexity of ZK proof data, this provides a low-level interface.
129+
func NewConfidentialTransferInstruction(
130+
subInstruction uint8,
131+
rawData []byte,
132+
accounts ...ag_solanago.AccountMeta,
133+
) *ConfidentialTransferExtension {
134+
inst := &ConfidentialTransferExtension{
135+
SubInstruction: subInstruction,
136+
RawData: rawData,
137+
Accounts: make(ag_solanago.AccountMetaSlice, len(accounts)),
138+
Signers: make(ag_solanago.AccountMetaSlice, 0),
139+
}
140+
for i := range accounts {
141+
inst.Accounts[i] = &accounts[i]
142+
}
143+
return inst
144+
}

0 commit comments

Comments
 (0)