-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypestate.ts
141 lines (119 loc) · 3.38 KB
/
typestate.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import * as anchor from "@coral-xyz/anchor";
import { TokenStaking } from "../core/types";
// Our Builder Pattern utilizes the Typestate Pattern
// Why Typestate Pattern? Google it ;)
export interface IConfig {
walletAddress: anchor.web3.PublicKey;
cluster: string;
rpc: string;
confirm: anchor.web3.ConfirmOptions;
idl: anchor.Idl;
}
export enum BuilderState {
Empty,
Ready, // for sending
}
// Transaction Builder Generic Interface
export interface IBuilder<T extends anchor.Idl> {
//----- DATA ------
readonly wallet: anchor.Wallet;
readonly idl: anchor.Idl;
readonly cluster: anchor.web3.Cluster;
readonly rpc: string;
readonly confirmOpts: anchor.web3.ConfirmOptions;
readonly program: anchor.Program<T>;
readonly provider: anchor.AnchorProvider;
}
export interface IEmpty {
readonly state: BuilderState.Empty;
}
export interface IReadyBuilder {
readonly state: BuilderState.Ready;
readonly transactionPromise: Promise<anchor.web3.Transaction>;
// clear tx
clear: () => void;
// send tx
send: () => void;
}
export interface IStakingBuilder extends IBuilder<TokenStaking> {}
export class EmptyStakingBuilder implements IEmpty {
state: BuilderState.Empty = BuilderState.Empty;
data: IStakingBuilder;
constructor(data: IStakingBuilder) {
this.data = data;
}
// instruction: init_stake_pool;
initialize(): ReadyStakingBuilder {
const txPromise = this.data.program.methods
.initializeStakePool()
.accounts({})
.signers([])
.transaction();
return new ReadyStakingBuilder(this.data, txPromise);
}
// instruction: add_reward_pool
register(): ReadyStakingBuilder {
const txPromise = this.data.program.methods
.addRewardPool()
.accounts({})
.signers([])
.transaction();
return new ReadyStakingBuilder(this.data, txPromise);
}
// instruction: deposit
stake(): ReadyStakingBuilder {
const txPromise = this.data.program.methods
.deposit()
.accounts({})
.signers([])
.transaction();
return new ReadyStakingBuilder(this.data, txPromise);
}
// instruction: withdraw
unstake(): ReadyStakingBuilder {
const txPromise = this.data.program.methods
.withdraw()
.accounts({})
.signers([])
.transaction();
return new ReadyStakingBuilder(this.data, txPromise);
}
}
export class ReadyStakingBuilder implements IReadyBuilder {
state: BuilderState.Ready = BuilderState.Ready;
transactionPromise: Promise<anchor.web3.Transaction>;
data: IStakingBuilder;
constructor(data: IStakingBuilder, tx: Promise<anchor.web3.Transaction>) {
this.data = data;
this.transactionPromise = tx;
}
clear(): EmptyStakingBuilder {
return new EmptyStakingBuilder(this.data);
}
async send(): Promise<void> {
const tx = await this.transactionPromise;
await this.data.provider.sendAndConfirm(tx);
}
}
export function createBuilder(
wallet: anchor.Wallet,
cluster: anchor.web3.Cluster,
idl: TokenStaking,
rpc: string,
confirmOpts: anchor.web3.ConfirmOptions,
): EmptyStakingBuilder {
const connection = new anchor.web3.Connection(rpc);
const provider = new anchor.AnchorProvider(connection, wallet, confirmOpts);
return {
state: BuilderState.Empty,
data: {
wallet,
idl,
cluster,
rpc,
confirmOpts,
provider,
program: new anchor.Program<TokenStaking>(idl, provider),
},
};
}