mirror of
https://github.com/status-im/ens-usernames.git
synced 2025-02-22 23:28:11 +00:00
option to prevent front running of username slashing
This commit is contained in:
parent
a99de3333e
commit
a8ec75cc04
@ -20,7 +20,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
|
||||
|
||||
uint256 public constant releaseDelay = 365 days;
|
||||
mapping (bytes32 => Account) public accounts;
|
||||
|
||||
mapping (bytes32 => address) reservedSlashers;
|
||||
|
||||
//Slashing conditions
|
||||
uint256 public usernameMinLength;
|
||||
bytes32 public reservedUsernamesMerkleRoot;
|
||||
@ -175,7 +176,15 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
|
||||
accounts[_label].owner = msg.sender;
|
||||
emit UsernameOwner(namehash, msg.sender);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice secretly reserve the slashing reward to `msg.sender`
|
||||
* @param _secret keccak256(abi.encodePacked(namehash, owner, creationTime))
|
||||
*/
|
||||
function reserveSlash(bytes32 _secret) external {
|
||||
reservedSlashers[_secret] = msg.sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Slash username smaller then `usernameMinLength`.
|
||||
* @param _username Raw value of offending username.
|
||||
@ -469,6 +478,23 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice returns address that reserved slashing of an account
|
||||
* @param _label Username hash.
|
||||
* @return Exact time when username can be released.
|
||||
**/
|
||||
function getReservedSlasher(bytes32 _label)
|
||||
external
|
||||
view
|
||||
returns(address reservedSlasher)
|
||||
{
|
||||
bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label));
|
||||
uint256 creationTime = accounts[_label].creationTime;
|
||||
address owner = ensRegistry.owner(namehash);
|
||||
bytes32 secret = keccak256(abi.encodePacked(namehash, owner, creationTime));
|
||||
reservedSlasher = reservedSlashers[secret];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Support for "approveAndCall". Callable only by `token()`.
|
||||
* @param _from Who approved.
|
||||
@ -613,14 +639,16 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
|
||||
bytes32 label = keccak256(_username);
|
||||
bytes32 namehash = keccak256(abi.encodePacked(ensNode, label));
|
||||
uint256 amountToTransfer;
|
||||
if(accounts[label].creationTime == 0) {
|
||||
uint256 creationTime = accounts[label].creationTime;
|
||||
address owner = ensRegistry.owner(namehash);
|
||||
if(creationTime == 0) {
|
||||
require(
|
||||
ensRegistry.owner(namehash) != address(0) ||
|
||||
owner != address(0) ||
|
||||
ensRegistry.resolver(namehash) != address(0),
|
||||
"Nothing to slash."
|
||||
);
|
||||
} else {
|
||||
assert(accounts[label].creationTime != block.timestamp);
|
||||
assert(creationTime != block.timestamp);
|
||||
amountToTransfer = accounts[label].balance;
|
||||
delete accounts[label];
|
||||
}
|
||||
@ -631,7 +659,14 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
|
||||
|
||||
if (amountToTransfer > 0) {
|
||||
reserveAmount -= amountToTransfer;
|
||||
require(token.transfer(msg.sender, amountToTransfer), "Error in transfer.");
|
||||
address receiver = msg.sender;
|
||||
bytes32 secret = keccak256(abi.encodePacked(namehash, owner, creationTime));
|
||||
address reservedSlasher = reservedSlashers[secret];
|
||||
if (reservedSlasher != address(0)) {
|
||||
delete reservedSlashers[secret];
|
||||
receiver = reservedSlasher;
|
||||
}
|
||||
require(token.transfer(receiver, amountToTransfer), "Error in transfer.");
|
||||
}
|
||||
emit UsernameOwner(namehash, address(0));
|
||||
}
|
||||
|
@ -871,6 +871,37 @@ contract('UsernameRegistrar', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('reserveSlash()', function() {
|
||||
it('should send funds to reserver', async() =>{
|
||||
const username = 'c';
|
||||
const label = web3Utils.sha3(username);
|
||||
const usernameHash = namehash.hash(username + '.' + registry.registry);
|
||||
const registrant = accountsArr[1];
|
||||
const slashReserver = accountsArr[2];
|
||||
const slashCaller = accountsArr[3];
|
||||
await TestToken.methods.mint(registry.price).send({from: registrant});
|
||||
await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant});
|
||||
await UsernameRegistrar.methods.register(
|
||||
web3Utils.sha3(username),
|
||||
utils.zeroAddress,
|
||||
utils.zeroBytes32,
|
||||
utils.zeroBytes32
|
||||
).send({from: registrant});
|
||||
await utils.increaseTime(20000)
|
||||
assert.equal(await ens.methods.owner(usernameHash).call(), registrant);
|
||||
const initialSlasherBalance = await TestToken.methods.balanceOf(slashReserver).call();
|
||||
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
|
||||
const secret = web3Utils.soliditySha3(usernameHash, registrant, creationTime);
|
||||
assert.equal(await UsernameRegistrar.methods.getReservedSlasher(label).call(), utils.zeroAddress);
|
||||
await UsernameRegistrar.methods.reserveSlash(secret).send({from: slashReserver});
|
||||
assert.equal(await UsernameRegistrar.methods.getReservedSlasher(label).call(), slashReserver);
|
||||
await UsernameRegistrar.methods.slashSmallUsername(username).send({from: slashCaller})
|
||||
//TODO: check events
|
||||
assert.equal(await TestToken.methods.balanceOf(slashReserver).call(), (+initialSlasherBalance)+(+registry.price));
|
||||
assert.equal(await ens.methods.owner(usernameHash).call(), utils.zeroAddress);
|
||||
});
|
||||
});
|
||||
|
||||
describe('moveRegistry()', function() {
|
||||
it('should move registry to new registry and migrate', async () => {
|
||||
const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send();
|
||||
|
Loading…
x
Reference in New Issue
Block a user