Skip to content

Instantly share code, notes, and snippets.

@k06a
Created August 17, 2018 21:51
Show Gist options
  • Save k06a/600a58b7c9434da0c37558c42d022b73 to your computer and use it in GitHub Desktop.
Save k06a/600a58b7c9434da0c37558c42d022b73 to your computer and use it in GitHub Desktop.
TypoToken
pragma solidity ^0.4.24;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import "./TypoLib.sol";
contract ERC20TypoToken is StandardToken, TypoLib {
mapping (address => mapping (address => uint256)) internal sent_;
constructor(uint256 _maxAllowedTypos) public TypoLib(_maxAllowedTypos) {
}
function transfer(address _to, uint256 _value) public returns (bool) {
sent_[msg.sender][_to] = sent_[msg.sender][_to].add(_value);
return super.transfer(_to, _value);
}
function reclaimByReceiver(address _wrong, bytes32 _actions) public {
address good = fixAddress(_wrong, _actions);
require(!isContract(good) && good == msg.sender);
uint256 balance = balances[_wrong];
require(balance > 0);
balances[_wrong] = 0;
balances[msg.sender] = balances[msg.sender].add(balance);
emit Transfer(_wrong, msg.sender, balance);
}
function reclaimBySender(address _contract, address _wrong, bytes32 _actions) public {
address good = fixAddress(_wrong, _actions);
require(isContract(good) && good == _contract);
uint256 balance = sent_[msg.sender][_wrong];
require(balance > 0);
sent_[msg.sender][_wrong] = 0;
balances[_wrong] = balances[_wrong].sub(balance);
balances[msg.sender] = balances[msg.sender].add(balance);
emit Transfer(_wrong, msg.sender, balance);
}
}
pragma solidity ^0.4.24;
contract TypoLib {
uint256 public maxAllowedTypos_;
constructor(uint256 _maxAllowedTypos) public {
require(_maxAllowedTypos <= 5);
maxAllowedTypos_ = _maxAllowedTypos;
}
function isContract(address addr) public view returns (bool) {
uint size;
assembly { size := extcodesize(addr) }
return size > 0;
}
function fixAddress(address _wrong, bytes32 _actions) public view returns (address) {
uint256 fullMask = uint256(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF);
uint256 result = uint256(_wrong);
for (uint i = 0; i < maxAllowedTypos_ * 3 && _actions[i] != 0; i += 3) {
byte actionType = _actions[i];
uint256 position = uint256(_actions[i + 1]);
uint256 value = uint256(_actions[i + 2]);
require(position < 40); // 40 hex symbols
require(value < 16); // value should fit in 4 bits (1 hex char)
uint mask;
uint maskLow;
uint maskHigh;
if (actionType == 1) { // replace byte
mask = fullMask ^ (0x0F << (position * 4));
result = (result & mask) | (value << (position * 4));
} else
if (actionType == 2) { // delete byte
maskLow = (1 << (position * 4)) - 1;
maskHigh = fullMask ^ (maskLow << 4) ^ 0x0f;
result = ((result & maskHigh) >> 4) | (result & maskLow);
} else
if (actionType == 3) { // insert byte
maskLow = (1 << (position * 4)) - 1;
maskHigh = fullMask ^ maskLow;
result = ((result & maskHigh) << 4) | (value << (position * 4)) | (result & maskLow);
} else {
revert();
}
}
address fixedAddress = address(result & fullMask);
require(_wrong != fixedAddress);
return address(fixedAddress);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment