文件 1 的 1:DODODspProxy.sol
pragma solidity 0.6.9;
interface IDODOApprove {
function claimTokens(address token,address who,address dest,uint256 amount) external;
function getDODOProxy() external view returns (address);
}
contract InitializableOwnable {
address public _OWNER_;
address public _NEW_OWNER_;
bool internal _INITIALIZED_;
event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
modifier notInitialized() {
require(!_INITIALIZED_, "DODO_INITIALIZED");
_;
}
modifier onlyOwner() {
require(msg.sender == _OWNER_, "NOT_OWNER");
_;
}
function initOwner(address newOwner) public notInitialized {
_INITIALIZED_ = true;
_OWNER_ = newOwner;
}
function transferOwnership(address newOwner) public onlyOwner {
emit OwnershipTransferPrepared(_OWNER_, newOwner);
_NEW_OWNER_ = newOwner;
}
function claimOwnership() public {
require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM");
emit OwnershipTransferred(_OWNER_, _NEW_OWNER_);
_OWNER_ = _NEW_OWNER_;
_NEW_OWNER_ = address(0);
}
}
interface IDODOApproveProxy {
function isAllowedProxy(address _proxy) external view returns (bool);
function claimTokens(address token,address who,address dest,uint256 amount) external;
}
contract DODOApproveProxy is InitializableOwnable {
uint256 private constant _TIMELOCK_DURATION_ = 3 days;
mapping (address => bool) public _IS_ALLOWED_PROXY_;
uint256 public _TIMELOCK_;
address public _PENDING_ADD_DODO_PROXY_;
address public immutable _DODO_APPROVE_;
modifier notLocked() {
require(
_TIMELOCK_ <= block.timestamp,
"SetProxy is timelocked"
);
_;
}
constructor(address dodoApporve) public {
_DODO_APPROVE_ = dodoApporve;
}
function init(address owner, address[] memory proxies) external {
initOwner(owner);
for(uint i = 0; i < proxies.length; i++)
_IS_ALLOWED_PROXY_[proxies[i]] = true;
}
function unlockAddProxy(address newDodoProxy) public onlyOwner {
_TIMELOCK_ = block.timestamp + _TIMELOCK_DURATION_;
_PENDING_ADD_DODO_PROXY_ = newDodoProxy;
}
function lockAddProxy() public onlyOwner {
_PENDING_ADD_DODO_PROXY_ = address(0);
_TIMELOCK_ = 0;
}
function addDODOProxy() external onlyOwner notLocked() {
_IS_ALLOWED_PROXY_[_PENDING_ADD_DODO_PROXY_] = true;
lockAddProxy();
}
function removeDODOProxy (address oldDodoProxy) public onlyOwner {
_IS_ALLOWED_PROXY_[oldDodoProxy] = false;
}
function claimTokens(
address token,
address who,
address dest,
uint256 amount
) external {
require(_IS_ALLOWED_PROXY_[msg.sender], "DODOApproveProxy:Access restricted");
IDODOApprove(_DODO_APPROVE_).claimTokens(
token,
who,
dest,
amount
);
}
function isAllowedProxy(address _proxy) external view returns (bool) {
return _IS_ALLOWED_PROXY_[_proxy];
}
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
}
interface IWETH {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "MUL_ERROR");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "DIVIDING_ERROR");
return a / b;
}
function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 quotient = div(a, b);
uint256 remainder = a - quotient * b;
if (remainder > 0) {
return quotient + 1;
} else {
return quotient;
}
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SUB_ERROR");
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "ADD_ERROR");
return c;
}
function sqrt(uint256 x) internal pure returns (uint256 y) {
uint256 z = x / 2 + 1;
y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
}
}
library SafeERC20 {
using SafeMath for uint256;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
library DecimalMath {
using SafeMath for uint256;
uint256 internal constant ONE = 10**18;
uint256 internal constant ONE2 = 10**36;
function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d) / (10**18);
}
function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(d).divCeil(10**18);
}
function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(10**18).div(d);
}
function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
return target.mul(10**18).divCeil(d);
}
function reciprocalFloor(uint256 target) internal pure returns (uint256) {
return uint256(10**36).div(target);
}
function reciprocalCeil(uint256 target) internal pure returns (uint256) {
return uint256(10**36).divCeil(target);
}
function powFloor(uint256 target, uint256 e) internal pure returns (uint256) {
if (e == 0) {
return 10 ** 18;
} else if (e == 1) {
return target;
} else {
uint p = powFloor(target, e.div(2));
p = p.mul(p) / (10**18);
if (e % 2 == 1) {
p = p.mul(target) / (10**18);
}
return p;
}
}
}
contract ReentrancyGuard {
bool private _ENTERED_;
modifier preventReentrant() {
require(!_ENTERED_, "REENTRANT");
_ENTERED_ = true;
_;
_ENTERED_ = false;
}
}
interface IDSP {
function init(
address maintainer,
address baseTokenAddress,
address quoteTokenAddress,
uint256 lpFeeRate,
address mtFeeRateModel,
uint256 i,
uint256 k,
bool isOpenTWAP
) external;
function _BASE_TOKEN_() external view returns (address);
function _QUOTE_TOKEN_() external view returns (address);
function _I_() external view returns (uint256);
function _MT_FEE_RATE_MODEL_() external view returns (address);
function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve);
function sellBase(address to) external returns (uint256);
function sellQuote(address to) external returns (uint256);
function buyShares(address to) external returns (uint256,uint256,uint256);
}
interface ICloneFactory {
function clone(address prototype) external returns (address proxy);
}
contract CloneFactory is ICloneFactory {
function clone(address prototype) external override returns (address proxy) {
bytes20 targetBytes = bytes20(prototype);
assembly {
let clone := mload(0x40)
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone, 0x14), targetBytes)
mstore(
add(clone, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
proxy := create(0, clone, 0x37)
}
return proxy;
}
}
interface IDSPFactory {
function createDODOStablePool(
address baseToken,
address quoteToken,
uint256 lpFeeRate,
uint256 i,
uint256 k,
bool isOpenTWAP
) external returns (address newStablePool);
}
contract DSPFactory is InitializableOwnable {
address public immutable _CLONE_FACTORY_;
address public immutable _DEFAULT_MT_FEE_RATE_MODEL_;
address public _DEFAULT_MAINTAINER_;
address public _DSP_TEMPLATE_;
mapping(address => mapping(address => address[])) public _REGISTRY_;
mapping(address => address[]) public _USER_REGISTRY_;
event NewDSP(address baseToken, address quoteToken, address creator, address DSP);
event RemoveDSP(address DSP);
constructor(
address cloneFactory,
address DSPTemplate,
address defaultMaintainer,
address defaultMtFeeRateModel
) public {
_CLONE_FACTORY_ = cloneFactory;
_DSP_TEMPLATE_ = DSPTemplate;
_DEFAULT_MAINTAINER_ = defaultMaintainer;
_DEFAULT_MT_FEE_RATE_MODEL_ = defaultMtFeeRateModel;
}
function createDODOStablePool(
address baseToken,
address quoteToken,
uint256 lpFeeRate,
uint256 i,
uint256 k,
bool isOpenTWAP
) external returns (address newStablePool) {
newStablePool = ICloneFactory(_CLONE_FACTORY_).clone(_DSP_TEMPLATE_);
{
IDSP(newStablePool).init(
_DEFAULT_MAINTAINER_,
baseToken,
quoteToken,
lpFeeRate,
_DEFAULT_MT_FEE_RATE_MODEL_,
i,
k,
isOpenTWAP
);
}
_REGISTRY_[baseToken][quoteToken].push(newStablePool);
_USER_REGISTRY_[tx.origin].push(newStablePool);
emit NewDSP(baseToken, quoteToken, tx.origin, newStablePool);
}
function updateDSPTemplate(address _newDSPTemplate) external onlyOwner {
_DSP_TEMPLATE_ = _newDSPTemplate;
}
function updateDefaultMaintainer(address _newMaintainer) external onlyOwner {
_DEFAULT_MAINTAINER_ = _newMaintainer;
}
function addPoolByAdmin(
address creator,
address baseToken,
address quoteToken,
address pool
) external onlyOwner {
_REGISTRY_[baseToken][quoteToken].push(pool);
_USER_REGISTRY_[creator].push(pool);
emit NewDSP(baseToken, quoteToken, creator, pool);
}
function removePoolByAdmin(
address creator,
address baseToken,
address quoteToken,
address pool
) external onlyOwner {
address[] memory registryList = _REGISTRY_[baseToken][quoteToken];
for (uint256 i = 0; i < registryList.length; i++) {
if (registryList[i] == pool) {
registryList[i] = registryList[registryList.length - 1];
break;
}
}
_REGISTRY_[baseToken][quoteToken] = registryList;
_REGISTRY_[baseToken][quoteToken].pop();
address[] memory userRegistryList = _USER_REGISTRY_[creator];
for (uint256 i = 0; i < userRegistryList.length; i++) {
if (userRegistryList[i] == pool) {
userRegistryList[i] = userRegistryList[userRegistryList.length - 1];
break;
}
}
_USER_REGISTRY_[creator] = userRegistryList;
_USER_REGISTRY_[creator].pop();
emit RemoveDSP(pool);
}
function getDODOPool(address baseToken, address quoteToken)
external
view
returns (address[] memory machines)
{
return _REGISTRY_[baseToken][quoteToken];
}
function getDODOPoolBidirection(address token0, address token1)
external
view
returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines)
{
return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]);
}
function getDODOPoolByUser(address user) external view returns (address[] memory machines) {
return _USER_REGISTRY_[user];
}
}
interface IGSP {
function init(
address maintainer,
address admin,
address baseTokenAddress,
address quoteTokenAddress,
uint256 lpFeeRate,
uint256 mtFeeRate,
uint256 i,
uint256 k,
uint256 priceLimit,
bool isOpenTWAP
) external;
function _BASE_TOKEN_() external view returns (address);
function _QUOTE_TOKEN_() external view returns (address);
function _I_() external view returns (uint256);
function _MT_FEE_RATE_MODEL_() external view returns (address);
function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve);
function getUserFeeRate(address user) external view returns (uint256 lpFeeRate, uint256 mtFeeRate);
function getMtFeeTotal() external view returns (uint256 mtFeeBase, uint256 mtFeeQuote);
function sellBase(address to) external returns (uint256);
function sellQuote(address to) external returns (uint256);
function buyShares(address to) external returns (uint256 shares, uint256 baseInput, uint256 quoteInput);
function sellShares(uint256 shareAmount, address to, uint256 baseMinAmount, uint256 quoteMinAmount, bytes calldata data, uint256 deadline) external returns (uint256 baseAmount, uint256 quoteAmount);
}
interface IGSPFactory {
function createDODOGasSavingPool(
address admin,
address baseToken,
address quoteToken,
uint256 lpFeeRate,
uint256 mtFeeRate,
uint256 i,
uint256 k,
uint256 priceLimit,
bool isOpenTWAP
) external returns (address newGasSavingPool);
}
contract GSPFactory is InitializableOwnable {
address public immutable _CLONE_FACTORY_;
address public _DEFAULT_MAINTAINER_;
address public _GSP_TEMPLATE_;
mapping(address => mapping(address => address[])) public _REGISTRY_;
mapping(address => address[]) public _USER_REGISTRY_;
event NewGSP(address baseToken, address quoteToken, address creator, address GSP);
event RemoveGSP(address GSP);
constructor(
address cloneFactory,
address GSPTemplate,
address defaultMaintainer
) public {
_CLONE_FACTORY_ = cloneFactory;
_GSP_TEMPLATE_ = GSPTemplate;
_DEFAULT_MAINTAINER_ = defaultMaintainer;
}
function createDODOGasSavingPool(
address admin,
address baseToken,
address quoteToken,
uint256 lpFeeRate,
uint256 mtFeeRate,
uint256 i,
uint256 k,
uint256 priceLimit,
bool isOpenTWAP
) external returns (address newGasSavingPool) {
newGasSavingPool = ICloneFactory(_CLONE_FACTORY_).clone(_GSP_TEMPLATE_);
{
IGSP(newGasSavingPool).init(
_DEFAULT_MAINTAINER_,
admin,
baseToken,
quoteToken,
lpFeeRate,
mtFeeRate,
i,
k,
priceLimit,
isOpenTWAP
);
}
_REGISTRY_[baseToken][quoteToken].push(newGasSavingPool);
_USER_REGISTRY_[tx.origin].push(newGasSavingPool);
emit NewGSP(baseToken, quoteToken, tx.origin, newGasSavingPool);
}
function updateGSPTemplate(address _newGSPTemplate) external onlyOwner {
_GSP_TEMPLATE_ = _newGSPTemplate;
}
function updateDefaultMaintainer(address _newMaintainer) external onlyOwner {
_DEFAULT_MAINTAINER_ = _newMaintainer;
}
function addPoolByAdmin(
address creator,
address baseToken,
address quoteToken,
address pool
) external onlyOwner {
_REGISTRY_[baseToken][quoteToken].push(pool);
_USER_REGISTRY_[creator].push(pool);
emit NewGSP(baseToken, quoteToken, creator, pool);
}
function removePoolByAdmin(
address creator,
address baseToken,
address quoteToken,
address pool
) external onlyOwner {
address[] memory registryList = _REGISTRY_[baseToken][quoteToken];
for (uint256 i = 0; i < registryList.length; i++) {
if (registryList[i] == pool) {
registryList[i] = registryList[registryList.length - 1];
break;
}
}
_REGISTRY_[baseToken][quoteToken] = registryList;
_REGISTRY_[baseToken][quoteToken].pop();
address[] memory userRegistryList = _USER_REGISTRY_[creator];
for (uint256 i = 0; i < userRegistryList.length; i++) {
if (userRegistryList[i] == pool) {
userRegistryList[i] = userRegistryList[userRegistryList.length - 1];
break;
}
}
_USER_REGISTRY_[creator] = userRegistryList;
_USER_REGISTRY_[creator].pop();
emit RemoveGSP(pool);
}
function getDODOPool(address baseToken, address quoteToken)
external
view
returns (address[] memory machines)
{
return _REGISTRY_[baseToken][quoteToken];
}
function getDODOPoolBidirection(address token0, address token1)
external
view
returns (address[] memory baseToken0Machines, address[] memory baseToken1Machines)
{
return (_REGISTRY_[token0][token1], _REGISTRY_[token1][token0]);
}
function getDODOPoolByUser(address user) external view returns (address[] memory machines) {
return _USER_REGISTRY_[user];
}
}
contract DODODspProxy is ReentrancyGuard {
using SafeMath for uint256;
address constant _ETH_ADDRESS_ = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public immutable _WETH_;
address public immutable _DODO_APPROVE_PROXY_;
address public immutable _DSP_FACTORY_;
address public immutable _GSP_FACTORY_;
modifier judgeExpired(uint256 deadLine) {
require(deadLine >= block.timestamp, "DODODspProxy: EXPIRED");
_;
}
fallback() external payable {}
receive() external payable {}
constructor(
address dspFactory,
address gspFactory,
address payable weth,
address dodoApproveProxy
) public {
_DSP_FACTORY_ = dspFactory;
_GSP_FACTORY_ = gspFactory;
_WETH_ = weth;
_DODO_APPROVE_PROXY_ = dodoApproveProxy;
}
function createDODOGasSavingPair(
address admin,
address baseToken,
address quoteToken,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 lpFeeRate,
uint256 mtFeeRate,
uint256 i,
uint256 k,
uint256 priceLimit,
uint256 deadLine
)
external
payable
preventReentrant
judgeExpired(deadLine)
returns (address newGasSavingPair, uint256 shares)
{
{
address _admin = admin;
address _baseToken = baseToken == _ETH_ADDRESS_ ? _WETH_ : baseToken;
address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
uint256 _lpFeeRate = lpFeeRate;
uint256 _mtFeeRate = mtFeeRate;
uint256 _i = i;
uint256 _k = k;
uint256 _priceLimit = priceLimit;
newGasSavingPair = IGSPFactory(_GSP_FACTORY_).createDODOGasSavingPool(
_admin,
_baseToken,
_quoteToken,
_lpFeeRate,
_mtFeeRate,
_i,
_k,
_priceLimit,
false
);
}
{
address _baseToken = baseToken;
address _quoteToken = quoteToken;
uint256 _baseInAmount = baseInAmount;
uint256 _quoteInAmount = quoteInAmount;
_deposit(
msg.sender,
newGasSavingPair,
_baseToken,
_baseInAmount,
_baseToken == _ETH_ADDRESS_
);
_deposit(
msg.sender,
newGasSavingPair,
_quoteToken,
_quoteInAmount,
_quoteToken == _ETH_ADDRESS_
);
}
(shares, , ) = IGSP(newGasSavingPair).buyShares(msg.sender);
}
function createDODOStablePair(
address baseToken,
address quoteToken,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 lpFeeRate,
uint256 i,
uint256 k,
bool isOpenTWAP,
uint256 deadLine
)
external
payable
preventReentrant
judgeExpired(deadLine)
returns (address newDODOStablePair, uint256 shares)
{
{
address _baseToken = baseToken == _ETH_ADDRESS_ ? _WETH_ : baseToken;
address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
newDODOStablePair = IDSPFactory(_DSP_FACTORY_).createDODOStablePool(
_baseToken,
_quoteToken,
lpFeeRate,
i,
k,
isOpenTWAP
);
}
{
address _baseToken = baseToken;
address _quoteToken = quoteToken;
_deposit(
msg.sender,
newDODOStablePair,
_baseToken,
baseInAmount,
_baseToken == _ETH_ADDRESS_
);
_deposit(
msg.sender,
newDODOStablePair,
_quoteToken,
quoteInAmount,
_quoteToken == _ETH_ADDRESS_
);
}
(shares, , ) = IDSP(newDODOStablePair).buyShares(msg.sender);
}
function addDSPLiquidity(
address dspAddress,
uint256 baseInAmount,
uint256 quoteInAmount,
uint256 baseMinAmount,
uint256 quoteMinAmount,
uint8 flag,
uint256 deadLine
)
external
payable
preventReentrant
judgeExpired(deadLine)
returns (
uint256 shares,
uint256 baseAdjustedInAmount,
uint256 quoteAdjustedInAmount
)
{
address _dsp = dspAddress;
(baseAdjustedInAmount, quoteAdjustedInAmount) = _addDSPLiquidity(
_dsp,
baseInAmount,
quoteInAmount
);
require(
baseAdjustedInAmount >= baseMinAmount && quoteAdjustedInAmount >= quoteMinAmount,
"DODODspProxy: deposit amount is not enough"
);
_deposit(msg.sender, _dsp, IDSP(_dsp)._BASE_TOKEN_(), baseAdjustedInAmount, flag == 1);
_deposit(msg.sender, _dsp, IDSP(_dsp)._QUOTE_TOKEN_(), quoteAdjustedInAmount, flag == 2);
(shares, , ) = IDSP(_dsp).buyShares(msg.sender);
if (flag == 1 && msg.value > baseAdjustedInAmount) msg.sender.transfer(msg.value - baseAdjustedInAmount);
if (flag == 2 && msg.value > quoteAdjustedInAmount) msg.sender.transfer(msg.value - quoteAdjustedInAmount);
}
function _addDSPLiquidity(
address dspAddress,
uint256 baseInAmount,
uint256 quoteInAmount
) internal view returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount) {
(uint256 baseReserve, uint256 quoteReserve) = IDSP(dspAddress).getVaultReserve();
if (quoteReserve == 0 && baseReserve == 0) {
uint256 i = IDSP(dspAddress)._I_();
uint256 shares = quoteInAmount < DecimalMath.mulFloor(baseInAmount, i)
? DecimalMath.divFloor(quoteInAmount, i)
: baseInAmount;
baseAdjustedInAmount = shares;
quoteAdjustedInAmount = DecimalMath.mulFloor(shares, i);
}
if (quoteReserve > 0 && baseReserve > 0) {
uint256 baseIncreaseRatio = DecimalMath.divFloor(baseInAmount, baseReserve);
uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteInAmount, quoteReserve);
if (baseIncreaseRatio <= quoteIncreaseRatio) {
baseAdjustedInAmount = baseInAmount;
quoteAdjustedInAmount = DecimalMath.mulFloor(quoteReserve, baseIncreaseRatio);
} else {
quoteAdjustedInAmount = quoteInAmount;
baseAdjustedInAmount = DecimalMath.mulFloor(baseReserve, quoteIncreaseRatio);
}
}
}
function _deposit(
address from,
address to,
address token,
uint256 amount,
bool isETH
) internal {
if (isETH) {
if (amount > 0) {
IWETH(_WETH_).deposit{value: amount}();
if (to != address(this)) SafeERC20.safeTransfer(IERC20(_WETH_), to, amount);
}
} else {
IDODOApproveProxy(_DODO_APPROVE_PROXY_).claimTokens(token, from, to, amount);
}
}
}