@chorus-one/polygon 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.
Files changed (43) hide show
  1. package/.mocharc.json +6 -0
  2. package/LICENSE +13 -0
  3. package/README.md +233 -0
  4. package/dist/cjs/constants.d.ts +187 -0
  5. package/dist/cjs/constants.js +141 -0
  6. package/dist/cjs/index.d.ts +4 -0
  7. package/dist/cjs/index.js +12 -0
  8. package/dist/cjs/package.json +3 -0
  9. package/dist/cjs/referrer.d.ts +2 -0
  10. package/dist/cjs/referrer.js +15 -0
  11. package/dist/cjs/staker.d.ts +335 -0
  12. package/dist/cjs/staker.js +716 -0
  13. package/dist/cjs/types.d.ts +40 -0
  14. package/dist/cjs/types.js +2 -0
  15. package/dist/mjs/constants.d.ts +187 -0
  16. package/dist/mjs/constants.js +138 -0
  17. package/dist/mjs/index.d.ts +4 -0
  18. package/dist/mjs/index.js +2 -0
  19. package/dist/mjs/package.json +3 -0
  20. package/dist/mjs/referrer.d.ts +2 -0
  21. package/dist/mjs/referrer.js +11 -0
  22. package/dist/mjs/staker.d.ts +335 -0
  23. package/dist/mjs/staker.js +712 -0
  24. package/dist/mjs/types.d.ts +40 -0
  25. package/dist/mjs/types.js +1 -0
  26. package/hardhat.config.ts +27 -0
  27. package/package.json +50 -0
  28. package/src/constants.ts +151 -0
  29. package/src/index.ts +14 -0
  30. package/src/referrer.ts +15 -0
  31. package/src/staker.ts +878 -0
  32. package/src/types.ts +45 -0
  33. package/test/fixtures/expected-data.ts +17 -0
  34. package/test/integration/localSigner.spec.ts +128 -0
  35. package/test/integration/setup.ts +41 -0
  36. package/test/integration/staker.spec.ts +587 -0
  37. package/test/integration/testStaker.ts +130 -0
  38. package/test/integration/utils.ts +263 -0
  39. package/test/lib/networks.json +14 -0
  40. package/test/staker.spec.ts +154 -0
  41. package/tsconfig.cjs.json +9 -0
  42. package/tsconfig.json +13 -0
  43. package/tsconfig.mjs.json +9 -0
@@ -0,0 +1,40 @@
1
+ import type { Hex, TransactionReceipt } from 'viem';
2
+ import type { PolygonNetworks } from './constants';
3
+ export interface PolygonNetworkConfig {
4
+ /** Network to use: 'mainnet' (Ethereum L1) or 'testnet' (Sepolia L1) */
5
+ network: PolygonNetworks;
6
+ /** Optional RPC endpoint URL override. If not provided, uses viem's default for the network. */
7
+ rpcUrl?: string;
8
+ }
9
+ export interface Transaction {
10
+ /** The recipient (contract) address in hexadecimal format */
11
+ to: Hex;
12
+ /** The data to be included in the transaction in hexadecimal format (includes referrer tracking suffix) */
13
+ data: Hex;
14
+ /** The amount of ETH (in wei) to be sent with the transaction */
15
+ value?: bigint;
16
+ }
17
+ export interface PolygonTxStatus {
18
+ /** Status of the transaction */
19
+ status: 'success' | 'failure' | 'unknown';
20
+ /** Transaction receipt (null if unknown) */
21
+ receipt: TransactionReceipt | null;
22
+ }
23
+ export interface StakeInfo {
24
+ /** Total staked amount formatted in POL */
25
+ balance: string;
26
+ /** Total shares held by the delegator */
27
+ shares: bigint;
28
+ /** Current exchange rate between shares and POL (with high precision) */
29
+ exchangeRate: bigint;
30
+ }
31
+ export interface UnbondInfo {
32
+ /** Amount pending unbonding in POL */
33
+ amount: string;
34
+ /** Whether the unbond can be withdrawn now */
35
+ isWithdrawable: boolean;
36
+ /** Shares amount pending unbonding */
37
+ shares: bigint;
38
+ /** Epoch number when the unbond becomes claimable */
39
+ withdrawEpoch: bigint;
40
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { type HardhatUserConfig } from 'hardhat/config'
2
+ import networkConfig from './test/lib/networks.json'
3
+
4
+ const config: HardhatUserConfig = {
5
+ solidity: '0.8.20',
6
+ networks: {
7
+ hardhat: {
8
+ type: 'edr-simulated',
9
+ initialBaseFeePerGas: 0,
10
+ forking: {
11
+ url: networkConfig.networks.ethereum.url,
12
+ enabled: true,
13
+ blockNumber: 24382010 // Fetched on 2026-02-04
14
+ },
15
+ accounts: networkConfig.accounts.map((acc) => ({
16
+ privateKey: acc.privateKey,
17
+ balance: acc.balance
18
+ }))
19
+ },
20
+ localhost: {
21
+ type: 'http',
22
+ url: 'http://127.0.0.1:8545'
23
+ }
24
+ }
25
+ }
26
+
27
+ export default config
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@chorus-one/polygon",
3
+ "version": "1.0.0",
4
+ "description": "All-in-one toolkit for building staking dApps on Polygon network",
5
+ "scripts": {
6
+ "build": "rm -fr dist/* && tsc -p tsconfig.mjs.json --outDir dist/mjs && tsc -p tsconfig.cjs.json --outDir dist/cjs && bash ../../scripts/fix-package-json",
7
+ "test": "mocha 'test/**/*.spec.ts' --ignore 'test/integration/**/*.spec.ts'",
8
+ "hardhat:start": "hardhat node --network hardhat & echo $! > hardhat.pid;",
9
+ "hardhat:stop": "kill $(cat hardhat.pid) && rm hardhat.pid",
10
+ "test:integration": "npm run hardhat:start > hardhat.log & sleep 5; mocha --require tsx --timeout 60000 'test/integration/setup.ts' 'test/integration/**/*.spec.ts'; status=$?; npm run hardhat:stop; exit $status"
11
+ },
12
+ "main": "dist/cjs/index.js",
13
+ "module": "dist/mjs/index.js",
14
+ "types": "dist/mjs/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/mjs/index.js",
18
+ "require": "./dist/cjs/index.js",
19
+ "types": "./dist/mjs/index.d.ts"
20
+ }
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/ChorusOne/chorus-one-sdk.git",
25
+ "directory": "packages/polygon"
26
+ },
27
+ "homepage": "https://chorus-one.gitbook.io/sdk",
28
+ "keywords": [
29
+ "polygon",
30
+ "staking",
31
+ "dApps",
32
+ "blockchain",
33
+ "chorus-one",
34
+ "sdk"
35
+ ],
36
+ "author": "Chorus One AG",
37
+ "license": "Apache-2.0",
38
+ "type": "module",
39
+ "dependencies": {
40
+ "@chorus-one/signer": "^1.0.0",
41
+ "@noble/curves": "^2.0.1",
42
+ "viem": "^2.28.0"
43
+ },
44
+ "devDependencies": {
45
+ "@chorus-one/signer-local": "^1.0.0",
46
+ "@scure/bip32": "^1.6.2",
47
+ "bip39": "^3.1.0",
48
+ "hardhat": "^3.0.3"
49
+ }
50
+ }
@@ -0,0 +1,151 @@
1
+ import type { Address } from 'viem'
2
+
3
+ export type PolygonNetworks = 'mainnet' | 'testnet'
4
+
5
+ export interface NetworkContracts {
6
+ stakeManagerAddress: Address
7
+ stakingTokenAddress: Address
8
+ }
9
+
10
+ /** Contract addresses per network (mainnet = Ethereum L1, testnet = Sepolia L1) */
11
+ // Reference: https://docs.polygon.technology/pos/reference/rpc-endpoints/
12
+ export const NETWORK_CONTRACTS: Record<PolygonNetworks, NetworkContracts> = {
13
+ mainnet: {
14
+ stakeManagerAddress: '0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908',
15
+ stakingTokenAddress: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6'
16
+ },
17
+ testnet: {
18
+ stakeManagerAddress: '0x4AE8f648B1Ec892B6cc68C89cc088583964d08bE',
19
+ stakingTokenAddress: '0x44499312f493F62f2DFd3C6435Ca3603EbFCeeBa'
20
+ }
21
+ }
22
+
23
+ /** Chorus One Polygon ValidatorShare contract addresses */
24
+ // Reference mainnet: https://staking.polygon.technology/validators/106
25
+ // Reference testnet (Random Validator): https://staking.polygon.technology/validators/31
26
+ export const CHORUS_ONE_POLYGON_VALIDATORS = {
27
+ mainnet: '0xD9E6987D77bf2c6d0647b8181fd68A259f838C36' as Address,
28
+ testnet: '0x91344055cb0511b3aa36c561d741ee356b95f1c9' as Address
29
+ } as const
30
+
31
+ // Reference: https://github.com/0xPolygon/pos-contracts/blob/main/contracts/staking/validatorShare/ValidatorShare.sol
32
+ export const VALIDATOR_SHARE_ABI = [
33
+ {
34
+ type: 'function',
35
+ name: 'buyVoucherPOL',
36
+ inputs: [
37
+ { name: '_amount', type: 'uint256', internalType: 'uint256' },
38
+ { name: '_minSharesToMint', type: 'uint256', internalType: 'uint256' }
39
+ ],
40
+ outputs: [{ name: 'amountToDeposit', type: 'uint256', internalType: 'uint256' }],
41
+ stateMutability: 'nonpayable'
42
+ },
43
+ {
44
+ type: 'function',
45
+ name: 'sellVoucher_newPOL',
46
+ inputs: [
47
+ { name: 'claimAmount', type: 'uint256', internalType: 'uint256' },
48
+ { name: 'maximumSharesToBurn', type: 'uint256', internalType: 'uint256' }
49
+ ],
50
+ outputs: [],
51
+ stateMutability: 'nonpayable'
52
+ },
53
+ {
54
+ type: 'function',
55
+ name: 'unstakeClaimTokens_newPOL',
56
+ inputs: [{ name: 'unbondNonce', type: 'uint256', internalType: 'uint256' }],
57
+ outputs: [],
58
+ stateMutability: 'nonpayable'
59
+ },
60
+ {
61
+ type: 'function',
62
+ name: 'withdrawRewardsPOL',
63
+ inputs: [],
64
+ outputs: [],
65
+ stateMutability: 'nonpayable'
66
+ },
67
+ {
68
+ type: 'function',
69
+ name: 'restakePOL',
70
+ inputs: [],
71
+ outputs: [
72
+ { name: 'amountRestaked', type: 'uint256', internalType: 'uint256' },
73
+ { name: 'liquidReward', type: 'uint256', internalType: 'uint256' }
74
+ ],
75
+ stateMutability: 'nonpayable'
76
+ },
77
+ {
78
+ type: 'function',
79
+ name: 'getTotalStake',
80
+ inputs: [{ name: 'user', type: 'address', internalType: 'address' }],
81
+ outputs: [
82
+ { name: '', type: 'uint256', internalType: 'uint256' },
83
+ { name: '', type: 'uint256', internalType: 'uint256' }
84
+ ],
85
+ stateMutability: 'view'
86
+ },
87
+ {
88
+ type: 'function',
89
+ name: 'unbondNonces',
90
+ inputs: [{ name: '', type: 'address', internalType: 'address' }],
91
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
92
+ stateMutability: 'view'
93
+ },
94
+ {
95
+ type: 'function',
96
+ name: 'unbonds_new',
97
+ inputs: [
98
+ { name: '', type: 'address', internalType: 'address' },
99
+ { name: '', type: 'uint256', internalType: 'uint256' }
100
+ ],
101
+ outputs: [
102
+ { name: 'shares', type: 'uint256', internalType: 'uint256' },
103
+ { name: 'withdrawEpoch', type: 'uint256', internalType: 'uint256' }
104
+ ],
105
+ stateMutability: 'view'
106
+ },
107
+ {
108
+ type: 'function',
109
+ name: 'getLiquidRewards',
110
+ inputs: [{ name: 'user', type: 'address', internalType: 'address' }],
111
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
112
+ stateMutability: 'view'
113
+ },
114
+ {
115
+ type: 'function',
116
+ name: 'validatorId',
117
+ inputs: [],
118
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
119
+ stateMutability: 'view'
120
+ },
121
+ {
122
+ type: 'function',
123
+ name: 'withdrawExchangeRate',
124
+ inputs: [],
125
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
126
+ stateMutability: 'view'
127
+ }
128
+ ] as const
129
+
130
+ // Exchange rate precision constants from the ValidatorShare contract
131
+ // Reference: https://github.com/0xPolygon/pos-contracts/blob/main/contracts/staking/validatorShare/ValidatorShare.sol
132
+ export const EXCHANGE_RATE_PRECISION = 100n
133
+ export const EXCHANGE_RATE_HIGH_PRECISION = 10n ** 29n
134
+
135
+ // Reference: https://github.com/0xPolygon/pos-contracts/blob/main/contracts/staking/stakeManager/StakeManager.sol
136
+ export const STAKE_MANAGER_ABI = [
137
+ {
138
+ type: 'function',
139
+ name: 'epoch',
140
+ inputs: [],
141
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
142
+ stateMutability: 'view'
143
+ },
144
+ {
145
+ type: 'function',
146
+ name: 'withdrawalDelay',
147
+ inputs: [],
148
+ outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
149
+ stateMutability: 'view'
150
+ }
151
+ ] as const
package/src/index.ts ADDED
@@ -0,0 +1,14 @@
1
+ export { PolygonStaker } from './staker'
2
+
3
+ export { PolygonNetworkConfig, Transaction, PolygonTxStatus, StakeInfo, UnbondInfo } from './types'
4
+
5
+ export {
6
+ NETWORK_CONTRACTS,
7
+ CHORUS_ONE_POLYGON_VALIDATORS,
8
+ VALIDATOR_SHARE_ABI,
9
+ STAKE_MANAGER_ABI,
10
+ EXCHANGE_RATE_PRECISION,
11
+ EXCHANGE_RATE_HIGH_PRECISION
12
+ } from './constants'
13
+
14
+ export type { PolygonNetworks, NetworkContracts } from './constants'
@@ -0,0 +1,15 @@
1
+ import type { Hex } from 'viem'
2
+ import { keccak256, toHex } from 'viem'
3
+
4
+ const DEFAULT_REFERRER = 'sdk-chorusone-staking'
5
+ const REFERRER_MARKER = 'c1c1'
6
+
7
+ const encodeReferrer = (referrer: string): Hex => {
8
+ const hash = keccak256(toHex(referrer))
9
+ return `0x${REFERRER_MARKER}${hash.slice(2, 8)}`
10
+ }
11
+
12
+ export const appendReferrerTracking = (data: Hex, referrer?: string): Hex => {
13
+ const encoded = encodeReferrer(referrer ?? DEFAULT_REFERRER)
14
+ return `${data}${encoded.slice(2)}` as Hex
15
+ }