@zebec-network/zebec-stake-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/artifacts/index.d.ts +3 -0
- package/dist/artifacts/index.js +9 -0
- package/dist/artifacts/zebec_stake_v1.d.ts +1360 -0
- package/dist/artifacts/zebec_stake_v1.js +2 -0
- package/dist/artifacts/zebec_stake_v1.json +934 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.js +29 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/pda.d.ts +7 -0
- package/dist/pda.js +39 -0
- package/dist/providers.d.ts +17 -0
- package/dist/providers.js +24 -0
- package/dist/service.d.ts +123 -0
- package/dist/service.js +305 -0
- package/package.json +46 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
export declare const isSdkEnvDev: boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Zebec Card Program Ids
|
|
5
|
+
*/
|
|
6
|
+
export declare const ZEBEC_STAKE_PROGRAM: {
|
|
7
|
+
/** Mainnet Program Id */
|
|
8
|
+
mainnet: string;
|
|
9
|
+
/** Devnet Program Id */
|
|
10
|
+
devnet: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const ZBCN: PublicKey;
|
|
13
|
+
/** BigNumber Object for 10 */
|
|
14
|
+
export declare const TEN_BIGNUM: BigNumber;
|
|
15
|
+
/** Token Program ID */
|
|
16
|
+
export declare const TOKEN_PROGRAM_ID: PublicKey;
|
|
17
|
+
/** Associated Token Program ID */
|
|
18
|
+
export declare const ASSOCIATED_TOKEN_PROGRAM_ID: PublicKey;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ASSOCIATED_TOKEN_PROGRAM_ID = exports.TOKEN_PROGRAM_ID = exports.TEN_BIGNUM = exports.ZBCN = exports.ZEBEC_STAKE_PROGRAM = exports.isSdkEnvDev = void 0;
|
|
7
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
8
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
9
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
10
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
11
|
+
dotenv_1.default.config();
|
|
12
|
+
const SDK_ENV = process.env.SDK_ENV ?? "production";
|
|
13
|
+
exports.isSdkEnvDev = SDK_ENV === "development";
|
|
14
|
+
/**
|
|
15
|
+
* Zebec Card Program Ids
|
|
16
|
+
*/
|
|
17
|
+
exports.ZEBEC_STAKE_PROGRAM = {
|
|
18
|
+
/** Mainnet Program Id */
|
|
19
|
+
mainnet: "6S5tbu8jPJKFvpBMjaMPQbcwcrw8iHcuGnXH8ZwHgwaE",
|
|
20
|
+
/** Devnet Program Id */
|
|
21
|
+
devnet: "6S5tbu8jPJKFvpBMjaMPQbcwcrw8iHcuGnXH8ZwHgwaE",
|
|
22
|
+
};
|
|
23
|
+
exports.ZBCN = new web3_js_1.PublicKey("ZBCNpuD7YMXzTHB2fhGkGi78MNsHGLRXUhRewNRm9RU");
|
|
24
|
+
/** BigNumber Object for 10 */
|
|
25
|
+
exports.TEN_BIGNUM = (0, bignumber_js_1.BigNumber)(10);
|
|
26
|
+
/** Token Program ID */
|
|
27
|
+
exports.TOKEN_PROGRAM_ID = anchor_1.utils.token.TOKEN_PROGRAM_ID;
|
|
28
|
+
/** Associated Token Program ID */
|
|
29
|
+
exports.ASSOCIATED_TOKEN_PROGRAM_ID = anchor_1.utils.token.ASSOCIATED_PROGRAM_ID;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./constants"), exports);
|
|
18
|
+
__exportStar(require("./artifacts"), exports);
|
|
19
|
+
__exportStar(require("./service"), exports);
|
|
20
|
+
__exportStar(require("./providers"), exports);
|
|
21
|
+
__exportStar(require("./pda"), exports);
|
package/dist/pda.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Address } from "@coral-xyz/anchor";
|
|
2
|
+
import { PublicKey } from "@solana/web3.js";
|
|
3
|
+
export declare function deriveStakeAddress(staker: Address, lockup: Address, nonce: bigint, programId?: Address): PublicKey;
|
|
4
|
+
export declare function deriveLockupAddress(name: string, programId?: Address): PublicKey;
|
|
5
|
+
export declare function deriveUserNonceAddress(user: Address, lockup: Address, programId?: Address): PublicKey;
|
|
6
|
+
export declare function deriveStakeVaultAddress(lockup: Address, programId?: Address): PublicKey;
|
|
7
|
+
export declare function deriveRewardVaultAddress(lockup: Address, programId?: Address): PublicKey;
|
package/dist/pda.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveStakeAddress = deriveStakeAddress;
|
|
4
|
+
exports.deriveLockupAddress = deriveLockupAddress;
|
|
5
|
+
exports.deriveUserNonceAddress = deriveUserNonceAddress;
|
|
6
|
+
exports.deriveStakeVaultAddress = deriveStakeVaultAddress;
|
|
7
|
+
exports.deriveRewardVaultAddress = deriveRewardVaultAddress;
|
|
8
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
9
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
const SEEDS = {
|
|
12
|
+
lockup: "zebec_lockup",
|
|
13
|
+
stakeVault: "stake_vault",
|
|
14
|
+
rewardVault: "reward_vault",
|
|
15
|
+
};
|
|
16
|
+
function deriveStakeAddress(staker, lockup, nonce, programId = constants_1.ZEBEC_STAKE_PROGRAM.mainnet) {
|
|
17
|
+
const [stakeAddress] = web3_js_1.PublicKey.findProgramAddressSync([
|
|
18
|
+
(0, anchor_1.translateAddress)(staker).toBuffer(),
|
|
19
|
+
(0, anchor_1.translateAddress)(lockup).toBuffer(),
|
|
20
|
+
new anchor_1.BN(nonce.toString()).toArrayLike(Buffer, "le", 8),
|
|
21
|
+
], (0, anchor_1.translateAddress)(programId));
|
|
22
|
+
return stakeAddress;
|
|
23
|
+
}
|
|
24
|
+
function deriveLockupAddress(name, programId = constants_1.ZEBEC_STAKE_PROGRAM.mainnet) {
|
|
25
|
+
const [lockupAddress] = web3_js_1.PublicKey.findProgramAddressSync([anchor_1.utils.bytes.utf8.encode(SEEDS.lockup), anchor_1.utils.bytes.utf8.encode(name)], (0, anchor_1.translateAddress)(programId));
|
|
26
|
+
return lockupAddress;
|
|
27
|
+
}
|
|
28
|
+
function deriveUserNonceAddress(user, lockup, programId = constants_1.ZEBEC_STAKE_PROGRAM.mainnet) {
|
|
29
|
+
const [userNonceAddress] = web3_js_1.PublicKey.findProgramAddressSync([(0, anchor_1.translateAddress)(user).toBuffer(), (0, anchor_1.translateAddress)(lockup).toBuffer()], (0, anchor_1.translateAddress)(programId));
|
|
30
|
+
return userNonceAddress;
|
|
31
|
+
}
|
|
32
|
+
function deriveStakeVaultAddress(lockup, programId = constants_1.ZEBEC_STAKE_PROGRAM.mainnet) {
|
|
33
|
+
const [stakeVault] = web3_js_1.PublicKey.findProgramAddressSync([anchor_1.utils.bytes.utf8.encode(SEEDS.stakeVault), (0, anchor_1.translateAddress)(lockup).toBuffer()], (0, anchor_1.translateAddress)(programId));
|
|
34
|
+
return stakeVault;
|
|
35
|
+
}
|
|
36
|
+
function deriveRewardVaultAddress(lockup, programId = constants_1.ZEBEC_STAKE_PROGRAM.mainnet) {
|
|
37
|
+
const [rewardVault] = web3_js_1.PublicKey.findProgramAddressSync([anchor_1.utils.bytes.utf8.encode(SEEDS.rewardVault), (0, anchor_1.translateAddress)(lockup).toBuffer()], (0, anchor_1.translateAddress)(programId));
|
|
38
|
+
return rewardVault;
|
|
39
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Address, AnchorProvider } from "@coral-xyz/anchor";
|
|
2
|
+
import { ConfirmOptions, Connection, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
|
|
3
|
+
export declare class ReadonlyProvider {
|
|
4
|
+
readonly connection: Connection;
|
|
5
|
+
readonly walletAddress?: PublicKey;
|
|
6
|
+
constructor(connection: Connection, walletAddress?: Address);
|
|
7
|
+
}
|
|
8
|
+
export declare function createReadonlyProvider(connection: Connection, walletAddress?: Address): ReadonlyProvider;
|
|
9
|
+
/**
|
|
10
|
+
* Wallet interface used by Anchor Framework
|
|
11
|
+
*/
|
|
12
|
+
export interface AnchorWallet {
|
|
13
|
+
signTransaction: <T extends Transaction | VersionedTransaction>(tx: T) => Promise<T>;
|
|
14
|
+
signAllTransactions: <T extends Transaction | VersionedTransaction>(txs: T[]) => Promise<T[]>;
|
|
15
|
+
publicKey: PublicKey;
|
|
16
|
+
}
|
|
17
|
+
export declare function createAnchorProvider(connection: Connection, wallet: AnchorWallet, options?: ConfirmOptions): AnchorProvider;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReadonlyProvider = void 0;
|
|
4
|
+
exports.createReadonlyProvider = createReadonlyProvider;
|
|
5
|
+
exports.createAnchorProvider = createAnchorProvider;
|
|
6
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
7
|
+
class ReadonlyProvider {
|
|
8
|
+
connection;
|
|
9
|
+
walletAddress;
|
|
10
|
+
constructor(connection, walletAddress) {
|
|
11
|
+
this.connection = connection;
|
|
12
|
+
this.walletAddress = walletAddress ? (0, anchor_1.translateAddress)(walletAddress) : undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ReadonlyProvider = ReadonlyProvider;
|
|
16
|
+
function createReadonlyProvider(connection, walletAddress) {
|
|
17
|
+
return new ReadonlyProvider(connection, walletAddress);
|
|
18
|
+
}
|
|
19
|
+
function createAnchorProvider(connection, wallet, options) {
|
|
20
|
+
return new anchor_1.AnchorProvider(connection, wallet, {
|
|
21
|
+
...anchor_1.AnchorProvider.defaultOptions(),
|
|
22
|
+
...options,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Address, AnchorProvider, BN, Program, Provider } from "@coral-xyz/anchor";
|
|
2
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
3
|
+
import { TransactionPayload } from "@zebec-network/solana-common";
|
|
4
|
+
import { ZebecStakeIdlV1 } from "./artifacts";
|
|
5
|
+
import { ReadonlyProvider } from "./providers";
|
|
6
|
+
type ProgramCreateFunction = (provider: ReadonlyProvider | AnchorProvider) => Program<ZebecStakeIdlV1>;
|
|
7
|
+
/**
|
|
8
|
+
* StakeServiceBuilder is a builder class for creating a StakeService instance.
|
|
9
|
+
* It allows you to set the network, provider, and program to use.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StakeServiceBuilder {
|
|
12
|
+
private _program;
|
|
13
|
+
private _provider;
|
|
14
|
+
private _network;
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @param network The network to use. If not set, a default network: 'mainnet-beta' will be used.
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
setNetwork(network?: "mainnet-beta" | "devnet"): StakeServiceBuilder;
|
|
21
|
+
/**
|
|
22
|
+
* Set the provider to use. If not set, a default provider will be created.
|
|
23
|
+
* @param provider The provider to use. If not set, a default provider: 'ReadonlyProvider' will be created.
|
|
24
|
+
* @returns The StakeServiceBuilder instance.
|
|
25
|
+
*/
|
|
26
|
+
setProvider(provider?: ReadonlyProvider | AnchorProvider): StakeServiceBuilder;
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param provider The provider to compare with.
|
|
30
|
+
*/
|
|
31
|
+
private validateProviderNetwork;
|
|
32
|
+
/**
|
|
33
|
+
* Set the program to use. If not set, a default program will be created.
|
|
34
|
+
* @param program The program to use. If not set, a default program will be created.
|
|
35
|
+
* @returns The StakeServiceBuilder instance.
|
|
36
|
+
*/
|
|
37
|
+
setProgram(createProgram?: ProgramCreateFunction): StakeServiceBuilder;
|
|
38
|
+
build(): StakeService;
|
|
39
|
+
}
|
|
40
|
+
export declare class StakeService {
|
|
41
|
+
readonly provider: Provider;
|
|
42
|
+
readonly program: Program<ZebecStakeIdlV1>;
|
|
43
|
+
readonly network: "mainnet-beta" | "devnet";
|
|
44
|
+
constructor(provider: Provider, program: Program<ZebecStakeIdlV1>, network: "mainnet-beta" | "devnet");
|
|
45
|
+
private _createPayload;
|
|
46
|
+
getInitLockupInstruction(creator: PublicKey, lockup: PublicKey, stakeToken: PublicKey, rewardToken: PublicKey, rewardVault: PublicKey, stakeVault: PublicKey, data: InitLockupInstructionData): Promise<TransactionInstruction>;
|
|
47
|
+
getStakeInstruction(lockup: PublicKey, stakeToken: PublicKey, stakeVault: PublicKey, staker: PublicKey, userNonce: PublicKey, stakePda: PublicKey, stakeVaultTokenAccount: PublicKey, data: StakeInstructionData): Promise<TransactionInstruction>;
|
|
48
|
+
getUnstakeInstruction(feeVault: PublicKey, lockup: PublicKey, stakePda: PublicKey, rewardToken: PublicKey, rewardVault: PublicKey, stakeToken: PublicKey, stakeVault: PublicKey, staker: PublicKey, stakerTokenAccount: PublicKey, nonce: BN): Promise<TransactionInstruction>;
|
|
49
|
+
initLockup(params: {
|
|
50
|
+
stakeToken: Address;
|
|
51
|
+
rewardToken: Address;
|
|
52
|
+
creator?: Address;
|
|
53
|
+
name: string;
|
|
54
|
+
fee: Numeric;
|
|
55
|
+
feeVault: Address;
|
|
56
|
+
rewardSchemes: RewardScheme[];
|
|
57
|
+
}): Promise<TransactionPayload>;
|
|
58
|
+
stake(params: {
|
|
59
|
+
lockupName: string;
|
|
60
|
+
staker?: Address;
|
|
61
|
+
amount: Numeric;
|
|
62
|
+
lockPeriod: number;
|
|
63
|
+
nonce: bigint;
|
|
64
|
+
}): Promise<TransactionPayload>;
|
|
65
|
+
unstake(params: {
|
|
66
|
+
lockupName: string;
|
|
67
|
+
nonce: bigint;
|
|
68
|
+
staker?: Address;
|
|
69
|
+
}): Promise<TransactionPayload>;
|
|
70
|
+
getLockupInfo(lockupAddress: Address): Promise<LockupInfo | null>;
|
|
71
|
+
getStakeInfo(stakeAddress: Address, lockupAddress: Address): Promise<StakeInfo | null>;
|
|
72
|
+
getUserNonceInfo(userNonceAddress: Address): Promise<UserNonceInfo | null>;
|
|
73
|
+
}
|
|
74
|
+
export type InitLockupInstructionData = {
|
|
75
|
+
rewardSchemes: ParsedRewardScheme[];
|
|
76
|
+
fee: BN;
|
|
77
|
+
feeVault: PublicKey;
|
|
78
|
+
name: string;
|
|
79
|
+
};
|
|
80
|
+
export type ParsedRewardScheme = {
|
|
81
|
+
duration: BN;
|
|
82
|
+
reward: BN;
|
|
83
|
+
};
|
|
84
|
+
type Numeric = string | number;
|
|
85
|
+
export type RewardScheme = {
|
|
86
|
+
duration: number;
|
|
87
|
+
rewardRate: Numeric;
|
|
88
|
+
};
|
|
89
|
+
export type StakeInstructionData = {
|
|
90
|
+
amount: BN;
|
|
91
|
+
lockPeriod: BN;
|
|
92
|
+
nonce: BN;
|
|
93
|
+
};
|
|
94
|
+
export type LockupInfo = {
|
|
95
|
+
feeInfo: {
|
|
96
|
+
fee: string;
|
|
97
|
+
feeVault: string;
|
|
98
|
+
};
|
|
99
|
+
rewardToken: {
|
|
100
|
+
tokenAddress: string;
|
|
101
|
+
};
|
|
102
|
+
stakeToken: {
|
|
103
|
+
tokenAdress: string;
|
|
104
|
+
totalStaked: string;
|
|
105
|
+
};
|
|
106
|
+
stakeInfo: {
|
|
107
|
+
name: string;
|
|
108
|
+
creator: string;
|
|
109
|
+
rewardSchemes: RewardScheme[];
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
export type StakeInfo = {
|
|
113
|
+
nonce: bigint;
|
|
114
|
+
createdTime: number;
|
|
115
|
+
stakedAmount: string;
|
|
116
|
+
rewardAmount: string;
|
|
117
|
+
stakeClaimed: boolean;
|
|
118
|
+
lockPeriod: number;
|
|
119
|
+
};
|
|
120
|
+
export type UserNonceInfo = {
|
|
121
|
+
nonce: bigint;
|
|
122
|
+
};
|
|
123
|
+
export {};
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StakeService = exports.StakeServiceBuilder = void 0;
|
|
4
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
5
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
6
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
7
|
+
const core_utils_1 = require("@zebec-network/core-utils");
|
|
8
|
+
const solana_common_1 = require("@zebec-network/solana-common");
|
|
9
|
+
const artifacts_1 = require("./artifacts");
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
const pda_1 = require("./pda");
|
|
12
|
+
const providers_1 = require("./providers");
|
|
13
|
+
/**
|
|
14
|
+
* StakeServiceBuilder is a builder class for creating a StakeService instance.
|
|
15
|
+
* It allows you to set the network, provider, and program to use.
|
|
16
|
+
*/
|
|
17
|
+
class StakeServiceBuilder {
|
|
18
|
+
_program;
|
|
19
|
+
_provider;
|
|
20
|
+
_network;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param network The network to use. If not set, a default network: 'mainnet-beta' will be used.
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
setNetwork(network) {
|
|
27
|
+
if (this._network) {
|
|
28
|
+
throw new Error("InvalidOperation: Network is set twice.");
|
|
29
|
+
}
|
|
30
|
+
this._network = network ? network : "mainnet-beta";
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set the provider to use. If not set, a default provider will be created.
|
|
35
|
+
* @param provider The provider to use. If not set, a default provider: 'ReadonlyProvider' will be created.
|
|
36
|
+
* @returns The StakeServiceBuilder instance.
|
|
37
|
+
*/
|
|
38
|
+
setProvider(provider) {
|
|
39
|
+
if (this._provider) {
|
|
40
|
+
throw new Error("InvalidOperation: Provider is set twice.");
|
|
41
|
+
}
|
|
42
|
+
if (!this._network) {
|
|
43
|
+
throw new Error("InvalidOperation: Network is not set. Please set the network before setting the provider.");
|
|
44
|
+
}
|
|
45
|
+
if (provider) {
|
|
46
|
+
this.validateProviderNetwork(provider, this._network);
|
|
47
|
+
this._provider = provider;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this._provider = (0, providers_1.createReadonlyProvider)(new web3_js_1.Connection((0, web3_js_1.clusterApiUrl)(this._network)));
|
|
51
|
+
}
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* @param provider The provider to compare with.
|
|
57
|
+
*/
|
|
58
|
+
validateProviderNetwork(provider, network) {
|
|
59
|
+
const connection = provider.connection;
|
|
60
|
+
const rpcEndpoint = connection.rpcEndpoint;
|
|
61
|
+
const connNetwork = rpcEndpoint.includes("devnet")
|
|
62
|
+
? "devnet"
|
|
63
|
+
: rpcEndpoint.includes("testnet")
|
|
64
|
+
? "testnet"
|
|
65
|
+
: rpcEndpoint.includes("localhost:8899")
|
|
66
|
+
? "localnet"
|
|
67
|
+
: "mainnet-beta";
|
|
68
|
+
if (network !== connNetwork) {
|
|
69
|
+
throw new Error(`InvalidOperation: Network mismatch. network and connection network should be same. network: ${this._network}, connection: ${connNetwork}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Set the program to use. If not set, a default program will be created.
|
|
74
|
+
* @param program The program to use. If not set, a default program will be created.
|
|
75
|
+
* @returns The StakeServiceBuilder instance.
|
|
76
|
+
*/
|
|
77
|
+
setProgram(createProgram) {
|
|
78
|
+
if (this._program) {
|
|
79
|
+
throw new Error("InvalidOperation: Program is set twice.");
|
|
80
|
+
}
|
|
81
|
+
if (!this._network) {
|
|
82
|
+
throw new Error("InvalidOperation: Network is not set. Please set the network before setting the provider.");
|
|
83
|
+
}
|
|
84
|
+
if (!this._provider) {
|
|
85
|
+
throw new Error("InvalidOperation: Provider is not set. Please set the provider before setting the program.");
|
|
86
|
+
}
|
|
87
|
+
this._program = !createProgram ? new anchor_1.Program(artifacts_1.ZEBEC_STAKE_IDL_V1, this._provider) : createProgram(this._provider);
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
build() {
|
|
91
|
+
if (!this._network) {
|
|
92
|
+
throw new Error("InvalidOperation: Network is not set. Please set the network before building the service.");
|
|
93
|
+
}
|
|
94
|
+
if (!this._provider) {
|
|
95
|
+
throw new Error("InvalidOperation: Provider is not set. Please set the provider before building the service.");
|
|
96
|
+
}
|
|
97
|
+
if (!this._program) {
|
|
98
|
+
throw new Error("InvalidOperation: Program is not set. Please set the program before building the service.");
|
|
99
|
+
}
|
|
100
|
+
return new StakeService(this._provider, this._program, this._network);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.StakeServiceBuilder = StakeServiceBuilder;
|
|
104
|
+
class StakeService {
|
|
105
|
+
provider;
|
|
106
|
+
program;
|
|
107
|
+
network;
|
|
108
|
+
constructor(provider, program, network) {
|
|
109
|
+
this.provider = provider;
|
|
110
|
+
this.program = program;
|
|
111
|
+
this.network = network;
|
|
112
|
+
}
|
|
113
|
+
async _createPayload(payerKey, instructions, signers, addressLookupTableAccounts) {
|
|
114
|
+
const errorMap = new Map();
|
|
115
|
+
this.program.idl.errors.forEach((error) => errorMap.set(error.code, error.msg));
|
|
116
|
+
let signTransaction = undefined;
|
|
117
|
+
const provider = this.provider;
|
|
118
|
+
if (provider instanceof anchor_1.AnchorProvider) {
|
|
119
|
+
signTransaction = async (tx) => {
|
|
120
|
+
return provider.wallet.signTransaction(tx);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return new solana_common_1.TransactionPayload(this.provider.connection, errorMap, instructions, payerKey, signers, addressLookupTableAccounts, signTransaction);
|
|
124
|
+
}
|
|
125
|
+
async getInitLockupInstruction(creator, lockup, stakeToken, rewardToken, rewardVault, stakeVault, data) {
|
|
126
|
+
return this.program.methods
|
|
127
|
+
.initLockup({
|
|
128
|
+
fee: data.fee,
|
|
129
|
+
durationMap: data.rewardSchemes,
|
|
130
|
+
feeVault: data.feeVault,
|
|
131
|
+
name: data.name,
|
|
132
|
+
})
|
|
133
|
+
.accountsPartial({
|
|
134
|
+
creator,
|
|
135
|
+
lockup,
|
|
136
|
+
rewardToken,
|
|
137
|
+
rewardVault,
|
|
138
|
+
stakeToken,
|
|
139
|
+
stakeVault,
|
|
140
|
+
})
|
|
141
|
+
.instruction();
|
|
142
|
+
}
|
|
143
|
+
async getStakeInstruction(lockup, stakeToken, stakeVault, staker, userNonce, stakePda, stakeVaultTokenAccount, data) {
|
|
144
|
+
return this.program.methods
|
|
145
|
+
.stakeZbcn(data)
|
|
146
|
+
.accountsPartial({ stakeToken, staker, lockup, stakeVault, userNonce, stakePda, stakeVaultTokenAccount })
|
|
147
|
+
.instruction();
|
|
148
|
+
}
|
|
149
|
+
async getUnstakeInstruction(feeVault, lockup, stakePda, rewardToken, rewardVault, stakeToken, stakeVault, staker, stakerTokenAccount, nonce) {
|
|
150
|
+
return this.program.methods
|
|
151
|
+
.unstakeZbcn(nonce)
|
|
152
|
+
.accountsPartial({
|
|
153
|
+
feeVault,
|
|
154
|
+
rewardToken,
|
|
155
|
+
stakeToken,
|
|
156
|
+
staker,
|
|
157
|
+
lockup,
|
|
158
|
+
stakeVault,
|
|
159
|
+
stakePda,
|
|
160
|
+
rewardVault,
|
|
161
|
+
stakerTokenAccount,
|
|
162
|
+
})
|
|
163
|
+
.instruction();
|
|
164
|
+
}
|
|
165
|
+
async initLockup(params) {
|
|
166
|
+
const creator = params.creator ? (0, anchor_1.translateAddress)(params.creator) : this.provider.publicKey;
|
|
167
|
+
if (!creator) {
|
|
168
|
+
throw new Error("MissingArgument: Please provide either creator address or publicKey in provider");
|
|
169
|
+
}
|
|
170
|
+
const stakeToken = (0, anchor_1.translateAddress)(params.stakeToken);
|
|
171
|
+
const rewardToken = (0, anchor_1.translateAddress)(params.rewardToken);
|
|
172
|
+
const feeVault = (0, anchor_1.translateAddress)(params.feeVault);
|
|
173
|
+
const stakeTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, stakeToken);
|
|
174
|
+
const rewardSchemes = params.rewardSchemes.map((value) => {
|
|
175
|
+
return {
|
|
176
|
+
duration: new anchor_1.BN(value.duration),
|
|
177
|
+
reward: new anchor_1.BN((0, core_utils_1.percentToBps)(value.rewardRate)),
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
const lockup = (0, pda_1.deriveLockupAddress)(params.name, this.program.programId);
|
|
181
|
+
const rewardVault = (0, pda_1.deriveRewardVaultAddress)(lockup, this.program.programId);
|
|
182
|
+
const stakeVault = (0, pda_1.deriveStakeVaultAddress)(lockup, this.program.programId);
|
|
183
|
+
const fee = new anchor_1.BN((0, bignumber_js_1.BigNumber)(params.fee).times(constants_1.TEN_BIGNUM.pow(stakeTokenDecimals)).toFixed());
|
|
184
|
+
const instruction = await this.getInitLockupInstruction(creator, lockup, stakeToken, rewardToken, rewardVault, stakeVault, {
|
|
185
|
+
fee,
|
|
186
|
+
feeVault: feeVault,
|
|
187
|
+
name: params.name,
|
|
188
|
+
rewardSchemes,
|
|
189
|
+
});
|
|
190
|
+
return this._createPayload(creator, [instruction]);
|
|
191
|
+
}
|
|
192
|
+
async stake(params) {
|
|
193
|
+
const staker = params.staker ? (0, anchor_1.translateAddress)(params.staker) : this.provider.publicKey;
|
|
194
|
+
if (!staker) {
|
|
195
|
+
throw new Error("MissingArgument: Please provide either staker address or publicKey in provider");
|
|
196
|
+
}
|
|
197
|
+
const lockup = (0, pda_1.deriveLockupAddress)(params.lockupName, this.program.programId);
|
|
198
|
+
const lockupAccount = await this.program.account.lockup.fetchNullable(lockup, this.provider.connection.commitment);
|
|
199
|
+
if (!lockupAccount) {
|
|
200
|
+
throw new Error("Lockup account does not exists for address: " + lockup);
|
|
201
|
+
}
|
|
202
|
+
const stakeToken = lockupAccount.stakedToken.tokenAddress;
|
|
203
|
+
const stakeVault = (0, pda_1.deriveStakeVaultAddress)(lockup, this.program.programId);
|
|
204
|
+
const userNonce = (0, pda_1.deriveUserNonceAddress)(staker, lockup, this.program.programId);
|
|
205
|
+
const userNonceAccount = await this.program.account.userNonce.fetchNullable(userNonce, this.provider.connection.commitment);
|
|
206
|
+
let nonce = BigInt(0);
|
|
207
|
+
if (userNonceAccount) {
|
|
208
|
+
nonce = BigInt(userNonceAccount.nonce.toString());
|
|
209
|
+
}
|
|
210
|
+
const stakePda = (0, pda_1.deriveStakeAddress)(staker, lockup, nonce, this.program.programId);
|
|
211
|
+
const stakeVaultTokenAccount = (0, solana_common_1.getAssociatedTokenAddressSync)(stakeToken, stakeVault, true);
|
|
212
|
+
const stakeTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, stakeToken);
|
|
213
|
+
const UNITS_PER_STAKE_TOKEN = constants_1.TEN_BIGNUM.pow(stakeTokenDecimals);
|
|
214
|
+
const instruction = await this.getStakeInstruction(lockup, stakeToken, stakeVault, staker, userNonce, stakePda, stakeVaultTokenAccount, {
|
|
215
|
+
amount: new anchor_1.BN((0, bignumber_js_1.BigNumber)(params.amount).times(UNITS_PER_STAKE_TOKEN).toFixed(0)),
|
|
216
|
+
lockPeriod: new anchor_1.BN(params.lockPeriod),
|
|
217
|
+
nonce: new anchor_1.BN(params.nonce.toString()),
|
|
218
|
+
});
|
|
219
|
+
return this._createPayload(staker, [instruction]);
|
|
220
|
+
}
|
|
221
|
+
async unstake(params) {
|
|
222
|
+
const staker = params.staker ? (0, anchor_1.translateAddress)(params.staker) : this.provider.publicKey;
|
|
223
|
+
if (!staker) {
|
|
224
|
+
throw new Error("MissingArgument: Please provide either staker address or publicKey in provider");
|
|
225
|
+
}
|
|
226
|
+
const lockup = (0, pda_1.deriveLockupAddress)(params.lockupName, this.program.programId);
|
|
227
|
+
const lockupAccount = await this.program.account.lockup.fetchNullable(lockup, this.provider.connection.commitment);
|
|
228
|
+
if (!lockupAccount) {
|
|
229
|
+
throw new Error("Lockup account does not exists for address: " + lockup);
|
|
230
|
+
}
|
|
231
|
+
const stakeToken = lockupAccount.stakedToken.tokenAddress;
|
|
232
|
+
const rewardToken = lockupAccount.rewardToken.tokenAddress;
|
|
233
|
+
const feeVault = lockupAccount.feeInfo.feeVault;
|
|
234
|
+
const stakePda = (0, pda_1.deriveStakeAddress)(staker, lockup, params.nonce, this.program.programId);
|
|
235
|
+
const rewardVault = (0, pda_1.deriveRewardVaultAddress)(lockup, this.program.programId);
|
|
236
|
+
const stakeVault = (0, pda_1.deriveStakeVaultAddress)(lockup, this.program.programId);
|
|
237
|
+
const stakerTokenAccount = (0, solana_common_1.getAssociatedTokenAddressSync)(stakeToken, staker);
|
|
238
|
+
const instruction = await this.getUnstakeInstruction(feeVault, lockup, stakePda, rewardToken, rewardVault, stakeToken, stakeVault, staker, stakerTokenAccount, new anchor_1.BN(params.nonce.toString()));
|
|
239
|
+
return this._createPayload(staker, [instruction]);
|
|
240
|
+
}
|
|
241
|
+
async getLockupInfo(lockupAddress) {
|
|
242
|
+
const lockupAccount = await this.program.account.lockup.fetchNullable(lockupAddress, this.provider.connection.commitment);
|
|
243
|
+
if (!lockupAccount) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const stakeTokenAddress = lockupAccount.stakedToken.tokenAddress;
|
|
247
|
+
const stakeTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, stakeTokenAddress);
|
|
248
|
+
const UNITS_PER_STAKE_TOKEN = constants_1.TEN_BIGNUM.pow(stakeTokenDecimals);
|
|
249
|
+
return {
|
|
250
|
+
feeInfo: {
|
|
251
|
+
fee: (0, bignumber_js_1.BigNumber)(lockupAccount.feeInfo.fee.toString()).div(UNITS_PER_STAKE_TOKEN).toFixed(),
|
|
252
|
+
feeVault: lockupAccount.feeInfo.feeVault.toString(),
|
|
253
|
+
},
|
|
254
|
+
rewardToken: {
|
|
255
|
+
tokenAddress: lockupAccount.rewardToken.tokenAddress.toString(),
|
|
256
|
+
},
|
|
257
|
+
stakeToken: {
|
|
258
|
+
tokenAdress: lockupAccount.stakedToken.tokenAddress.toString(),
|
|
259
|
+
totalStaked: (0, bignumber_js_1.BigNumber)(lockupAccount.stakedToken.totalStaked.toString()).div(UNITS_PER_STAKE_TOKEN).toFixed(),
|
|
260
|
+
},
|
|
261
|
+
stakeInfo: {
|
|
262
|
+
name: lockupAccount.stakeInfo.name,
|
|
263
|
+
creator: lockupAccount.stakeInfo.creator.toString(),
|
|
264
|
+
rewardSchemes: lockupAccount.stakeInfo.durationMap.map((value) => ({
|
|
265
|
+
duration: value.duration.toNumber(),
|
|
266
|
+
rewardRate: (0, core_utils_1.bpsToPercent)(value.reward.toString()),
|
|
267
|
+
})),
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async getStakeInfo(stakeAddress, lockupAddress) {
|
|
272
|
+
const lockupAccount = await this.program.account.lockup.fetchNullable(lockupAddress, this.provider.connection.commitment);
|
|
273
|
+
if (!lockupAccount) {
|
|
274
|
+
throw new Error("Lockup account does not exists for address: " + lockupAddress);
|
|
275
|
+
}
|
|
276
|
+
const stakeTokenAddress = lockupAccount.stakedToken.tokenAddress;
|
|
277
|
+
const rewardTokenAddress = lockupAccount.rewardToken.tokenAddress;
|
|
278
|
+
const stakeTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, stakeTokenAddress);
|
|
279
|
+
const rewardTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, rewardTokenAddress);
|
|
280
|
+
const UNITS_PER_STAKE_TOKEN = constants_1.TEN_BIGNUM.pow(stakeTokenDecimals);
|
|
281
|
+
const UNITS_PER_REWARD_TOKEN = constants_1.TEN_BIGNUM.pow(rewardTokenDecimals);
|
|
282
|
+
const stakeAccount = await this.program.account.userStakeData.fetchNullable(stakeAddress, this.provider.connection.commitment);
|
|
283
|
+
if (!stakeAccount) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
nonce: BigInt(stakeAccount.nonce.toString()),
|
|
288
|
+
createdTime: stakeAccount.createdTime.toNumber(),
|
|
289
|
+
stakedAmount: (0, bignumber_js_1.BigNumber)(stakeAccount.stakedAmount.toString()).div(UNITS_PER_STAKE_TOKEN).toFixed(),
|
|
290
|
+
rewardAmount: (0, bignumber_js_1.BigNumber)(stakeAccount.rewardAmount.toString()).div(UNITS_PER_REWARD_TOKEN).toFixed(),
|
|
291
|
+
stakeClaimed: stakeAccount.stakeClaimed,
|
|
292
|
+
lockPeriod: stakeAccount.lockPeriod.toNumber(),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
async getUserNonceInfo(userNonceAddress) {
|
|
296
|
+
const userNonceAccount = await this.program.account.userNonce.fetchNullable(userNonceAddress, this.provider.connection.commitment);
|
|
297
|
+
if (!userNonceAccount) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
nonce: BigInt(userNonceAccount.nonce.toString()),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
exports.StakeService = StakeService;
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zebec-network/zebec-stake-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An SDK for zebec network stake solana program",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"author": "Ashish Sapkota",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"solana",
|
|
14
|
+
"zebec",
|
|
15
|
+
"zebec network",
|
|
16
|
+
"stake",
|
|
17
|
+
"staking"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "npm run clean && tsc",
|
|
21
|
+
"clean": "rimraf ./dist",
|
|
22
|
+
"format": "prettier --write .",
|
|
23
|
+
"start": "ts-node src/index.ts",
|
|
24
|
+
"test": "ts-mocha -p ./tsconfig.json -t 1000000"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@coral-xyz/anchor": "^0.31.1",
|
|
28
|
+
"@solana/web3.js": "1.98.2",
|
|
29
|
+
"@types/bn.js": "^5.1.6",
|
|
30
|
+
"@zebec-network/core-utils": "^1.0.4",
|
|
31
|
+
"@zebec-network/solana-common": "^1.2.6",
|
|
32
|
+
"bignumber.js": "^9.3.0",
|
|
33
|
+
"buffer": "^6.0.3",
|
|
34
|
+
"dotenv": "^16.5.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/mocha": "^10.0.10",
|
|
38
|
+
"@types/node": "^22.14.1",
|
|
39
|
+
"mocha": "^11.1.0",
|
|
40
|
+
"prettier": "^3.5.3",
|
|
41
|
+
"rimraf": "^6.0.1",
|
|
42
|
+
"ts-mocha": "^11.1.0",
|
|
43
|
+
"ts-node": "^10.9.2",
|
|
44
|
+
"typescript": "^5.8.3"
|
|
45
|
+
}
|
|
46
|
+
}
|