Skip to content
This repository was archived by the owner on May 22, 2023. It is now read-only.

Commit 0b36812

Browse files
committed
Merge remote-tracking branch 'origin/master' into no-beneficiary-withdraw
2 parents 08c2c2e + 62284c7 commit 0b36812

13 files changed

Lines changed: 346 additions & 44 deletions

pkg/chain/gen/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ abi/%.abi: ${solidity_dir}/contracts/%.sol
4242

4343

4444
abi/%.go: abi/%.abi
45-
abigen --abi $< --pkg abi --type $* --out $@
45+
go run github.com/ethereum/go-ethereum/cmd/abigen --abi $< --pkg abi --type $* --out $@
4646

4747
contract/%.go cmd/%.go: abi/%ImplV1.abi abi/%ImplV1.go abi/%.go *.go
4848
go run github.com/keep-network/keep-common/tools/generators/ethereum $< contract/$*.go cmd/$*.go

solidity/contracts/KeepBonding.sol

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pragma solidity 0.5.17;
1616

1717
import "@keep-network/keep-core/contracts/KeepRegistry.sol";
1818
import "@keep-network/keep-core/contracts/TokenStaking.sol";
19+
import "@keep-network/keep-core/contracts/TokenGrant.sol";
20+
import "@keep-network/keep-core/contracts/libraries/RolesLookup.sol";
1921

2022
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
2123

@@ -24,13 +26,17 @@ import "openzeppelin-solidity/contracts/math/SafeMath.sol";
2426
/// @notice Contract holding deposits from keeps' operators.
2527
contract KeepBonding {
2628
using SafeMath for uint256;
29+
using RolesLookup for address payable;
2730

2831
// Registry contract with a list of approved factories (operator contracts).
2932
KeepRegistry internal registry;
3033

3134
// KEEP token staking contract.
3235
TokenStaking internal tokenStaking;
3336

37+
// KEEP token grant contract.
38+
TokenGrant internal tokenGrant;
39+
3440
// Unassigned value in wei deposited by operators.
3541
mapping(address => uint256) public unbondedValue;
3642

@@ -71,10 +77,16 @@ contract KeepBonding {
7177

7278
/// @notice Initializes Keep Bonding contract.
7379
/// @param registryAddress Keep registry contract address.
74-
/// @param tokenStakingAddress KEEP Token staking contract address.
75-
constructor(address registryAddress, address tokenStakingAddress) public {
80+
/// @param tokenStakingAddress KEEP token staking contract address.
81+
/// @param tokenGrantAddress KEEP token grant contract address.
82+
constructor(
83+
address registryAddress,
84+
address tokenStakingAddress,
85+
address tokenGrantAddress
86+
) public {
7687
registry = KeepRegistry(registryAddress);
7788
tokenStaking = TokenStaking(tokenStakingAddress);
89+
tokenGrant = TokenGrant(tokenGrantAddress);
7890
}
7991

8092
/// @notice Add the provided value to operator's pool available for bonding.
@@ -113,34 +125,47 @@ contract KeepBonding {
113125
}
114126

115127
/// @notice Withdraws amount from operator's value available for bonding.
116-
/// Can be called only by the operator or by the stake owner. The value is
117-
/// transferred to the beneficiary associated with the operator.
128+
/// Should not be used by grantee of managed grants. For this case,
129+
/// please use `withdrawAsManagedGrantee`.
130+
///
131+
/// This function can be called only by:
132+
/// - operator,
133+
/// - liquid, staked tokens owner (not a grant),
134+
/// - direct staked tokens grantee (not a managed grant).
135+
///
118136
/// @param amount Value to withdraw in wei.
119137
/// @param operator Address of the operator.
120138
function withdraw(uint256 amount, address operator) public {
121139
require(
122140
msg.sender == operator ||
123-
msg.sender == tokenStaking.ownerOf(operator),
141+
msg.sender.isTokenOwnerForOperator(operator, tokenStaking) ||
142+
msg.sender.isGranteeForOperator(operator, tokenGrant),
124143
"Only operator or the owner is allowed to withdraw bond"
125144
);
126145

127-
require(
128-
unbondedValue[operator] >= amount,
129-
"Insufficient unbonded value"
130-
);
131-
132-
unbondedValue[operator] = unbondedValue[operator].sub(amount);
146+
withdrawBond(amount, operator);
147+
}
133148

134-
address beneficiary = tokenStaking.beneficiaryOf(operator);
149+
/// @notice Withdraws amount from operator's value available for bonding.
150+
/// Can be called only by staked tokens managed grantee.
151+
/// @param amount Value to withdraw in wei.
152+
/// @param operator Address of the operator.
153+
/// @param managedGrant Address of the managed grant contract.
154+
function withdrawAsManagedGrantee(
155+
uint256 amount,
156+
address operator,
157+
address managedGrant
158+
) public {
135159
require(
136-
beneficiary != address(0),
137-
"Beneficiary not defined for the operator"
160+
msg.sender.isManagedGranteeForOperator(
161+
operator,
162+
managedGrant,
163+
tokenGrant
164+
),
165+
"Only grantee is allowed to withdraw bond"
138166
);
139167

140-
(bool success, ) = beneficiary.call.value(amount)("");
141-
require(success, "Transfer failed");
142-
143-
emit UnbondedValueWithdrawn(operator, beneficiary, amount);
168+
withdrawBond(amount, operator);
144169
}
145170

146171
/// @notice Create bond for the given operator, holder, reference and amount.
@@ -338,4 +363,27 @@ contract KeepBonding {
338363
{
339364
return authorizedPools[_operator][_poolAddress];
340365
}
366+
367+
/// @notice Withdraws the provided amount from unbonded value of the
368+
/// provided operator to operator's beneficiary. If there is no enough
369+
/// unbonded value or the transfer failed, function fails.
370+
function withdrawBond(uint256 amount, address operator) internal {
371+
require(
372+
unbondedValue[operator] >= amount,
373+
"Insufficient unbonded value"
374+
);
375+
376+
unbondedValue[operator] = unbondedValue[operator].sub(amount);
377+
378+
address beneficiary = tokenStaking.beneficiaryOf(operator);
379+
require(
380+
beneficiary != address(0),
381+
"Beneficiary not defined for the operator"
382+
);
383+
384+
(bool success, ) = beneficiary.call.value(amount)("");
385+
require(success, "Transfer failed");
386+
387+
emit UnbondedValueWithdrawn(operator, beneficiary, amount);
388+
}
341389
}

solidity/migrations/2_deploy_contracts.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const BondedSortitionPoolFactory = artifacts.require(
1717
let {
1818
RandomBeaconAddress,
1919
TokenStakingAddress,
20+
TokenGrantAddress,
2021
RegistryAddress,
2122
} = require("./external-contracts")
2223

@@ -27,13 +28,21 @@ module.exports = async function (deployer) {
2728
TokenStakingStub = artifacts.require("TokenStakingStub")
2829
TokenStakingAddress = (await TokenStakingStub.new()).address
2930

31+
TokenGrantStub = artifacts.require("TokenGrantStub")
32+
TokenGrantAddress = (await TokenGrantStub.new()).address
33+
3034
RandomBeaconStub = artifacts.require("RandomBeaconStub")
3135
RandomBeaconAddress = (await RandomBeaconStub.new()).address
3236

3337
RegistryAddress = (await deployer.deploy(KeepRegistry)).address
3438
}
3539

36-
await deployer.deploy(KeepBonding, RegistryAddress, TokenStakingAddress)
40+
await deployer.deploy(
41+
KeepBonding,
42+
RegistryAddress,
43+
TokenStakingAddress,
44+
TokenGrantAddress
45+
)
3746

3847
await deployer.deploy(BondedECDSAKeep)
3948

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Addresses of externally deployed smart contracts
22
const RegistryAddress = "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
33
const TokenStakingAddress = "0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
4-
const RandomBeaconAddress = "0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
5-
const TBTCSystemAddress = "0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
4+
const TokenGrantAddress = "0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
5+
const RandomBeaconAddress = "0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
6+
const TBTCSystemAddress = "0xEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
67

78
module.exports = {
89
RegistryAddress,
910
TokenStakingAddress,
11+
TokenGrantAddress,
1012
RandomBeaconAddress,
1113
TBTCSystemAddress,
1214
}

solidity/package-lock.json

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

solidity/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"homepage": "https://github.com/keep-network/keep-ecdsa",
3434
"dependencies": {
35-
"@keep-network/keep-core": "1.1.2",
35+
"@keep-network/keep-core": "1.2.3-pre.0",
3636
"@keep-network/sortition-pools": "1.0.0",
3737
"@openzeppelin/upgrades": "^2.7.2",
3838
"openzeppelin-solidity": "2.3.0",

solidity/scripts/lcl-provision-external-contracts.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ REGISTRY_PROPERTY="RegistryAddress"
1818
TOKEN_STAKING_CONTRACT_DATA="TokenStaking.json"
1919
TOKEN_STAKING_PROPERTY="TokenStakingAddress"
2020

21+
TOKEN_GRANT_CONTRACT_DATA="TokenGrant.json"
22+
TOKEN_GRANT_PROPERTY="TokenGrantAddress"
23+
2124
RANDOM_BEACON_CONTRACT_DATA="KeepRandomBeaconService.json"
2225
RANDOM_BEACON_PROPERTY="RandomBeaconAddress"
2326

@@ -61,6 +64,21 @@ function fetch_token_staking_contract_address() {
6164
fi
6265
}
6366

67+
function fetch_token_grant_contract_address() {
68+
echo "Fetching value for ${TOKEN_GRANT_PROPERTY}..."
69+
70+
local contractDataPath=$(realpath $KEEP_CORE_SOL_ARTIFACTS_PATH/$TOKEN_GRANT_CONTRACT_DATA)
71+
local ADDRESS=$(cat ${contractDataPath} | jq "${JSON_QUERY}" | tr -d '"')
72+
73+
if [[ !($ADDRESS =~ $ADDRESS_REGEXP) ]]; then
74+
echo "Invalid address: ${ADDRESS}"
75+
FAILED=true
76+
else
77+
echo "Found value for ${TOKEN_GRANT_PROPERTY} = ${ADDRESS}"
78+
sed -i -e "/${TOKEN_GRANT_PROPERTY}/s/${SED_SUBSTITUTION_REGEXP}/\"${ADDRESS}\"/" $DESTINATION_FILE
79+
fi
80+
}
81+
6482
function fetch_random_beacon_contract_address() {
6583
echo "Fetching value for ${RANDOM_BEACON_PROPERTY}..."
6684

@@ -78,6 +96,7 @@ function fetch_random_beacon_contract_address() {
7896

7997
fetch_registry_contract_address
8098
fetch_token_staking_contract_address
99+
fetch_token_grant_contract_address
81100
fetch_random_beacon_contract_address
82101

83102
if $FAILED; then

solidity/test/BondedECDSAKeepFactoryTest.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const BondedECDSAKeepFactoryStub = artifacts.require(
1212
)
1313
const KeepBonding = artifacts.require("KeepBonding")
1414
const TokenStakingStub = artifacts.require("TokenStakingStub")
15+
const TokenGrantStub = artifacts.require("TokenGrantStub")
1516
const BondedSortitionPool = artifacts.require("BondedSortitionPool")
1617
const BondedSortitionPoolFactory = artifacts.require(
1718
"BondedSortitionPoolFactory"
@@ -28,6 +29,7 @@ const expect = chai.expect
2829
contract("BondedECDSAKeepFactory", async (accounts) => {
2930
let registry
3031
let tokenStaking
32+
let tokenGrant
3133
let keepFactory
3234
let bondedSortitionPoolFactory
3335
let keepBonding
@@ -1178,9 +1180,11 @@ contract("BondedECDSAKeepFactory", async (accounts) => {
11781180
registry = await KeepRegistry.new()
11791181
bondedSortitionPoolFactory = await BondedSortitionPoolFactory.new()
11801182
tokenStaking = await TokenStakingStub.new()
1183+
tokenGrant = await TokenGrantStub.new()
11811184
keepBonding = await KeepBonding.new(
11821185
registry.address,
1183-
tokenStaking.address
1186+
tokenStaking.address,
1187+
tokenGrant.address
11841188
)
11851189
randomBeacon = accounts[1]
11861190
const bondedECDSAKeepMasterContract = await BondedECDSAKeep.new()
@@ -1477,7 +1481,12 @@ contract("BondedECDSAKeepFactory", async (accounts) => {
14771481
registry = await KeepRegistry.new()
14781482
bondedSortitionPoolFactory = await BondedSortitionPoolFactory.new()
14791483
tokenStaking = await TokenStakingStub.new()
1480-
keepBonding = await KeepBonding.new(registry.address, tokenStaking.address)
1484+
tokenGrant = await TokenGrantStub.new()
1485+
keepBonding = await KeepBonding.new(
1486+
registry.address,
1487+
tokenStaking.address,
1488+
tokenGrant.address
1489+
)
14811490
randomBeacon = await RandomBeaconStub.new()
14821491
const bondedECDSAKeepMasterContract = await BondedECDSAKeep.new()
14831492
keepFactory = await BondedECDSAKeepFactoryStub.new(

solidity/test/BondedECDSAKeepIntegrationTest.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const BondedECDSAKeepFactoryStub = artifacts.require(
1111
)
1212
const KeepBonding = artifacts.require("KeepBonding")
1313
const TokenStaking = artifacts.require("TokenStaking")
14+
const TokenGrant = artifacts.require("TokenGrant")
1415
const BondedSortitionPool = artifacts.require("BondedSortitionPool")
1516
const BondedSortitionPoolFactory = artifacts.require(
1617
"BondedSortitionPoolFactory"
@@ -27,6 +28,7 @@ const expect = chai.expect
2728
contract("BondedECDSAKeepFactory", async (accounts) => {
2829
let keepToken
2930
let tokenStaking
31+
let tokenGrant
3032
let keepFactory
3133
let bondedSortitionPoolFactory
3234
let keepBonding
@@ -245,8 +247,13 @@ contract("BondedECDSAKeepFactory", async (accounts) => {
245247
initializationPeriod,
246248
undelegationPeriod
247249
)
250+
tokenGrant = await TokenGrant.new(keepToken.address)
248251

249-
keepBonding = await KeepBonding.new(registry.address, tokenStaking.address)
252+
keepBonding = await KeepBonding.new(
253+
registry.address,
254+
tokenStaking.address,
255+
tokenGrant.address
256+
)
250257
randomBeacon = await RandomBeaconStub.new()
251258
const bondedECDSAKeepMasterContract = await BondedECDSAKeep.new()
252259
keepFactory = await BondedECDSAKeepFactoryStub.new(

solidity/test/BondedECDSAKeepTest.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const TestToken = artifacts.require("TestToken")
1616
const KeepBonding = artifacts.require("KeepBonding")
1717
const TestEtherReceiver = artifacts.require("TestEtherReceiver")
1818
const TokenStakingStub = artifacts.require("TokenStakingStub")
19+
const TokenGrantStub = artifacts.require("TokenGrantStub")
1920
const BondedECDSAKeepCloneFactory = artifacts.require(
2021
"BondedECDSAKeepCloneFactory"
2122
)
@@ -42,6 +43,7 @@ contract("BondedECDSAKeep", (accounts) => {
4243
let registry
4344
let keepBonding
4445
let tokenStaking
46+
let tokenGrant
4547
let bondedECDSAKeepStubMaster
4648
let keep
4749
let factoryStub
@@ -87,7 +89,12 @@ contract("BondedECDSAKeep", (accounts) => {
8789
before(async () => {
8890
registry = await KeepRegistry.new()
8991
tokenStaking = await TokenStakingStub.new()
90-
keepBonding = await KeepBonding.new(registry.address, tokenStaking.address)
92+
tokenGrant = await TokenGrantStub.new()
93+
keepBonding = await KeepBonding.new(
94+
registry.address,
95+
tokenStaking.address,
96+
tokenGrant.address
97+
)
9198
bondedECDSAKeepStubMaster = await BondedECDSAKeepStub.new()
9299
factoryStub = await BondedECDSAKeepCloneFactory.new(
93100
bondedECDSAKeepStubMaster.address

0 commit comments

Comments
 (0)