-
Notifications
You must be signed in to change notification settings - Fork 6
Airdrop Contract #49
Airdrop Contract #49
Changes from 7 commits
5315d1e
93c1933
4b9d49f
2cea8c7
ab90149
33342ef
69c1a03
870649c
7059b15
d45e084
340baa4
69c7bbb
380c39c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/* solhint-disable-next-line compiler-fixed */ | ||
pragma solidity ^0.4.17; | ||
|
||
// Copyright 2018 OpenST Ltd. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// ---------------------------------------------------------------------------- | ||
// Utility chain: Airdrop | ||
// | ||
// http://www.simpletoken.org/ | ||
// | ||
// ---------------------------------------------------------------------------- | ||
|
||
import "./Workers.sol"; | ||
import "./Pricer.sol"; | ||
|
||
|
||
contract Airdrop is Pricer, Workers { | ||
|
||
/* | ||
* Events | ||
*/ | ||
/// Event for AirdropPayment complete | ||
event AirdropPayment( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. up to three arguments can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indexing is cool. Does indexing cost extra gas or it's neglegible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also for formatting on events we've previously filled the line (different from function signatures) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @benjaminbollen: for consistency/ease, we started declaring events similar to functions,
This way it not subject to personal preference in terms of how many is too many arguments to list on the line. We can go back to the other way, if preferred, but that will mean changes in other rule for max number of arguments per line (so that how it looks in an individual dev's editor is not driving the decision). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the event |
||
address _beneficiary, | ||
uint256 tokenAmount, | ||
address _commissionBeneficiary, | ||
uint256 commissionTokenAmount, | ||
uint256 _actualPricePoint, | ||
address _spender, | ||
uint256 _airdropAmount | ||
); | ||
|
||
/* | ||
* Storage | ||
*/ | ||
Workers public workers; | ||
address public airdropBudgetHolder; | ||
|
||
/* | ||
* Constructor | ||
*/ | ||
/// @dev Takes _brandedToken, _baseCurrency, _workers, _airdropBudgetHolder; | ||
/// constructor; | ||
/// public method; | ||
/// @param _brandedToken Branded Token | ||
/// @param _baseCurrency Base Currency | ||
/// @param _workers Workers contract address | ||
/// @param _airdropBudgetHolder Airdrop Budget Holder Address | ||
function Airdrop( | ||
address _brandedToken, | ||
bytes3 _baseCurrency, | ||
Workers _workers, | ||
address _airdropBudgetHolder) | ||
public | ||
Pricer(_brandedToken, _baseCurrency) | ||
OpsManaged() | ||
{ | ||
require(_workers != address(0)); | ||
require(airdropBudgetHolder != address(0)); | ||
|
||
workers = _workers; | ||
airdropBudgetHolder = _airdropBudgetHolder; | ||
} | ||
|
||
/* | ||
* External functions | ||
*/ | ||
/// clean up or revoke airdrop contract | ||
function remove() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should the remove function not be implemented in |
||
external | ||
onlyAdminOrOps | ||
{ | ||
selfdestruct(msg.sender); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an event before self-destruct is useful There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding event "Removed" |
||
} | ||
|
||
/* | ||
* External functions | ||
*/ | ||
/// performPay matches the behaviour of Pricer:pay with extra functionality of airdrop evaluation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. payAirdrop on Airdrop; and pay on pricer; |
||
/// @param _beneficiary beneficiary | ||
/// @param _transferAmount transferAmount | ||
/// @param _commissionBeneficiary commissionBeneficiary | ||
/// @param _commissionAmount commissionAmount | ||
/// @param _currency currency | ||
/// @param _intendedPricePoint intendedPricePoint | ||
/// @param _spender spender | ||
/// @param _airdropAmount airdropAmount | ||
/// @return uint256 totalPaid | ||
function performPay( | ||
address _beneficiary, | ||
uint256 _transferAmount, | ||
address _commissionBeneficiary, | ||
uint256 _commissionAmount, | ||
bytes3 _currency, | ||
uint256 _intendedPricePoint, | ||
address _spender, | ||
uint256 _airdropAmount) | ||
public | ||
returns ( | ||
uint256 /* totalPaid */) | ||
{ | ||
require(workers.isWorker(msg.sender)); | ||
require(_spender != address(0)); | ||
|
||
require(isValidBeneficiaryData(_beneficiary, _transferAmount, _commissionBeneficiary, _commissionAmount)); | ||
|
||
uint256 tokenAmount = _transferAmount; | ||
uint256 commissionTokenAmount = _commissionAmount; | ||
uint256 pricePoint = _intendedPricePoint; | ||
|
||
// check Margin And Calculate BTAmount | ||
if (_currency != "") { | ||
(pricePoint, tokenAmount, commissionTokenAmount) = validateMarginAndCalculateBTAmount(_currency, | ||
_intendedPricePoint, _transferAmount, _commissionAmount); | ||
} | ||
|
||
require(performAirdropTransferToSpender(_spender, _airdropAmount, | ||
tokenAmount, commissionTokenAmount)); | ||
require(performTransfer(_spender, _beneficiary, tokenAmount, | ||
_commissionBeneficiary, commissionTokenAmount)); | ||
|
||
/// Emit AirdropPayment Event | ||
AirdropPayment(_beneficiary, tokenAmount, _commissionBeneficiary, | ||
commissionTokenAmount, pricePoint, _spender, _airdropAmount); | ||
|
||
return ((tokenAmount + commissionTokenAmount)); | ||
} | ||
|
||
/* | ||
* Private functions | ||
*/ | ||
/// @dev Takes _spender, _airdropAmount, _tokenAmount, _commissionTokenAmount; | ||
/// Calculate airdropUsed to transfer | ||
/// Perform perform Airdrop Transfer To Spender | ||
/// internal method; | ||
/// @param _spender spenderUser | ||
/// @param _airdropAmount airdropAmount | ||
/// @param _tokenAmount tokenAmount | ||
/// @param _commissionTokenAmount commissionTokenAmount | ||
/// @return uint256 airdropUsed | ||
function performAirdropTransferToSpender( | ||
address _spender, | ||
uint256 _airdropAmount, | ||
uint256 _tokenAmount, | ||
uint256 _commissionTokenAmount) | ||
private | ||
returns ( | ||
bool /* boolean value */) | ||
{ | ||
// @Ben Do we need this? Can't we transfer all _airdropAmount to _spender? | ||
uint256 airdropUsed = _airdropAmount; | ||
uint256 totalPaid = (_tokenAmount + _commissionTokenAmount); | ||
if (_airdropAmount > totalPaid) { | ||
airdropUsed = _airdropAmount - totalPaid; | ||
} | ||
|
||
// Prefund the user from the airdrop budget holder | ||
if (airdropUsed > 0) { | ||
require(EIP20Interface(brandedToken()).transferFrom(airdropBudgetHolder, _spender, airdropUsed)); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
/* solhint-disable-next-line compiler-fixed */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. on L34: Pricer is not PricerInterface; the dependency direction is reversed; pricer calls on contracts, for now other contracts dont call on pricer; neither is there anything general about pricer worthy of generalising in an interface There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as we concluded we will keep PricerInterface.sol |
||
pragma solidity ^0.4.17; | ||
|
||
// Copyright 2018 OpenST Ltd. | ||
|
@@ -60,8 +61,8 @@ contract Pricer is OpsManaged, PricerInterface { | |
/// @dev Takes _brandedToken, _baseCurrency; | ||
/// constructor; | ||
/// public method; | ||
/// @param _brandedToken _brandedToken | ||
/// @param _baseCurrency _baseCurrency | ||
/// @param _brandedToken Branded Token | ||
/// @param _baseCurrency Base Currency | ||
function Pricer( | ||
address _brandedToken, | ||
bytes3 _baseCurrency) | ||
|
@@ -251,7 +252,7 @@ contract Pricer is OpsManaged, PricerInterface { | |
/// @param _commissionAmount commissionAmount | ||
/// @param _currency currency | ||
/// @param _intendedPricePoint _intendedPricePoint | ||
/// @return bool isSuccess | ||
/// @return uint256 total paid | ||
function pay( | ||
address _beneficiary, | ||
uint256 _transferAmount, | ||
|
@@ -260,36 +261,28 @@ contract Pricer is OpsManaged, PricerInterface { | |
bytes3 _currency, | ||
uint256 _intendedPricePoint) | ||
public | ||
returns (bool /* success */) | ||
returns (uint256 /* total paid */) | ||
{ | ||
require(_beneficiary != address(0)); | ||
require(_transferAmount != 0); | ||
|
||
if (_commissionAmount > 0) { | ||
require(_commissionBeneficiary != address(0)); | ||
} | ||
require(isValidBeneficiaryData(_beneficiary, _transferAmount, | ||
_commissionBeneficiary, _commissionAmount)); | ||
|
||
uint256 tokenAmount = _transferAmount; | ||
uint256 commissionTokenAmount = _commissionAmount; | ||
uint256 pricePoint = _intendedPricePoint; | ||
if (_currency != 0) { | ||
pricePoint = getPricePoint(_currency); | ||
require(pricePoint > 0); | ||
require(isPricePointInRange(_intendedPricePoint, pricePoint, pricerAcceptedMargins[_currency])); | ||
(tokenAmount, commissionTokenAmount) = getBTAmountFromCurrencyValue(pricePoint, | ||
_transferAmount, _commissionAmount); | ||
} | ||
|
||
require(EIP20Interface(pricerBrandedToken).transferFrom(msg.sender, _beneficiary, tokenAmount)); | ||
if (_commissionBeneficiary != address(0)) { | ||
require(EIP20Interface(pricerBrandedToken).transferFrom(msg.sender, | ||
_commissionBeneficiary, commissionTokenAmount)); | ||
|
||
// check Margin And Calculate BTAmount | ||
if (_currency != "") { | ||
(pricePoint, tokenAmount, commissionTokenAmount) = validateMarginAndCalculateBTAmount(_currency, | ||
_intendedPricePoint, _transferAmount, _commissionAmount); | ||
} | ||
|
||
|
||
require(performTransfer(msg.sender, _beneficiary, tokenAmount, | ||
_commissionBeneficiary, commissionTokenAmount)); | ||
|
||
//Trigger Event for PaymentComplete | ||
Payment(_beneficiary, _transferAmount, _commissionBeneficiary, | ||
_commissionAmount, _currency, _intendedPricePoint, pricePoint); | ||
return true; | ||
_commissionAmount, _currency, _intendedPricePoint, pricePoint); | ||
return (tokenAmount + commissionTokenAmount); | ||
} | ||
|
||
/// @dev Takes _currency; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
again, the interaction layer can determine that there was no valid price point based on the return value, and an event on the get function is not needed |
||
|
@@ -309,7 +302,7 @@ contract Pricer is OpsManaged, PricerInterface { | |
|
||
/// @dev Takes _intendedPricePoint, _currentPricePoint, _acceptedMargin; | ||
/// checks if the current price point is in the acceptable range of intendedPricePoint; | ||
/// private method; | ||
/// internal method; | ||
/// @param _intendedPricePoint intendedPricePoint | ||
/// @param _currentPricePoint currentPricePoint | ||
/// @param _acceptedMargin acceptedMargin | ||
|
@@ -318,7 +311,7 @@ contract Pricer is OpsManaged, PricerInterface { | |
uint256 _intendedPricePoint, | ||
uint256 _currentPricePoint, | ||
uint256 _acceptedMargin) | ||
private | ||
internal | ||
pure | ||
returns (bool /*isValid*/) | ||
{ | ||
|
@@ -334,7 +327,7 @@ contract Pricer is OpsManaged, PricerInterface { | |
|
||
/// @dev Takes _pricePoint, _transferAmount, _commissionAmount; | ||
/// calculates the number of branded token equivalant to the currency amount; | ||
/// private method; | ||
/// internal method; | ||
/// @param _pricePoint pricePoint | ||
/// @param _transferAmount transferAmount | ||
/// @param _commissionAmount commissionAmount | ||
|
@@ -343,7 +336,7 @@ contract Pricer is OpsManaged, PricerInterface { | |
uint256 _pricePoint, | ||
uint256 _transferAmount, | ||
uint256 _commissionAmount) | ||
private | ||
internal | ||
view | ||
returns (uint256, uint256) /* number of BT ,number of commission BT */ | ||
{ | ||
|
@@ -352,4 +345,88 @@ contract Pricer is OpsManaged, PricerInterface { | |
uint256 commissionAmountBT = SafeMath.div(SafeMath.mul(_commissionAmount, adjConversionRate), _pricePoint); | ||
return (amountBT, commissionAmountBT); | ||
} | ||
|
||
/// @dev Takes _beneficiary, _transferAmount, _commissionBeneficiary, _commissionAmount; | ||
/// checks if the current price point is in the acceptable range of intendedPricePoint; | ||
/// internal method; | ||
/// @param _beneficiary beneficiary | ||
/// @param _transferAmount transferAmount | ||
/// @param _commissionBeneficiary commissionBeneficiary | ||
/// @param _commissionAmount commissionAmount | ||
/// @return bool isValid | ||
function isValidBeneficiaryData( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this function is ideal to put as up in Pricer.sol as a |
||
address _beneficiary, | ||
uint256 _transferAmount, | ||
address _commissionBeneficiary, | ||
uint256 _commissionAmount) | ||
internal | ||
returns (bool /*isValid*/) | ||
{ | ||
require(_beneficiary != address(0)); | ||
require(_transferAmount != 0); | ||
|
||
if (_commissionAmount > 0) { | ||
require(_commissionBeneficiary != address(0)); | ||
} | ||
return true; | ||
} | ||
|
||
/// @dev Takes _spender, _beneficiary, _tokenAmount, _commissionBeneficiary, _commissionTokenAmount; | ||
/// Perform tokenAmount transfer | ||
/// Perform commissionTokenAmount transfer | ||
/// internal method; | ||
/// @param _spender spender | ||
/// @param _beneficiary beneficiary | ||
/// @param _tokenAmount tokenAmount | ||
/// @param _commissionBeneficiary commissionBeneficiary | ||
/// @param _commissionTokenAmount commissionTokenAmount | ||
/// @return (bool) | ||
function performTransfer( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename to |
||
address _spender, | ||
address _beneficiary, | ||
uint256 _tokenAmount, | ||
address _commissionBeneficiary, | ||
uint256 _commissionTokenAmount) | ||
internal | ||
returns ( | ||
bool /* boolean value */) | ||
{ | ||
require(EIP20Interface(pricerBrandedToken).transferFrom(_spender, _beneficiary, _tokenAmount)); | ||
|
||
if (_commissionBeneficiary != address(0)) { | ||
require(EIP20Interface(pricerBrandedToken).transferFrom(_spender, | ||
_commissionBeneficiary, _commissionTokenAmount)); | ||
} | ||
return true; | ||
} | ||
|
||
/// @dev Takes _currency, _intendedPricePoint, _transferAmount, _commissionAmount; | ||
/// Validate accepted margin | ||
/// Calculates tokenAmount and commissionTokenAmount | ||
/// internal method | ||
/// @param _currency currency | ||
/// @param _intendedPricePoint intendedPricePoint | ||
/// @param _transferAmount transferAmount | ||
/// @param _commissionAmount commissionAmount | ||
/// @return (pricePoint, tokenAmount, commissionTokenAmount) | ||
function validateMarginAndCalculateBTAmount( | ||
bytes3 _currency, | ||
uint256 _intendedPricePoint, | ||
uint256 _transferAmount, | ||
uint256 _commissionAmount) | ||
internal | ||
returns (uint256, uint256, uint256) /* pricePoint, tokenAmount, commissionTokenAmount */ | ||
{ | ||
uint256 pricePoint = getPricePoint(_currency); | ||
require(pricePoint > 0); | ||
require(isPricePointInRange(_intendedPricePoint, pricePoint, acceptedMargins(_currency))); | ||
|
||
uint256 tokenAmount; | ||
uint256 commissionTokenAmount; | ||
(tokenAmount, commissionTokenAmount) = getBTAmountFromCurrencyValue(pricePoint, _transferAmount, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this function call to the functionality of having this function (L221) public is achievable in the interaction layer by using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as we concluded getPricePoint is called once in pay and payAirdrop flow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correction, in return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @benjaminbollen: are you noting this for posterity or commenting that this is a change you would like Abhay to make for this PR (which I think contradicts what we agreed in the meeting)? And does this relate to #50? |
||
_commissionAmount); | ||
|
||
return (pricePoint, tokenAmount, commissionTokenAmount); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Airdrop is not Workers