@exodus/ethereum-api 6.2.15 → 6.2.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "6.2.15",
3
+ "version": "6.2.16",
4
4
  "description": "Ethereum Api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -36,5 +36,5 @@
36
36
  "devDependencies": {
37
37
  "@exodus/models": "^8.10.4"
38
38
  },
39
- "gitHead": "400f32b2bc05d771cf049327cf599aaf105fc7f9"
39
+ "gitHead": "0e97de11d59c09ce5403c1e5641cb520b537b712"
40
40
  }
@@ -18,6 +18,9 @@ export class MaticStaking {
18
18
  validatorId = EVERSTAKE_VALIDATOR_CONTRACT_ADDR,
19
19
  stakeManagerAddr = STAKING_MANAGER_ADDR
20
20
  ) {
21
+ // harcoded exchange rate from the validtor share contract
22
+ // in order to calculate claim unstake amount off-chain
23
+ this.EXCHANGE_RATE_PRECISION = new BN(10).pow(new BN(29))
21
24
  this.validatorShareContract = createContract(validatorId, 'maticValidatorShare')
22
25
  this.stakingManagerContract = createContract(stakeManagerAddr, 'maticStakingManager')
23
26
  this.polygonContract = createContract(polygonEthToken.contract.current, 'polygon')
@@ -40,22 +43,20 @@ export class MaticStaking {
40
43
  return retry(eth.ethCall, { delayTimesMs: RETRY_DELAYS })(data)
41
44
  }
42
45
 
43
- /**
44
- * Approves StakeManager contract for withdrawing {amount} in Matic tokens
45
- * when users stakes.
46
- * This function needs to be called before calling delegate function so that staking
47
- * can properly work
48
- * This also partially address the front running attack on ERC20 approve function:
49
- * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/f959d7e4e6ee0b022b41e5b644c79369869d8411/contracts/token/ERC20/ERC20.sol#L165-L206
50
- * @param amount Matic tokens to be approved for StakeManager to withdraw (polygon currency)
51
- */
52
- approveStakeManager = (amount) => {
53
- return this.buildTxData(
54
- this.polygonContract,
55
- 'increaseAllowance',
56
- this.polygonContract.address,
57
- amount.toBaseString()
46
+ getWithdrawalDelay = async () => {
47
+ const withdrawalDelay = await this.callReadFunctionContract(
48
+ this.stakingManagerContract,
49
+ 'withdrawalDelay'
50
+ )
51
+ return toBN(withdrawalDelay)
52
+ }
53
+
54
+ getMinRewardsToWithdraw = async () => {
55
+ const minRewardsToWithdraw = await this.callReadFunctionContract(
56
+ this.validatorShareContract,
57
+ 'minAmount'
58
58
  )
59
+ return polygon.currency.baseUnit(minRewardsToWithdraw)
59
60
  }
60
61
 
61
62
  /**
@@ -85,10 +86,10 @@ export class MaticStaking {
85
86
  _nonce
86
87
  )
87
88
 
88
- const [withdrawEpoch, shares] = splitIn32BytesArray(unboundInfo)
89
+ const [shares, withdrawEpoch] = splitIn32BytesArray(unboundInfo)
89
90
  return {
90
- withdrawEpoch: toBN(withdrawEpoch, 16),
91
- shares: toBN(shares, 16),
91
+ withdrawEpoch: toBN(withdrawEpoch),
92
+ shares: toBN(shares),
92
93
  }
93
94
  }
94
95
 
@@ -125,6 +126,33 @@ export class MaticStaking {
125
126
  return polygon.currency.baseUnit(toBN(amount).toString())
126
127
  }
127
128
 
129
+ getWithdrawExchangeRate = async () => {
130
+ const withdrawExchangeRate = await this.callReadFunctionContract(
131
+ this.validatorShareContract,
132
+ 'withdrawExchangeRate'
133
+ )
134
+
135
+ return toBN(withdrawExchangeRate)
136
+ }
137
+
138
+ /**
139
+ * Approves StakeManager contract for withdrawing {amount} in Matic tokens
140
+ * when users stakes.
141
+ * This function needs to be called before calling delegate function so that staking
142
+ * can properly work
143
+ * This also partially address the front running attack on ERC20 approve function:
144
+ * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/f959d7e4e6ee0b022b41e5b644c79369869d8411/contracts/token/ERC20/ERC20.sol#L165-L206
145
+ * @param amount Matic tokens to be approved for StakeManager to withdraw (polygon currency)
146
+ */
147
+ approveStakeManager = (amount) => {
148
+ return this.buildTxData(
149
+ this.polygonContract,
150
+ 'increaseAllowance',
151
+ this.stakingManagerContract.address,
152
+ amount.toBaseString()
153
+ )
154
+ }
155
+
128
156
  restakeReward = () => {
129
157
  return this.buildTxData(this.validatorShareContract, 'restake')
130
158
  }
@@ -134,7 +162,7 @@ export class MaticStaking {
134
162
  }
135
163
 
136
164
  delegate = ({ amount }) => {
137
- return this.buildTxData(this.validatorShareContract, 'buyVoucher', amount.toBaseString(), 0)
165
+ return this.buildTxData(this.validatorShareContract, 'buyVoucher', amount.toBaseString(), '0')
138
166
  }
139
167
 
140
168
  undelegate = ({ amount, maximumSharesToBurn }) => {
@@ -148,10 +176,10 @@ export class MaticStaking {
148
176
  }
149
177
 
150
178
  /**
151
- * @param {number} nonce the unbond nonce from where delegator claim its staked tokens
179
+ * @param {number} unbondNonce the unbond nonce from where delegator claim its staked tokens
152
180
  */
153
- claimStake = ({ nonce }) => {
154
- return this.buildTxData(this.validatorShareContract, 'unstakeClaimTokens_new', nonce)
181
+ claimUndelegatedBalance = ({ unbondNonce }) => {
182
+ return this.buildTxData(this.validatorShareContract, 'unstakeClaimTokens_new', unbondNonce)
155
183
  }
156
184
  }
157
185
 
@@ -0,0 +1,67 @@
1
+
2
+ ## Staking in Polygon (MATIC)
3
+
4
+ ## How it works?
5
+ Polygon Staking happens in the **Ethereum network**, it is implemented by a set of smart contracts deployed on the ETH mainnet.
6
+ Staking is made by delegating the `ERC20 MATIC` token to those smart contracts which handle the `(un)staking/rewards` process and it shouldn't be confused with the Native asset in **Polygon network** (`MATIC NATIVE`).
7
+
8
+ Stakers are divided into `validators`, `delegators`, and watchers (for fraud reporting).
9
+
10
+ ## Contracts
11
+
12
+ ### StakeManager contract
13
+ `StakeManager` is the main contract for handling validator related activities like checkPoint signature verification, reward distribution, and stake management. Since the contract is using NFT ID as a source of ownership, change of ownership and signer won't affect anything in the system. [see](https://wiki.polygon.technology/docs/pos/contracts/stakingmanager).
14
+
15
+ ### ValidatorShare contract
16
+ For delegation staking each validator has its own deployed **contract**, this contract has the logic to `stake/unstake` as delegators, but it also acts as an `ERC20`, this `ERC20` token is what we know as the shares token. Shares token are calculated based on the total amount staked in the contract, varying from time to time
17
+ When delegators stake matic, they call `buyVoucher()` , the contract receives the MATIC tokens to stake (approval is needed on Matic token contract) and it calculates and mints the number of token shares that correspond to that staked amount. [see](https://wiki.polygon.technology/docs/pos/contracts/delegation).
18
+
19
+ ### Staking Anatomy
20
+ Example taken from the docs:
21
+
22
+ *Polygon supports delegation via validator shares. By using this design, it is easier to distribute rewards and slash with scale (thousands of delegators) on Ethereum contracts without much computation.
23
+ Delegators delegate by purchasing shares of a finite pool from validators. Each validator will have their own validator share token. Let's call these fungible tokens `VATIC` for a validator `A`. As soon as a user delegates to a validator `A`, they will be issued `VATIC` based on an exchange rate of `MATIC/VATIC` pair. As users accrue value the exchange rate indicates that they can now withdraw more `MATIC` for each `VATIC` and when users get slashed, users withdraw less `MATIC` for their `VATIC`.
24
+ Note that `MATIC` is a staking token. A delegator needs to have `MATIC` tokens to participate in the delegation.
25
+ Initially, a delegator `D` buys tokens from validator `A` specific pool when `1 MATIC per 1 VATIC`.
26
+ When a validator gets rewarded with more `MATIC` tokens, new tokens are added to the pool. Let's say with the current pool of `100 MATIC` tokens, `10 MATIC` rewards are added to the pool. But since the total supply of `VATIC` tokens didn't change due to rewards, the exchange rate becomes `1 MATIC per 0.9 VATIC`. Now, delegator `D` gets more `MATIC` for the same shares.
27
+ `VATIC`: Validator specific minted validator share tokens (ERC20 tokens)*
28
+
29
+ #### Rewards
30
+ Delegators can do with their rewards the following:
31
+ withdraw via `withdrawRewards()` or
32
+ `restake` (earned rewards are put as stake in the contract via `restake()`)
33
+
34
+ #### Unstaking
35
+ For delegators to unstake, there are two steps:
36
+ 1. `sellVoucher_new()`
37
+ 2. `unstakeClaimTokens()`
38
+
39
+ **Note**: there are some methods in the validator share contract with the suffix `_new`, for instance:
40
+ `sellVoucher()` and `sellVoucher_new()` this is because the recent changes on the smart contract to support the new exit API (**unstake** and **claim** tokens)*
41
+
42
+ **sellVoucher** method calculates the token shares that correspond to the staked MATIC at that time, and burns those share tokens, it also transfers the rewards, and makes changes in the contract to update the total stake held in the contract .
43
+ Basically it prepares the contract to let delegators withdraw their staked MATIC in a second step once the **withdrawal delay** it's ben fulfilled.
44
+
45
+ #### Unstake Claim Tokens
46
+ **unstakeClaimTokens** makes the actual withdraw of the staked tokens, sellVoucher does not transfer the staked MATIC back to the delegator, we need to call this function after the withdrawal delay has been fulfilled, so that delegators can get their stake amount back to their wallet.
47
+
48
+
49
+ ### Staking Bussines Rules
50
+
51
+ All of these rules can be queried from the smart contracts, except `minimum amount to stake`, this is defined by Exodus.
52
+
53
+ - **Minimum rewards to withdraw**: 1 MATIC (contract rule)
54
+ - **Minimum amount to stake**: 1 MATIC (exodus rule)
55
+ - **Withdrawal delay**: The amount of time delegators must wait before claiming their staked amount. Varies depending on the contract governance
56
+ - **Withdrawal exchange rate**: The exchange rate used to convert tokens to shares and vice-versa. Varies depending on the number of MATIC in the withdraw pool share (affected by the earned rewards).
57
+ - **Unstaking period**: immediately, but staked MATIC tokens are not available to be withdrawn before withdrawal delay
58
+ - **Claim unstaked tokens**: after 3-4 days has passed since unstaked was called, the unstaked tokens can be claimed by the delegator.
59
+
60
+
61
+ Useful resources:
62
+
63
+ [Polygon docs](https://wiki.polygon.technology/docs/pos/polygon-architecture/)
64
+ [Polygon Staking](https://wiki.polygon.technology/docs/pos/contracts/delegation)
65
+ [StakeManager contract](https://github.com/maticnetwork/contracts/blob/main/contracts/staking/stakeManager/StakeManager.sol)
66
+ [Validator share contract](https://github.com/maticnetwork/contracts/blob/main/contracts/staking/stakeManager/StakeManager.sol)
67
+