diff --git a/abi/StakingV2.json b/abi/StakingV2.json index 1fd8268f..aab204f0 100644 --- a/abi/StakingV2.json +++ b/abi/StakingV2.json @@ -383,6 +383,55 @@ "name": "StakeIncreased", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint72", + "name": "identityId", + "type": "uint72" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "nodeId", + "type": "bytes" + }, + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "oldStake", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "newStake", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "sharesMintedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalSupply", + "type": "uint256" + } + ], + "name": "StakeWithdrawalCanceled", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -521,6 +570,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint72", + "name": "identityId", + "type": "uint72" + } + ], + "name": "cancelStakeWithdrawal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/contracts/v2/Staking.sol b/contracts/v2/Staking.sol index 0e7b95d1..1be62211 100644 --- a/contracts/v2/Staking.sol +++ b/contracts/v2/Staking.sol @@ -56,6 +56,15 @@ contract StakingV2 is Named, Versioned, ContractStatusV2, Initializable { uint256 withdrawalPeriodEnd ); event StakeWithdrawn(uint72 indexed identityId, bytes nodeId, address indexed staker, uint96 withdrawnStakeAmount); + event StakeWithdrawalCanceled( + uint72 indexed identityId, + bytes nodeId, + address indexed staker, + uint96 oldStake, + uint96 newStake, + uint256 sharesMintedAmount, + uint256 newTotalSupply + ); event InactiveStakeWithdrawn( uint72 indexed identityId, bytes nodeId, @@ -79,7 +88,7 @@ contract StakingV2 is Named, Versioned, ContractStatusV2, Initializable { event OperatorFeeChangeFinished(uint72 indexed identityId, bytes nodeId, uint8 operatorFee); string private constant _NAME = "Staking"; - string private constant _VERSION = "2.1.1"; + string private constant _VERSION = "2.2.0"; ShardingTableV2 public shardingTableContract; IdentityStorageV2 public identityStorage; @@ -268,6 +277,7 @@ contract StakingV2 is Named, Versioned, ContractStatusV2, Initializable { if (!ps.profileExists(identityId)) { revert ProfileErrors.ProfileDoesntExist(identityId); } + StakingStorage ss = stakingStorage; uint96 stakeWithdrawalAmount; @@ -287,6 +297,61 @@ contract StakingV2 is Named, Versioned, ContractStatusV2, Initializable { emit StakeWithdrawn(identityId, ps.getNodeId(identityId), msg.sender, stakeWithdrawalAmount); } + function cancelStakeWithdrawal(uint72 identityId) external { + ProfileStorage ps = profileStorage; + + if (!ps.profileExists(identityId)) { + revert ProfileErrors.ProfileDoesntExist(identityId); + } + + StakingStorage ss = stakingStorage; + + uint96 stakeWithdrawalAmount; + uint256 withdrawalTimestamp; + (stakeWithdrawalAmount, withdrawalTimestamp) = ss.withdrawalRequests(identityId, msg.sender); + + if (stakeWithdrawalAmount == 0) { + revert StakingErrors.WithdrawalWasntInitiated(); + } + + uint96 oldStake = ss.totalStakes(identityId); + uint96 newStake = oldStake + stakeWithdrawalAmount; + + Shares sharesContract = Shares(ps.getSharesContractAddress(identityId)); + + uint256 sharesMinted; + if (sharesContract.totalSupply() == 0) { + sharesMinted = stakeWithdrawalAmount; + } else { + sharesMinted = ((uint256(stakeWithdrawalAmount) * sharesContract.totalSupply()) / oldStake); + } + sharesContract.mint(msg.sender, sharesMinted); + + ss.deleteWithdrawalRequest(identityId, msg.sender); + ss.setTotalStake(identityId, newStake); + + ShardingTableStorageV2 sts = shardingTableStorage; + ParametersStorage params = parametersStorage; + + if (!sts.nodeExists(identityId) && newStake >= params.minimumStake()) { + if (sts.nodesCount() >= params.shardingTableSizeLimit()) { + revert ShardingTableErrors.ShardingTableIsFull(); + } + shardingTableContract.insertNode(identityId); + } + emit StakeWithdrawalCanceled( + identityId, + ps.getNodeId(identityId), + msg.sender, + oldStake, + newStake, + sharesMinted, + sharesContract.totalSupply() + ); + emit StakeIncreased(identityId, ps.getNodeId(identityId), msg.sender, oldStake, newStake); + emit SharesMinted(identityId, address(sharesContract), msg.sender, sharesMinted, sharesContract.totalSupply()); + } + function addReward(bytes32 agreementId, uint72 identityId, uint96 rewardAmount) external onlyContracts { ServiceAgreementStorageProxy sasProxy = serviceAgreementStorageProxy; NodeOperatorFeesStorage nofs = nodeOperatorFeesStorage; diff --git a/deployments/base_mainnet_contracts.json b/deployments/base_mainnet_contracts.json index 9ae96b83..30a80dc0 100644 --- a/deployments/base_mainnet_contracts.json +++ b/deployments/base_mainnet_contracts.json @@ -239,12 +239,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0x174FD3a9dbC2562F2360C9797d7dbF21f3bD6824", - "version": "2.1.1", - "gitBranch": "feature/base", - "gitCommitHash": "d3eab3d1a0fde48db522b16b49654558eed07dc3", - "deploymentBlock": 16310726, - "deploymentTimestamp": 1719410803582, + "evmAddress": "0x39713a4E7d05dAB796fCA6e84cBA5aFC905822d9", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 19022524, + "deploymentTimestamp": 1724834405325, "deployed": true }, "Profile": { diff --git a/deployments/base_sepolia_dev_contracts.json b/deployments/base_sepolia_dev_contracts.json index ad1fa6c9..aa1ff096 100644 --- a/deployments/base_sepolia_dev_contracts.json +++ b/deployments/base_sepolia_dev_contracts.json @@ -239,12 +239,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0xd4847eF7c0BF7d223a33339DA4f4194DC1DC7f8c", - "version": "2.1.1", - "gitBranch": "feature/base", - "gitCommitHash": "49543b7f02d9543b4c744dc8b8153921cf178ad9", - "deploymentBlock": 11509099, - "deploymentTimestamp": 1718786489842, + "evmAddress": "0x1E9BaA5b1c0003385f1C27d8175D59974c10A0dA", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 14543288, + "deploymentTimestamp": 1724854871142, "deployed": true }, "Profile": { diff --git a/deployments/base_sepolia_test_contracts.json b/deployments/base_sepolia_test_contracts.json index d460a92f..28301283 100644 --- a/deployments/base_sepolia_test_contracts.json +++ b/deployments/base_sepolia_test_contracts.json @@ -239,12 +239,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0x6d206b6834fE82811C3c659e7a6A6deeB076fe0B", - "version": "2.1.1", - "gitBranch": "feature/base", - "gitCommitHash": "49543b7f02d9543b4c744dc8b8153921cf178ad9", - "deploymentBlock": 11510539, - "deploymentTimestamp": 1718789370362, + "evmAddress": "0x1dD6bE1EC9410aff2E95685d84cEA6aCf40bFBa9", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 14543315, + "deploymentTimestamp": 1724854925334, "deployed": true }, "Profile": { diff --git a/deployments/gnosis_chiado_dev_contracts.json b/deployments/gnosis_chiado_dev_contracts.json index be7029be..6863fe13 100644 --- a/deployments/gnosis_chiado_dev_contracts.json +++ b/deployments/gnosis_chiado_dev_contracts.json @@ -265,12 +265,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0x140CA29bca7e9449f50021E051c8EE3187b48e4D", - "version": "2.1.1", - "gitBranch": "deployment/4.3.0", - "gitCommitHash": "7bd7fcbc9d5e8bfa5eb47573d57b0958515aca00", - "deploymentBlock": 10291472, - "deploymentTimestamp": 1718285932780, + "evmAddress": "0x4991C23D82469e1b9b583515Ed400e5B0437d499", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 11519675, + "deploymentTimestamp": 1724854757920, "deployed": true }, "ParanetsRegistry": { diff --git a/deployments/gnosis_chiado_test_contracts.json b/deployments/gnosis_chiado_test_contracts.json index d5606b13..961b5f40 100644 --- a/deployments/gnosis_chiado_test_contracts.json +++ b/deployments/gnosis_chiado_test_contracts.json @@ -256,12 +256,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0x878686d27ab7611D6cCA884Ad715B543F35b467a", - "version": "2.1.1", - "gitBranch": "deployment/4.3.0", - "gitCommitHash": "7bd7fcbc9d5e8bfa5eb47573d57b0958515aca00", - "deploymentBlock": 10291479, - "deploymentTimestamp": 1718285965963, + "evmAddress": "0xe4ce91C83B018B6E1e5a117eD899F35E502400E0", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 11519686, + "deploymentTimestamp": 1724854815721, "deployed": true }, "ContentAsset": { diff --git a/deployments/gnosis_mainnet_contracts.json b/deployments/gnosis_mainnet_contracts.json index 02c9d7c3..0691dca4 100644 --- a/deployments/gnosis_mainnet_contracts.json +++ b/deployments/gnosis_mainnet_contracts.json @@ -201,12 +201,12 @@ "deployed": true }, "Staking": { - "evmAddress": "0xAfFBc5E2833192aD3E28AE586aBA2c704aE76775", - "version": "2.1.1", - "gitBranch": "deployment/4.3.0", - "gitCommitHash": "7bd7fcbc9d5e8bfa5eb47573d57b0958515aca00", - "deploymentBlock": 34443978, - "deploymentTimestamp": 1718286039986, + "evmAddress": "0x8883aA8cd98fCf6D9203b731F843Fe9eed09E3bb", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 35708723, + "deploymentTimestamp": 1724834659300, "deployed": true }, "Profile": { diff --git a/deployments/otp_alphanet_contracts.json b/deployments/otp_alphanet_contracts.json deleted file mode 100644 index 91030221..00000000 --- a/deployments/otp_alphanet_contracts.json +++ /dev/null @@ -1,232 +0,0 @@ -{ - "contracts": { - "Assertion": { - "deployed": true, - "deploymentTimestamp": 1701161138695, - "evmAddress": "0xb1b3D0D35168B8f73607Aa710e9c39108B74CfdB", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczwnKf6pUawe178252ySopfKCRCcSxGNSjFDKTGSeoH", - "version": "1.0.1" - }, - "AssertionStorage": { - "deployed": true, - "evmAddress": "0x0009af84E5FB00D143f18b78dd0C0d7AA7b9ba2D", - "substrateAddress": "5EMjsczLBZzVAwGtTrUbzzN6ZSgWQRx7x52tRNTLP3Dceefh" - }, - "CommitManagerV1": { - "deployed": true, - "deploymentTimestamp": 1701161283820, - "evmAddress": "0x34dCCCB135288F4b50Ebf10B7eE685Dc260C2432", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczWmUiJUsKU5nXAbyPdzyay8oBwKxQjArWAjLoE5pku", - "version": "1.0.1" - }, - "CommitManagerV1U1": { - "deployed": true, - "deploymentTimestamp": 1701161328342, - "evmAddress": "0xbc1475eF01d4713fFdFec7e3040c1D1D32ecD7F1", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczyrvg6tMheBhqmEdzLCDqzcC7Uoxp5CgGZbuADBD6x", - "version": "1.0.1" - }, - "ContentAsset": { - "deployed": true, - "deploymentTimestamp": 1701161413096, - "evmAddress": "0x75F59329709AF9f0c02057B73bfFfE8C9c89C37D", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczjp1WfFxYCn9HM4KNYit9ZSB8CCWxuWNqroHLnVrFH", - "version": "1.0.2" - }, - "ContentAssetStorage": { - "deployed": true, - "evmAddress": "0x240f3dD7a221611E9d67399AeADcc650Cdbd1F39", - "substrateAddress": "5EMjsczTQCbVhq79Wn5oWogDueq5SVjQcMYVLUVG2ZSRVDMp" - }, - "HashingProxy": { - "deployed": true, - "deploymentTimestamp": 1701160993265, - "evmAddress": "0x6f0799Ef88e8Aed132fc7bf93Ab3660D694A7980", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjscziRUbK2mWhFto8fsps5sikhA93GZEBTBBEe5Ay53V7", - "version": "1.0.1" - }, - "Hub": { - "deployed": true, - "evmAddress": "0x7585a99C5C150a08f5CDeFD16465C6De8D41EbbD", - "substrateAddress": "5EMjsczjivqukkFgd9GAzHPdSJ9zwUuUDe2jPZXKi7CShqJo" - }, - "HubController": { - "deployed": true, - "deploymentTimestamp": 1701160908647, - "evmAddress": "0x33d4b36d4F53dE6d2eF52BCDbb97d85946B3d9Ec", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczWZVLKn7YN5kx7kxRonLTwpEjUSavvh9VcYUKXzTVG", - "version": "1.0.1" - }, - "Identity": { - "deployed": true, - "deploymentTimestamp": 1701161162888, - "evmAddress": "0x9EdA0E5Ff78d3B379a834bCdB2E95768954C6fe8", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczt1FJZcfh9XJCxWRtSj5Z3VneLy8qVZ5iBQy8VCDPB", - "version": "1.0.1" - }, - "IdentityStorage": { - "deployed": true, - "evmAddress": "0x37cDE763a46C3bc01472E837F5F6347b65DE1AdC", - "substrateAddress": "5EMjsczXMff3DRs5p19xJ5voP2Dieh2qFdT6Wdau2XwN4Aur" - }, - "Log2PLDSF": { - "deployed": true, - "deploymentTimestamp": 1701161078009, - "evmAddress": "0x2Ab691f5c086Af9CF609e0466ee7E8ae5222a17c", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczUjXWG6dXfcGwRmY8ZqMypQEMQ6qDXVESPceonqCwF", - "version": null - }, - "ParametersStorage": { - "deployed": true, - "deploymentTimestamp": 1701160968992, - "evmAddress": "0xa1bBaA53E2d26278775Cf749db6Df09561CE1af4", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjscztajSxX1kjpUDQRDZmU2PrCtcX3boGjG95JMmG29UH", - "variables": { - "epochLength": 3600, - "finalizationCommitsNumber": 3, - "updateCommitWindowDuration": 600 - }, - "version": "1.1.0" - }, - "Profile": { - "deployed": true, - "deploymentTimestamp": 1701161247595, - "evmAddress": "0x8aBACB9beb344da39F0e545ff5be956D146b8104", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczoyPtvbUm1WbApToDZyqnkhc8oDhGRvD5bHhYjM4Uy", - "version": "1.0.2" - }, - "ProfileStorage": { - "deployed": true, - "evmAddress": "0x8D71144642d8CdEcD255d193C5ea0dA4F56A2e81", - "substrateAddress": "5EMjsczpWuxsCSdk2JDcYQhzfZqjJXivRvnj4rw8vGhA7HwE" - }, - "ProofManagerV1": { - "deployed": true, - "deploymentTimestamp": 1701161308102, - "evmAddress": "0x9559c365E8A179d5bbB4aFEd1fc587cF04cEd460", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczr6q1cWmu6TL8VH2Jennj5SpkVdkXUBa4aB325FmCw", - "version": "1.0.2" - }, - "ProofManagerV1U1": { - "deployed": true, - "deploymentTimestamp": 1701161364550, - "evmAddress": "0xE313A51068BF7667DBCE0b03959fFdDECe8aDE56", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsd17g8faLHw8u5zeNVC2NbjdNSiEYzXfFWsHhrarWbRf", - "version": "1.0.2" - }, - "SHA256": { - "deployed": true, - "deploymentTimestamp": 1701161029478, - "evmAddress": "0x67a82c63109586EcFCDC3c4e94BA4Cf334C75e50", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczgwnwiMqHkeVfKMSdE7wSXncZYdKU56sw8TKSmHzQr", - "version": null - }, - "ScoringProxy": { - "deployed": true, - "deploymentTimestamp": 1701161053765, - "evmAddress": "0x49ABECCaB698afA00fE4343C5eaD6D1a2E201771", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczawKBCRSRuzi1tBzciLvHmft2N9CDhn6aVLX4XF6eS", - "version": "1.0.1" - }, - "ServiceAgreementStorageProxy": { - "deployed": true, - "deploymentTimestamp": 1701161114430, - "evmAddress": "0x21b6dBbF3f5B4Bf141b9d07C9D360c2D82c7Fb52", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczSvwmeRrS3HfByAqiVa12jgUAtfs9k4dvZbyoc7ZR8", - "version": "1.0.0" - }, - "ServiceAgreementStorageV1": { - "deployed": true, - "evmAddress": "0x5954b83291826C0ebB03a94CE6927bb745141683", - "substrateAddress": "5EMjscze5JSUK1TZJagwQzuSMcpkq6832kSHq7d9TQHABd5T" - }, - "ServiceAgreementStorageV1U1": { - "deployed": true, - "evmAddress": "0xFF66d03205333D6cd149A329126431113428701b", - "substrateAddress": "5EMjsd1DMKBmsKoMbdqxii1eJBooqcJk6KMt2tvByP5KiXPn" - }, - "ServiceAgreementV1": { - "deployed": true, - "deploymentTimestamp": 1701161388854, - "evmAddress": "0xaba1128732FF3F92Da99B7F8Cdf7DDF6d9D419C9", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczvZjycTAaWXv5BHPk2NRX2vd1B4yFp1uDUq6uY2zkD", - "version": "1.1.1" - }, - "ShardingTable": { - "deployed": true, - "deploymentTimestamp": 1701161199136, - "evmAddress": "0x1351cB2dF744Bf62B7566E460909f470A9e209Da", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjsczQ3etxDzcJ5szpVutvMtaQjWsYmDpuNRxFG5a1eRbC", - "version": "1.0.1" - }, - "ShardingTableStorage": { - "deployed": true, - "evmAddress": "0xC7d93274f9f39216B467d07c4Cd9eacb2cD66467", - "substrateAddress": "5EMjsd12DhHoq96MassSx3nQFJZQMmrdNr8DuaxRVQtKVsCv" - }, - "Staking": { - "deployed": true, - "deploymentTimestamp": 1701161223380, - "evmAddress": "0x711E24c3268ac2EFA8cbdC2036ffFA9D0e60cdbD", - "gitBranch": "HEAD", - "gitCommitHash": "3802f13679a0cffa79f90b131cb00098ce6e0445", - "substrateAddress": "5EMjscziqk4ETnNrwR6JkNbrkXiQdtTEqxSwmHr4RMVy9uJG", - "version": "1.0.2" - }, - "StakingStorage": { - "deployed": true, - "evmAddress": "0xd7d3751BcDd744897Aa479AB1d24BC79c118Fc09", - "substrateAddress": "5EMjsd15RP4BFSQJBueMPYXsiERjhJufgXsaJT9h3mqXBe6G" - }, - "Token": { - "deployed": true, - "evmAddress": "0x010ad2D4530cA5099b37F79d517375Ca931A4E12", - "substrateAddress": "5EMjsczLPF3Sv1rz1Z5MLbaEnZmHAUtk1SeyJWtrExnYfbsS" - }, - "UnfinalizedStateStorage": { - "deployed": true, - "evmAddress": "0x44e3B5115F176bCC994b0B9bF56fb90350017F7E", - "substrateAddress": "5EMjsczZyjn7um7rWM3ZzBRWid1zrzz5w3Y5Zy2bx4F57TwP" - }, - "WhitelistStorage": { - "deployed": true, - "evmAddress": "0x85ca25DE0b15839927410a7117051f67c480aA83", - "substrateAddress": "5EMjscznyz3bRzqCSrbQa7DwwCzaa6amztJof9SJkGyJ7WYn" - } - }, - "deployedTimestamp": 1689862777764 -} diff --git a/deployments/otp_devnet_contracts.json b/deployments/otp_devnet_contracts.json index 93e0a1b1..b7135ab0 100644 --- a/deployments/otp_devnet_contracts.json +++ b/deployments/otp_devnet_contracts.json @@ -225,7 +225,7 @@ "gitCommitHash": "9e741344a4d2382c53bdd9da7e0f3ca84442cbab", "deploymentBlock": 4807396, "deploymentTimestamp": 1718108768208, - "deployed": true + "deployed": false }, "CommitManagerV1": { "evmAddress": "0x75460bb0af6da440F946a8c685543EF6Ed9441d9", diff --git a/deployments/otp_mainnet_contracts.json b/deployments/otp_mainnet_contracts.json index f9f6b2be..b3fbeea1 100644 --- a/deployments/otp_mainnet_contracts.json +++ b/deployments/otp_mainnet_contracts.json @@ -207,13 +207,13 @@ "deployed": true }, "Staking": { - "evmAddress": "0x618A89c38268F724271da7F96B139da2A9b619a6", - "substrateAddress": "5EMjsczfiiaryx3tW4j9PSpJbRwUfArRmAUCGNSNNb3bnZU2", - "version": "2.1.1", - "gitBranch": "deployment/4.3.0", - "gitCommitHash": "7bd7fcbc9d5e8bfa5eb47573d57b0958515aca00", - "deploymentBlock": 5134298, - "deploymentTimestamp": 1718285457235, + "evmAddress": "0x666B604B1b32ca467a6eEF3257475D32f8ADD04b", + "substrateAddress": "5EMjsczghQorAAxG77BAa4V9YSAkJ8TfGRJsvaARzTNHdDgn", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 5672930, + "deploymentTimestamp": 1724834500366, "deployed": true }, "CommitManagerV1": { diff --git a/deployments/otp_testnet_contracts.json b/deployments/otp_testnet_contracts.json index 70a72569..290c012d 100644 --- a/deployments/otp_testnet_contracts.json +++ b/deployments/otp_testnet_contracts.json @@ -216,13 +216,13 @@ "deployed": true }, "Staking": { - "evmAddress": "0xFB109Ae84be5AECBbeEb4B92259FD82E80d9Da80", - "substrateAddress": "5EMjsd1CUuyisawNmNnfxA9FZ4FHmvmLdivyKqjoJU9AFieG", - "version": "2.1.1", - "gitBranch": "improvement/paranet-registration-separation", - "gitCommitHash": "61d5b7c39b1ccd839ab7eb1067b007ab70b08227", - "deploymentBlock": 4092122, - "deploymentTimestamp": 1718192323530, + "evmAddress": "0x873d2Ac030ba5cb14184E6Af3152fcfF7555b432", + "substrateAddress": "5EMjsczoGpwyeX7YPDeYFej1RGnqi8CeW6b6Vw5xA4P6pN3k", + "version": "2.2.0", + "gitBranch": "main", + "gitCommitHash": "b9e7dede2a75acf193272f84b1a5ce155210e47a", + "deploymentBlock": 4354638, + "deploymentTimestamp": 1724854704943, "deployed": true }, "CommitManagerV1": { diff --git a/package-lock.json b/package-lock.json index fac7876c..c9e7603f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "license": "Apache-2.0", "dependencies": { "@openzeppelin/contracts": "^4.9.3", diff --git a/package.json b/package.json index 4ad864c4..1446c74d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dkg-evm-module", - "version": "4.3.3", + "version": "4.3.4", "description": "Smart contracts for OriginTrail V6", "main": "index.ts", "files": [ diff --git a/test/v2/unit/StakingV2.test.ts b/test/v2/unit/StakingV2.test.ts index 2ffb2a34..fc9430cf 100644 --- a/test/v2/unit/StakingV2.test.ts +++ b/test/v2/unit/StakingV2.test.ts @@ -130,8 +130,8 @@ describe('@v2 @unit StakingV2 contract', function () { expect(await StakingV2.name()).to.equal('Staking'); }); - it('The contract is version "2.1.1"', async () => { - expect(await StakingV2.version()).to.equal('2.1.1'); + it('The contract is version "2.2.0"', async () => { + expect(await StakingV2.version()).to.equal('2.2.0'); }); it('Non-Contract should not be able to setTotalStake; expect to fail', async () => { @@ -701,4 +701,100 @@ describe('@v2 @unit StakingV2 contract', function () { expect(finalBalance.sub(initialBalance)).to.be.equal(0); }); + + it('should correctly cancel a withdrawal and re-mint shares', async function () { + const initialStake = hre.ethers.utils.parseEther('1000'); + const { identityId, nodeId } = await createProfile(accounts[0], accounts[1]); + + await Token.approve(StakingV2.address, initialStake); + await StakingV2['addStake(uint72,uint96)'](identityId, initialStake); + + const sharesToBurn = hre.ethers.utils.parseEther('500'); + + const sharesAddress = await ProfileStorage.getSharesContractAddress(identityId); + const SharesContract = await hre.ethers.getContractAt('Shares', sharesAddress); + + await SharesContract.increaseAllowance(StakingV2.address, sharesToBurn); + await StakingV2.startStakeWithdrawal(identityId, sharesToBurn); + + const tx = await StakingV2.cancelStakeWithdrawal(identityId); + await expect(tx) + .to.emit(StakingV2, 'StakeWithdrawalCanceled') + .withArgs( + identityId, + nodeId, + accounts[0].address, + initialStake.sub(sharesToBurn), + initialStake, + sharesToBurn, + initialStake, + ); + + const newStake = await StakingStorage.totalStakes(identityId); + expect(newStake).to.equal(initialStake); + + const withdrawalRequestExists = await StakingStorage.withdrawalRequestExists(identityId, accounts[0].address); + expect(withdrawalRequestExists).to.eql(false); + }); + + it('should revert if there is no withdrawal request', async function () { + const { identityId } = await createProfile(accounts[0], accounts[1]); + + await expect(StakingV2.cancelStakeWithdrawal(identityId)).to.be.revertedWithCustomError( + StakingV2, + 'WithdrawalWasntInitiated', + ); + }); + + it('should handle recalculation of shares when additional reward added during a pending withdrawal', async () => { + const { identityId, nodeId } = await createProfile(accounts[0], accounts[1]); + + const initialStakeAmount = hre.ethers.utils.parseEther('500'); + const reward = hre.ethers.utils.parseEther('250'); + + await Token.approve(StakingV2.address, initialStakeAmount); + await StakingV2['addStake(uint72,uint96)'](identityId, initialStakeAmount); + + const sharesToBurn = initialStakeAmount.div(2); + + const sharesAddress = await ProfileStorage.getSharesContractAddress(identityId); + const SharesContract = await hre.ethers.getContractAt('Shares', sharesAddress); + + await SharesContract.connect(accounts[0]).increaseAllowance(StakingV2.address, sharesToBurn); + await StakingV2.startStakeWithdrawal(identityId, sharesToBurn); + + await Token.mint(ServiceAgreementStorageV1U1.address, hre.ethers.utils.parseEther(`${2_000_000}`)); + const agreementId = '0x' + randomBytes(32).toString('hex'); + const startTime = Math.floor(Date.now() / 1000).toString(); + const epochsNumber = 5; + const epochLength = 10; + const tokenAmount = hre.ethers.utils.parseEther('100'); + const scoreFunctionId = 0; + const proofWindowOffsetPerc = 10; + + await ServiceAgreementStorageV1U1.createServiceAgreementObject( + agreementId, + startTime, + epochsNumber, + epochLength, + tokenAmount, + scoreFunctionId, + proofWindowOffsetPerc, + ); + + await StakingV2.addReward(agreementId, identityId, reward); + + const tx = await StakingV2.cancelStakeWithdrawal(identityId); + await expect(tx) + .to.emit(StakingV2, 'StakeWithdrawalCanceled') + .withArgs( + identityId, + nodeId, + accounts[0].address, + initialStakeAmount.sub(sharesToBurn).add(reward), + initialStakeAmount.add(reward), + hre.ethers.utils.parseEther('125'), + hre.ethers.utils.parseEther('375'), + ); + }); });