Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Settlement adjustments for the management of previously settled amounts #431

Merged
merged 2 commits into from
Aug 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions contracts/DriipSettlementByPayment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ CommunityVotable, FraudChallengable, WalletLockable, PartnerBenefactorable {
{
// Extract current balance and total fees
(int256 correctedCurrentBalance, int settleAmount, NahmiiTypesLib.OriginFigure[] memory totalFees) =
_getCorrectedCurrentBalanceSettledAmountTotalFees(payment, wallet);
_paymentPartyProperties(payment, wallet);

// Get max nonce for wallet and currency
uint256 maxNonce = driipSettlementState.maxNonceByWalletAndCurrency(wallet, payment.currency);
Expand All @@ -279,7 +279,7 @@ CommunityVotable, FraudChallengable, WalletLockable, PartnerBenefactorable {
);

// Update settled amount
driipSettlementState.addSettledAmount(wallet, settleAmount, payment.currency, payment.blockNumber);
driipSettlementState.addSettledAmountByBlockNumber(wallet, settleAmount, payment.currency, payment.blockNumber);

// Stage (stage function assures positive amount only)
clientFund.stage(
Expand Down Expand Up @@ -312,37 +312,39 @@ CommunityVotable, FraudChallengable, WalletLockable, PartnerBenefactorable {
}
}

function _getCorrectedCurrentBalanceSettledAmountTotalFees(PaymentTypesLib.Payment memory payment,
function _paymentPartyProperties(PaymentTypesLib.Payment memory payment,
address wallet)
private
view
returns (int256 currentBalance, int settleAmount, NahmiiTypesLib.OriginFigure[] memory totalFees)
returns (int256 correctedCurrentBalance, int settleAmount, NahmiiTypesLib.OriginFigure[] memory totalFees)
{
if (validator.isPaymentSender(payment, wallet)) {
currentBalance = payment.sender.balances.current;
correctedCurrentBalance = payment.sender.balances.current;
totalFees = payment.sender.fees.total;
} else {
currentBalance = payment.recipient.balances.current;
correctedCurrentBalance = payment.recipient.balances.current;
totalFees = payment.recipient.fees.total;
}

// Calculate settle amount by this payment
settleAmount = currentBalance.sub(balanceTracker.fungibleActiveBalanceAmountByBlockNumber(
wallet, payment.currency, payment.blockNumber
));

// Obtain delta in active balance amount since payment's block number
int256 deltaActiveBalanceAmount = balanceTracker.fungibleActiveDeltaBalanceAmountByBlockNumbers(
wallet, payment.currency, payment.blockNumber, block.number
);

// Obtain delta in settled balance amount
int256 deltaSettledBalanceAmount = driipSettlementState.settledAmount(
wallet, payment.currency, block.number
int256 deltaSettledBalanceAmount = driipSettlementState.settledAmountByBlockNumber(
wallet, payment.currency, payment.blockNumber
);

// Calculate settle amount by this payment
settleAmount = correctedCurrentBalance.sub(
balanceTracker.fungibleActiveBalanceAmountByBlockNumber(
wallet, payment.currency, payment.blockNumber
)
).sub(deltaSettledBalanceAmount);

// Correct the payment's balance by on-chain deltas
currentBalance = currentBalance
correctedCurrentBalance = correctedCurrentBalance
.add(deltaActiveBalanceAmount)
.sub(deltaSettledBalanceAmount);
}
Expand Down
22 changes: 11 additions & 11 deletions contracts/DriipSettlementChallengeByPayment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ BalanceTrackable {
);

// Deduce the concerned nonce and cumulative relative transfer
(uint256 nonce, int256 cumulativeTransferAmount) = _paymentPartyProperties(payment, wallet);
(uint256 nonce, int256 correctedCumulativeTransferAmount) = _paymentPartyProperties(payment, wallet);

// Require that the wallet nonce of the payment is higher than the highest settled wallet nonce
require(
Expand All @@ -521,11 +521,11 @@ BalanceTrackable {
);

// Initiate proposal, including assurance that there is no overlap with active proposal
// Target balance amount is calculated as current balance - cumulativeTransferAmount - stageAmount
// Target balance amount is calculated as current (payment) balance - cumulativeTransferAmount - stageAmount
driipSettlementChallengeState.initiateProposal(
wallet, nonce, cumulativeTransferAmount, stageAmount,
wallet, nonce, correctedCumulativeTransferAmount, stageAmount,
balanceTracker.fungibleActiveBalanceAmount(wallet, payment.currency)
.sub(cumulativeTransferAmount.add(stageAmount)),
.sub(correctedCumulativeTransferAmount.add(stageAmount)),
payment.currency, payment.blockNumber,
walletInitiated, payment.seals.operator.hash, PaymentTypesLib.PAYMENT_KIND()
);
Expand Down Expand Up @@ -561,23 +561,23 @@ BalanceTrackable {
wallet, payment.currency, payment.blockNumber
);

// Obtain the settled amount
int256 settledBalanceAmount = driipSettlementState.settledAmount(
wallet, payment.currency, block.number
// Obtain the delta settled amount
int256 deltaSettledBalanceAmount = driipSettlementState.settledAmountByBlockNumber(
wallet, payment.currency, payment.blockNumber
);

// Obtain nonce and cumulative (relative) transfer amount.
// Correct the cumulative transfer amount by the amount that has already been settled
if (validator.isPaymentSender(payment, wallet)) {
nonce = payment.sender.nonce;
correctedCumulativeTransferAmount = balanceAmountAtPaymentBlock
correctedCumulativeTransferAmount = balanceAmountAtPaymentBlock // TODO Consider reverting sign of cumulative transfer amount
.sub(payment.sender.balances.current)
.add(settledBalanceAmount);
.add(deltaSettledBalanceAmount);
} else {
nonce = payment.recipient.nonce;
correctedCumulativeTransferAmount = balanceAmountAtPaymentBlock
correctedCumulativeTransferAmount = balanceAmountAtPaymentBlock // TODO Consider reverting sign of cumulative transfer amount
.sub(payment.recipient.balances.current)
.add(settledBalanceAmount);
.add(deltaSettledBalanceAmount);
}
}
}
63 changes: 44 additions & 19 deletions contracts/DriipSettlementState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {SafeMathUintLib} from "./SafeMathUintLib.sol";
import {MonetaryTypesLib} from "./MonetaryTypesLib.sol";
import {NahmiiTypesLib} from "./NahmiiTypesLib.sol";
import {DriipSettlementTypesLib} from "./DriipSettlementTypesLib.sol";
import {FungibleBalanceLib} from "./FungibleBalanceLib.sol";

/**
* @title DriipSettlementState
Expand All @@ -29,7 +28,6 @@ import {FungibleBalanceLib} from "./FungibleBalanceLib.sol";
contract DriipSettlementState is Ownable, Servable, CommunityVotable {
using SafeMathIntLib for int256;
using SafeMathUintLib for uint256;
using FungibleBalanceLib for FungibleBalanceLib.Balance;

//
// Constants
Expand All @@ -50,7 +48,8 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
mapping(address => mapping(uint256 => uint256)) public walletNonceSettlementIndex;
mapping(address => mapping(address => mapping(uint256 => uint256))) public walletCurrencyMaxNonce;

mapping(address => FungibleBalanceLib.Balance) private walletSettledAmount;
mapping(address => mapping(address => mapping(uint256 => mapping(uint256 => int256)))) public walletSettledAmount;
mapping(address => mapping(address => mapping(uint256 => uint256[]))) public walletSettledBlockNumbers;

mapping(address => mapping(address => mapping(address => mapping(address => mapping(uint256 => MonetaryTypesLib.NoncedAmount))))) public totalFeesMap;

Expand Down Expand Up @@ -111,7 +110,7 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
view
returns (DriipSettlementTypesLib.Settlement memory)
{
require(walletSettlementIndices[wallet].length > index, "Index out of bounds [DriipSettlementState.sol:114]");
require(walletSettlementIndices[wallet].length > index, "Index out of bounds [DriipSettlementState.sol:113]");
return settlements[walletSettlementIndices[wallet][index] - 1];
}

Expand All @@ -124,7 +123,7 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
view
returns (DriipSettlementTypesLib.Settlement memory)
{
require(0 != walletNonceSettlementIndex[wallet][nonce], "No settlement found for wallet and nonce [DriipSettlementState.sol:127]");
require(0 != walletNonceSettlementIndex[wallet][nonce], "No settlement found for wallet and nonce [DriipSettlementState.sol:126]");
return settlements[walletNonceSettlementIndex[wallet][nonce] - 1];
}

Expand Down Expand Up @@ -185,7 +184,7 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
uint256 index = walletNonceSettlementIndex[wallet][nonce];

// Require the existence of settlement
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:188]");
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:187]");

// Get the settlement party
DriipSettlementTypesLib.SettlementParty storage party =
Expand Down Expand Up @@ -250,7 +249,7 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
settlements[index - 1].origin : settlements[index - 1].target;

// Require that wallet is party of the right role
require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:253]");
require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:252]");

// Return done
return settlementParty.done;
Expand All @@ -269,7 +268,7 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
uint256 index = walletNonceSettlementIndex[wallet][nonce];

// Require the existence of settlement
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:272]");
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:271]");

// Return done block number
return (
Expand All @@ -294,15 +293,15 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
uint256 index = walletNonceSettlementIndex[wallet][nonce];

// Require the existence of settlement
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:297]");
require(0 != index, "No settlement found for wallet and nonce [DriipSettlementState.sol:296]");

// Get the settlement party
DriipSettlementTypesLib.SettlementParty storage settlementParty =
DriipSettlementTypesLib.SettlementRole.Origin == settlementRole ?
settlements[index - 1].origin : settlements[index - 1].target;

// Require that wallet is party of the right role
require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:305]");
require(wallet == settlementParty.wallet, "Wallet has wrong settlement role [DriipSettlementState.sol:304]");

// Return done block number
return settlementParty.doneBlockNumber;
Expand Down Expand Up @@ -365,28 +364,39 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
/// @notice Get the value of settled amount at the given block number
/// @param wallet The address of the concerned wallet
/// @param currency The concerned currency
/// @param blockNumber The block number of calculation
function settledAmount(address wallet, MonetaryTypesLib.Currency memory currency,
/// @param blockNumber The concerned block number
function settledAmountByBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency,
uint256 blockNumber)
public
view
returns (int256)
{
return walletSettledAmount[wallet].getByBlockNumber(currency.ct, currency.id, blockNumber);
uint256 settledBlockNumber = _walletSettledBlockNumber(wallet, currency, blockNumber);
return 0 < settledBlockNumber ? walletSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber] : 0;
}

/// @notice Add to the settled amount at the given block number
/// @param wallet The address of the concerned wallet
/// @param amount The new settled amount
/// @param currency The concerned currency
/// @param blockNumber The concerned block number
function addSettledAmount(address wallet, int256 amount, MonetaryTypesLib.Currency memory currency,
function addSettledAmountByBlockNumber(address wallet, int256 amount, MonetaryTypesLib.Currency memory currency,
uint256 blockNumber)
public
onlyEnabledServiceAction(ADD_SETTLED_AMOUNT_ACTION)
{
// Add amount record at the given block number
walletSettledAmount[wallet].addByBlockNumber(amount, currency.ct, currency.id, blockNumber);
// Get the current settled block number
uint256 settledBlockNumber = _walletSettledBlockNumber(wallet, currency, blockNumber);

// Update at settled block number if found
if (0 < settledBlockNumber)
walletSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber] =
walletSettledAmount[wallet][currency.ct][currency.id][settledBlockNumber].add(amount);
// Else update at new block number
else {
walletSettledBlockNumbers[wallet][currency.ct][currency.id].push(blockNumber);
walletSettledAmount[wallet][currency.ct][currency.id][blockNumber] = amount;
}

// Emit event
emit AddSettledAmountEvent(wallet, amount, currency, blockNumber);
Expand Down Expand Up @@ -447,11 +457,11 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
onlyDeployer
{
// Require that upgrades have not been frozen
require(!upgradesFrozen, "Upgrades have been frozen [DriipSettlementState.sol:450]");
require(!upgradesFrozen, "Upgrades have been frozen [DriipSettlementState.sol:460]");

// Require that settlement has not been initialized/upgraded already
require(0 == walletNonceSettlementIndex[originWallet][originNonce], "Settlement exists for origin wallet and nonce [DriipSettlementState.sol:453]");
require(0 == walletNonceSettlementIndex[targetWallet][targetNonce], "Settlement exists for target wallet and nonce [DriipSettlementState.sol:454]");
require(0 == walletNonceSettlementIndex[originWallet][originNonce], "Settlement exists for origin wallet and nonce [DriipSettlementState.sol:463]");
require(0 == walletNonceSettlementIndex[targetWallet][targetNonce], "Settlement exists for target wallet and nonce [DriipSettlementState.sol:464]");

// Create new settlement
settlements.length++;
Expand Down Expand Up @@ -481,4 +491,19 @@ contract DriipSettlementState is Ownable, Servable, CommunityVotable {
walletNonceSettlementIndex[originWallet][originNonce] = index;
walletNonceSettlementIndex[targetWallet][targetNonce] = index;
}

//
// Private functions
// -----------------------------------------------------------------------------------------------------------------
function _walletSettledBlockNumber(address wallet, MonetaryTypesLib.Currency memory currency,
uint256 blockNumber)
private
view
returns (uint256)
{
for (uint256 i = walletSettledBlockNumbers[wallet][currency.ct][currency.id].length; i > 0; i--)
if (walletSettledBlockNumbers[wallet][currency.ct][currency.id][i - 1] <= blockNumber)
return walletSettledBlockNumbers[wallet][currency.ct][currency.id][i - 1];
return 0;
}
}
26 changes: 26 additions & 0 deletions contracts/FungibleBalanceLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ library FungibleBalanceLib {
updateCurrencies(self, currencyCt, currencyId);
}

function setByBlockNumber(Balance storage self, int256 amount, address currencyCt, uint256 currencyId,
uint256 blockNumber)
internal
{
self.amountByCurrency[currencyCt][currencyId] = amount;

self.recordsByCurrency[currencyCt][currencyId].push(
Record(self.amountByCurrency[currencyCt][currencyId], blockNumber)
);

updateCurrencies(self, currencyCt, currencyId);
}

function add(Balance storage self, int256 amount, address currencyCt, uint256 currencyId)
internal
{
Expand Down Expand Up @@ -102,6 +115,19 @@ library FungibleBalanceLib {
updateCurrencies(self, currencyCt, currencyId);
}

function subByBlockNumber(Balance storage self, int256 amount, address currencyCt, uint256 currencyId,
uint256 blockNumber)
internal
{
self.amountByCurrency[currencyCt][currencyId] = self.amountByCurrency[currencyCt][currencyId].sub(amount);

self.recordsByCurrency[currencyCt][currencyId].push(
Record(self.amountByCurrency[currencyCt][currencyId], blockNumber)
);

updateCurrencies(self, currencyCt, currencyId);
}

function transfer(Balance storage _from, Balance storage _to, int256 amount,
address currencyCt, uint256 currencyId)
internal
Expand Down
4 changes: 2 additions & 2 deletions contracts/test/MockedDriipSettlementState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,14 @@ contract MockedDriipSettlementState {
maxDriipNonce = _maxDriipNonce;
}

function settledAmount(address, MonetaryTypesLib.Currency memory, uint256)
function settledAmountByBlockNumber(address, MonetaryTypesLib.Currency memory, uint256)
public
view
returns (int256) {
return _settledAmount;
}

function addSettledAmount(address, int256 amount, MonetaryTypesLib.Currency memory, uint256)
function addSettledAmountByBlockNumber(address, int256 amount, MonetaryTypesLib.Currency memory, uint256)
public
{
_settledAmount += amount;
Expand Down
4 changes: 2 additions & 2 deletions test/scenarios/DriipSettlementByPayment.js
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ module.exports = (glob) => {

describe('if there is delta in settled balance', () => {
beforeEach(async () => {
await ethersDriipSettlementState.addSettledAmount(
await ethersDriipSettlementState.addSettledAmountByBlockNumber(
payment.sender.wallet, utils.parseUnits('100', 18), payment.currency, payment.blockNumber
);
});
Expand Down Expand Up @@ -1186,7 +1186,7 @@ module.exports = (glob) => {

describe('if there is delta in settled balance', () => {
beforeEach(async () => {
await ethersDriipSettlementState.addSettledAmount(
await ethersDriipSettlementState.addSettledAmountByBlockNumber(
payment.sender.wallet, utils.parseUnits('100', 18), payment.currency, payment.blockNumber
);
});
Expand Down
4 changes: 2 additions & 2 deletions test/scenarios/DriipSettlementChallengeByPayment.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ module.exports = (glob) => {
await ethersDriipSettlementChallengeState._setProposal(true);
await ethersDriipSettlementChallengeState._setProposalTerminated(true);

await ethersDriipSettlementState.addSettledAmount(
await ethersDriipSettlementState.addSettledAmountByBlockNumber(
payment.sender.wallet, utils.parseUnits('100', 18), payment.currency, payment.blockNumber,
{gasLimit: 1e6}
);
Expand Down Expand Up @@ -607,7 +607,7 @@ module.exports = (glob) => {
await ethersDriipSettlementChallengeState._setProposal(true);
await ethersDriipSettlementChallengeState._setProposalTerminated(true);

await ethersDriipSettlementState.addSettledAmount(
await ethersDriipSettlementState.addSettledAmountByBlockNumber(
payment.sender.wallet, utils.parseUnits('100', 18), payment.currency, payment.blockNumber,
{gasLimit: 1e6}
);
Expand Down
Loading