Skip to content

Commit dcff584

Browse files
feat: vote program complete
1 parent 4370b70 commit dcff584

34 files changed

Lines changed: 4450 additions & 44 deletions

programs/vote/Authorize.go

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,152 @@
1515
package vote
1616

1717
import (
18+
"encoding/binary"
19+
"errors"
20+
"fmt"
21+
22+
bin "github.com/gagliardetto/binary"
1823
"github.com/gagliardetto/solana-go"
24+
"github.com/gagliardetto/solana-go/text/format"
25+
"github.com/gagliardetto/treeout"
1926
)
2027

28+
// Authorize is the Authorize instruction.
29+
// Data: (Pubkey, VoteAuthorize)
2130
type Authorize struct {
22-
// TODO
31+
NewAuthority *solana.PublicKey
32+
VoteAuthorize *VoteAuthorizeKind
2333

2434
// [0] = [WRITE] VoteAccount
25-
// ··········· Unitialized vote account
2635
//
2736
// [1] = [] SysVarClock
28-
// ··········· Clock sysvar
2937
//
3038
// [2] = [SIGNER] Authority
31-
// ··········· Vote or withdraw authority
39+
// ··········· Current vote or withdraw authority.
3240
solana.AccountMetaSlice `bin:"-" borsh_skip:"true"`
3341
}
42+
43+
func NewAuthorizeInstructionBuilder() *Authorize {
44+
return &Authorize{
45+
AccountMetaSlice: make(solana.AccountMetaSlice, 3),
46+
}
47+
}
48+
49+
func NewAuthorizeInstruction(
50+
newAuthority solana.PublicKey,
51+
kind VoteAuthorizeKind,
52+
voteAccount solana.PublicKey,
53+
currentAuthority solana.PublicKey,
54+
) *Authorize {
55+
return NewAuthorizeInstructionBuilder().
56+
SetNewAuthority(newAuthority).
57+
SetVoteAuthorize(kind).
58+
SetVoteAccount(voteAccount).
59+
SetClockSysvar(solana.SysVarClockPubkey).
60+
SetAuthority(currentAuthority)
61+
}
62+
63+
func (inst *Authorize) SetNewAuthority(pk solana.PublicKey) *Authorize {
64+
inst.NewAuthority = &pk
65+
return inst
66+
}
67+
68+
func (inst *Authorize) SetVoteAuthorize(kind VoteAuthorizeKind) *Authorize {
69+
inst.VoteAuthorize = &kind
70+
return inst
71+
}
72+
73+
func (inst *Authorize) SetVoteAccount(pk solana.PublicKey) *Authorize {
74+
inst.AccountMetaSlice[0] = solana.Meta(pk).WRITE()
75+
return inst
76+
}
77+
78+
func (inst *Authorize) SetClockSysvar(pk solana.PublicKey) *Authorize {
79+
inst.AccountMetaSlice[1] = solana.Meta(pk)
80+
return inst
81+
}
82+
83+
func (inst *Authorize) SetAuthority(pk solana.PublicKey) *Authorize {
84+
inst.AccountMetaSlice[2] = solana.Meta(pk).SIGNER()
85+
return inst
86+
}
87+
88+
func (inst *Authorize) GetVoteAccount() *solana.AccountMeta { return inst.AccountMetaSlice[0] }
89+
func (inst *Authorize) GetClockSysvar() *solana.AccountMeta { return inst.AccountMetaSlice[1] }
90+
func (inst *Authorize) GetAuthority() *solana.AccountMeta { return inst.AccountMetaSlice[2] }
91+
92+
func (inst Authorize) Build() *Instruction {
93+
return &Instruction{BaseVariant: bin.BaseVariant{
94+
Impl: inst,
95+
TypeID: bin.TypeIDFromUint32(Instruction_Authorize, bin.LE),
96+
}}
97+
}
98+
99+
func (inst Authorize) ValidateAndBuild() (*Instruction, error) {
100+
if err := inst.Validate(); err != nil {
101+
return nil, err
102+
}
103+
return inst.Build(), nil
104+
}
105+
106+
func (inst *Authorize) Validate() error {
107+
if inst.NewAuthority == nil {
108+
return errors.New("NewAuthority parameter is not set")
109+
}
110+
if inst.VoteAuthorize == nil {
111+
return errors.New("VoteAuthorize parameter is not set")
112+
}
113+
for i, acc := range inst.AccountMetaSlice {
114+
if acc == nil {
115+
return fmt.Errorf("accounts[%d] is not set", i)
116+
}
117+
}
118+
return nil
119+
}
120+
121+
func (inst *Authorize) UnmarshalWithDecoder(dec *bin.Decoder) error {
122+
b, err := dec.ReadNBytes(32)
123+
if err != nil {
124+
return err
125+
}
126+
pk := solana.PublicKeyFromBytes(b)
127+
inst.NewAuthority = &pk
128+
raw, err := dec.ReadUint32(binary.LittleEndian)
129+
if err != nil {
130+
return err
131+
}
132+
kind := VoteAuthorizeKind(raw)
133+
inst.VoteAuthorize = &kind
134+
return nil
135+
}
136+
137+
func (inst Authorize) MarshalWithEncoder(enc *bin.Encoder) error {
138+
if inst.NewAuthority == nil {
139+
return errors.New("Authorize.NewAuthority is nil")
140+
}
141+
if inst.VoteAuthorize == nil {
142+
return errors.New("Authorize.VoteAuthorize is nil")
143+
}
144+
if err := enc.WriteBytes(inst.NewAuthority[:], false); err != nil {
145+
return err
146+
}
147+
return enc.WriteUint32(uint32(*inst.VoteAuthorize), binary.LittleEndian)
148+
}
149+
150+
func (inst *Authorize) EncodeToTree(parent treeout.Branches) {
151+
parent.Child(format.Program(ProgramName, ProgramID)).
152+
ParentFunc(func(programBranch treeout.Branches) {
153+
programBranch.Child(format.Instruction("Authorize")).
154+
ParentFunc(func(instructionBranch treeout.Branches) {
155+
instructionBranch.Child("Params").ParentFunc(func(paramsBranch treeout.Branches) {
156+
paramsBranch.Child(format.Param(" NewAuthority", inst.NewAuthority))
157+
paramsBranch.Child(format.Param("VoteAuthorize", inst.VoteAuthorize))
158+
})
159+
instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch treeout.Branches) {
160+
accountsBranch.Child(format.Meta("VoteAccount", inst.AccountMetaSlice[0]))
161+
accountsBranch.Child(format.Meta("ClockSysvar", inst.AccountMetaSlice[1]))
162+
accountsBranch.Child(format.Meta(" Authority", inst.AccountMetaSlice[2]))
163+
})
164+
})
165+
})
166+
}

programs/vote/AuthorizeChecked.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package vote
2+
3+
import (
4+
"encoding/binary"
5+
"errors"
6+
"fmt"
7+
8+
bin "github.com/gagliardetto/binary"
9+
"github.com/gagliardetto/solana-go"
10+
"github.com/gagliardetto/solana-go/text/format"
11+
"github.com/gagliardetto/treeout"
12+
)
13+
14+
// AuthorizeChecked is the checked variant of Authorize.
15+
// Data: VoteAuthorize (u32 LE, plus BLS fields if kind=2).
16+
type AuthorizeChecked struct {
17+
VoteAuthorize *VoteAuthorizeKind
18+
19+
// [0] = [WRITE] VoteAccount
20+
// [1] = [] SysVarClock
21+
// [2] = [SIGNER] CurrentAuthority
22+
// [3] = [SIGNER] NewAuthority
23+
solana.AccountMetaSlice `bin:"-" borsh_skip:"true"`
24+
}
25+
26+
func NewAuthorizeCheckedInstructionBuilder() *AuthorizeChecked {
27+
return &AuthorizeChecked{
28+
AccountMetaSlice: make(solana.AccountMetaSlice, 4),
29+
}
30+
}
31+
32+
func NewAuthorizeCheckedInstruction(
33+
kind VoteAuthorizeKind,
34+
voteAccount solana.PublicKey,
35+
currentAuthority solana.PublicKey,
36+
newAuthority solana.PublicKey,
37+
) *AuthorizeChecked {
38+
return NewAuthorizeCheckedInstructionBuilder().
39+
SetVoteAuthorize(kind).
40+
SetVoteAccount(voteAccount).
41+
SetClockSysvar(solana.SysVarClockPubkey).
42+
SetCurrentAuthority(currentAuthority).
43+
SetNewAuthority(newAuthority)
44+
}
45+
46+
func (inst *AuthorizeChecked) SetVoteAuthorize(k VoteAuthorizeKind) *AuthorizeChecked {
47+
inst.VoteAuthorize = &k
48+
return inst
49+
}
50+
func (inst *AuthorizeChecked) SetVoteAccount(pk solana.PublicKey) *AuthorizeChecked {
51+
inst.AccountMetaSlice[0] = solana.Meta(pk).WRITE()
52+
return inst
53+
}
54+
func (inst *AuthorizeChecked) SetClockSysvar(pk solana.PublicKey) *AuthorizeChecked {
55+
inst.AccountMetaSlice[1] = solana.Meta(pk)
56+
return inst
57+
}
58+
func (inst *AuthorizeChecked) SetCurrentAuthority(pk solana.PublicKey) *AuthorizeChecked {
59+
inst.AccountMetaSlice[2] = solana.Meta(pk).SIGNER()
60+
return inst
61+
}
62+
func (inst *AuthorizeChecked) SetNewAuthority(pk solana.PublicKey) *AuthorizeChecked {
63+
inst.AccountMetaSlice[3] = solana.Meta(pk).SIGNER()
64+
return inst
65+
}
66+
67+
func (inst AuthorizeChecked) Build() *Instruction {
68+
return &Instruction{BaseVariant: bin.BaseVariant{
69+
Impl: inst,
70+
TypeID: bin.TypeIDFromUint32(Instruction_AuthorizeChecked, bin.LE),
71+
}}
72+
}
73+
74+
func (inst AuthorizeChecked) ValidateAndBuild() (*Instruction, error) {
75+
if err := inst.Validate(); err != nil {
76+
return nil, err
77+
}
78+
return inst.Build(), nil
79+
}
80+
81+
func (inst *AuthorizeChecked) Validate() error {
82+
if inst.VoteAuthorize == nil {
83+
return errors.New("VoteAuthorize parameter is not set")
84+
}
85+
for i, a := range inst.AccountMetaSlice {
86+
if a == nil {
87+
return fmt.Errorf("accounts[%d] is not set", i)
88+
}
89+
}
90+
return nil
91+
}
92+
93+
func (inst *AuthorizeChecked) UnmarshalWithDecoder(dec *bin.Decoder) error {
94+
raw, err := dec.ReadUint32(binary.LittleEndian)
95+
if err != nil {
96+
return err
97+
}
98+
k := VoteAuthorizeKind(raw)
99+
inst.VoteAuthorize = &k
100+
return nil
101+
}
102+
103+
func (inst AuthorizeChecked) MarshalWithEncoder(enc *bin.Encoder) error {
104+
if inst.VoteAuthorize == nil {
105+
return errors.New("AuthorizeChecked.VoteAuthorize is nil")
106+
}
107+
return enc.WriteUint32(uint32(*inst.VoteAuthorize), binary.LittleEndian)
108+
}
109+
110+
func (inst *AuthorizeChecked) EncodeToTree(parent treeout.Branches) {
111+
parent.Child(format.Program(ProgramName, ProgramID)).
112+
ParentFunc(func(programBranch treeout.Branches) {
113+
programBranch.Child(format.Instruction("AuthorizeChecked")).
114+
ParentFunc(func(instructionBranch treeout.Branches) {
115+
instructionBranch.Child("Params").ParentFunc(func(paramsBranch treeout.Branches) {
116+
paramsBranch.Child(format.Param("VoteAuthorize", inst.VoteAuthorize))
117+
})
118+
instructionBranch.Child("Accounts").ParentFunc(func(accountsBranch treeout.Branches) {
119+
accountsBranch.Child(format.Meta(" VoteAccount", inst.AccountMetaSlice[0]))
120+
accountsBranch.Child(format.Meta(" ClockSysvar", inst.AccountMetaSlice[1]))
121+
accountsBranch.Child(format.Meta("CurrentAuthority", inst.AccountMetaSlice[2]))
122+
accountsBranch.Child(format.Meta(" NewAuthority", inst.AccountMetaSlice[3]))
123+
})
124+
})
125+
})
126+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package vote
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestRoundTrip_AuthorizeChecked(t *testing.T) {
10+
inst := NewAuthorizeCheckedInstruction(VoteAuthorizeVoter, pubkeyOf(1), pubkeyOf(2), pubkeyOf(3))
11+
data, err := encodeInst(inst)
12+
require.NoError(t, err)
13+
require.Equal(t, u32LE(Instruction_AuthorizeChecked), data[:4])
14+
15+
expected := concat(u32LE(Instruction_AuthorizeChecked), u32LE(uint32(VoteAuthorizeVoter)))
16+
require.Equal(t, expected, data)
17+
18+
decoded, err := DecodeInstruction(nil, data)
19+
require.NoError(t, err)
20+
ac := decoded.Impl.(*AuthorizeChecked)
21+
require.Equal(t, VoteAuthorizeVoter, *ac.VoteAuthorize)
22+
}

0 commit comments

Comments
 (0)