Skip to content

Commit 50e6075

Browse files
committed
Initial setup
1 parent efeb730 commit 50e6075

21 files changed

+1940
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ packages/ethereum/hardhat.log
2525
packages/ethereum/hardhat.pid
2626
packages/ethereum/edr-fork-cache
2727

28+
packages/polygon/cache
29+
packages/polygon/hardhat.log
30+
packages/polygon/hardhat.pid
31+
packages/polygon/edr-fork-cache
32+
2833
.env
2934
packages/**/.env
3035

package-lock.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/polygon/.mocharc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"require": ["tsx/cjs"],
3+
"extensions": ["ts"],
4+
"spec": ["test/**/*.spec.ts"],
5+
"timeout": 10000,
6+
"reporter": "spec"
7+
}

packages/polygon/LICENSE

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2024 Chorus One AG
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

packages/polygon/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Chorus One SDK: Polygon
2+
3+
All-in-one toolkit for building staking dApps on Polygon network.
4+
5+
## Documentation
6+
7+
For detailed instructions on how to set up and use the Chorus One SDK for Polygon staking, please visit our [main documentation](https://chorus-one.gitbook.io/sdk/build-your-staking-dapp/polygon/overview).
8+
9+
## Installation
10+
11+
In the project's root directory, run the following command:
12+
13+
```bash
14+
npm install @chorus-one/polygon
15+
```
16+
17+
## Usage
18+
19+
Here is a basic example of how to use the Chorus One SDK to build, sign, and broadcast a staking transaction using Fireblocks as the signer.
20+
21+
```javascript
22+
// Configuration
23+
// -------------
24+
25+
import { PolygonStaker } from '@chorus-one/polygon'
26+
27+
const staker = new PolygonStaker({
28+
rpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY'
29+
})
30+
31+
await staker.init()
32+
33+
// Approving MATIC tokens
34+
// ----------------------
35+
36+
const delegatorAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
37+
const validatorShareAddress = '0x...' // Validator's share contract address
38+
39+
const { tx: approveTx } = await staker.buildApproveTx({
40+
amount: '1000' // Amount in MATIC
41+
})
42+
43+
// Building the staking transaction
44+
// ---------------------------------
45+
46+
const { tx } = await staker.buildStakeTx({
47+
delegatorAddress,
48+
validatorShareAddress,
49+
amount: '1000' // Amount in MATIC
50+
})
51+
52+
// Signing the transaction with Fireblocks
53+
// ----------------------------------------
54+
55+
import { FireblocksSigner } from '@chorus-one/signer-fireblocks'
56+
57+
const signer = new FireblocksSigner({...})
58+
await signer.init()
59+
60+
const { signedTx } = await staker.sign({
61+
signer,
62+
signerAddress: delegatorAddress,
63+
tx
64+
})
65+
66+
// Broadcasting the transaction
67+
// ----------------------------
68+
69+
const { txHash } = await staker.broadcast({ signedTx })
70+
71+
// Tracking the transaction
72+
// ------------------------
73+
74+
const { status, receipt } = await staker.getTxStatus({ txHash })
75+
76+
console.log(status) // 'success'
77+
```
78+
79+
## License
80+
81+
The Chorus One SDK is licensed under the Apache 2.0 License. For more detailed information, please refer to the [LICENSE](./LICENSE) file in the repository.

packages/polygon/hardhat.config.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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: 21500000
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

packages/polygon/package.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
"@chorus-one/utils": "^1.0.2",
42+
"secp256k1": "^5.0.0",
43+
"viem": "^2.28.0"
44+
},
45+
"devDependencies": {
46+
"hardhat": "^3.0.3"
47+
}
48+
}

packages/polygon/src/constants.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import type { Address } from 'viem'
2+
3+
/** Polygon StakeManager proxy contract on Ethereum mainnet */
4+
export const POLYGON_STAKE_MANAGER_ADDRESS: Address = '0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908'
5+
6+
/** POL token contract on Ethereum mainnet (staking token, migrated from MATIC via PIP-42) */
7+
export const POLYGON_STAKING_TOKEN_ADDRESS: Address = '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6'
8+
9+
/** Chorus One Polygon ValidatorShare contract addresses */
10+
export const CHORUS_ONE_POLYGON_VALIDATORS = {
11+
mainnet: '0xD9E6987D77bf2c6d0647b8181fd68A259f838C36' as Address
12+
} as const
13+
14+
export const VALIDATOR_SHARE_ABI = [
15+
{
16+
type: 'function',
17+
name: 'buyVoucherPOL',
18+
inputs: [
19+
{ name: '_amount', type: 'uint256', internalType: 'uint256' },
20+
{ name: '_minSharesToMint', type: 'uint256', internalType: 'uint256' }
21+
],
22+
outputs: [{ name: 'amountToDeposit', type: 'uint256', internalType: 'uint256' }],
23+
stateMutability: 'nonpayable'
24+
},
25+
{
26+
type: 'function',
27+
name: 'sellVoucher_newPOL',
28+
inputs: [
29+
{ name: 'claimAmount', type: 'uint256', internalType: 'uint256' },
30+
{ name: 'maximumSharesToBurn', type: 'uint256', internalType: 'uint256' }
31+
],
32+
outputs: [],
33+
stateMutability: 'nonpayable'
34+
},
35+
{
36+
type: 'function',
37+
name: 'unstakeClaimTokens_newPOL',
38+
inputs: [{ name: 'unbondNonce', type: 'uint256', internalType: 'uint256' }],
39+
outputs: [],
40+
stateMutability: 'nonpayable'
41+
},
42+
{
43+
type: 'function',
44+
name: 'withdrawRewardsPOL',
45+
inputs: [],
46+
outputs: [],
47+
stateMutability: 'nonpayable'
48+
},
49+
{
50+
type: 'function',
51+
name: 'restakePOL',
52+
inputs: [],
53+
outputs: [
54+
{ name: 'amountRestaked', type: 'uint256', internalType: 'uint256' },
55+
{ name: 'liquidReward', type: 'uint256', internalType: 'uint256' }
56+
],
57+
stateMutability: 'nonpayable'
58+
},
59+
{
60+
type: 'function',
61+
name: 'getTotalStake',
62+
inputs: [{ name: 'user', type: 'address', internalType: 'address' }],
63+
outputs: [
64+
{ name: '', type: 'uint256', internalType: 'uint256' },
65+
{ name: '', type: 'uint256', internalType: 'uint256' }
66+
],
67+
stateMutability: 'view'
68+
},
69+
{
70+
type: 'function',
71+
name: 'unbondNonces',
72+
inputs: [{ name: '', type: 'address', internalType: 'address' }],
73+
outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
74+
stateMutability: 'view'
75+
},
76+
{
77+
type: 'function',
78+
name: 'unbonds_new',
79+
inputs: [
80+
{ name: '', type: 'address', internalType: 'address' },
81+
{ name: '', type: 'uint256', internalType: 'uint256' }
82+
],
83+
outputs: [
84+
{ name: 'shares', type: 'uint256', internalType: 'uint256' },
85+
{ name: 'withdrawEpoch', type: 'uint256', internalType: 'uint256' }
86+
],
87+
stateMutability: 'view'
88+
},
89+
{
90+
type: 'function',
91+
name: 'getLiquidRewards',
92+
inputs: [{ name: 'user', type: 'address', internalType: 'address' }],
93+
outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
94+
stateMutability: 'view'
95+
}
96+
] as const
97+
98+
export const ERC20_ABI = [
99+
{
100+
type: 'function',
101+
name: 'approve',
102+
inputs: [
103+
{ name: 'spender', type: 'address', internalType: 'address' },
104+
{ name: 'amount', type: 'uint256', internalType: 'uint256' }
105+
],
106+
outputs: [{ name: '', type: 'bool', internalType: 'bool' }],
107+
stateMutability: 'nonpayable'
108+
},
109+
{
110+
type: 'function',
111+
name: 'allowance',
112+
inputs: [
113+
{ name: 'owner', type: 'address', internalType: 'address' },
114+
{ name: 'spender', type: 'address', internalType: 'address' }
115+
],
116+
outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
117+
stateMutability: 'view'
118+
}
119+
] as const
120+
121+
export const STAKE_MANAGER_ABI = [
122+
{
123+
type: 'function',
124+
name: 'epoch',
125+
inputs: [],
126+
outputs: [{ name: '', type: 'uint256', internalType: 'uint256' }],
127+
stateMutability: 'view'
128+
}
129+
] as const

packages/polygon/src/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export { PolygonStaker } from './staker'
2+
3+
export {
4+
PolygonNetworkConfig,
5+
Transaction,
6+
PolygonTxStatus,
7+
StakeInfo,
8+
UnbondInfo
9+
} from './types.d'
10+
11+
export {
12+
POLYGON_STAKE_MANAGER_ADDRESS,
13+
POLYGON_STAKING_TOKEN_ADDRESS,
14+
CHORUS_ONE_POLYGON_VALIDATORS,
15+
VALIDATOR_SHARE_ABI,
16+
ERC20_ABI,
17+
STAKE_MANAGER_ABI
18+
} from './constants'
19+
20+
export { buildReferrerTracking } from './referrer'

packages/polygon/src/referrer.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { AccessList, Address, Hex } from 'viem'
2+
import { keccak256, toHex } from 'viem'
3+
4+
const DEFAULT_REFERRER = 'sdk-chorusone-staking'
5+
const ACCESS_LIST_SENTINEL: Address = '0x000000000000000000000000000000000000dEaD'
6+
7+
const buildDefaultReferrerSlot = (): Hex => {
8+
const hash = keccak256(toHex(DEFAULT_REFERRER))
9+
const tag = `c1c1${hash.slice(2, 8)}`
10+
return `0x${tag.padEnd(64, '0')}`
11+
}
12+
13+
export const buildReferrerTracking = (referrer?: Hex): AccessList => [
14+
{
15+
address: ACCESS_LIST_SENTINEL,
16+
storageKeys: [referrer ?? buildDefaultReferrerSlot()]
17+
}
18+
]

0 commit comments

Comments
 (0)