Skip to content
This repository has been archived by the owner on Aug 6, 2021. It is now read-only.

Commit

Permalink
Fix wrong cyclic date if lastScheduleTime is zero in all Engines in a…
Browse files Browse the repository at this point in the history
…ctus-solidity
  • Loading branch information
jo-es committed Jul 1, 2020
1 parent 81b14a8 commit c38fb0b
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 81 deletions.
28 changes: 12 additions & 16 deletions packages/actus-solidity/contracts/Engines/ANN/ANNEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,9 @@ contract ANNEngine is Core, ANNSTF, ANNPOF, IANNEngine {
// interest payment related (starting with PRANX interest is paid following the PR schedule)
if (
terms.cycleOfInterestPayment.isSet == true && terms.cycleAnchorDateOfInterestPayment != 0) {
uint256 nextInterestPaymentDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfInterestPayment,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfInterestPayment : lastScheduleTime
);
uint256 nextInterestPaymentDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfInterestPayment
: computeNextCycleDateFromPrecedingDate(terms.cycleOfInterestPayment, lastScheduleTime);
if (nextInterestPaymentDate == 0) return bytes32(0);
if (nextInterestPaymentDate <= terms.capitalizationEndDate) return bytes32(0);
return encodeEvent(EventType.IP, nextInterestPaymentDate);
Expand All @@ -328,10 +327,9 @@ contract ANNEngine is Core, ANNSTF, ANNPOF, IANNEngine {
) {
IPS memory cycleOfInterestCapitalization = terms.cycleOfInterestPayment;
cycleOfInterestCapitalization.s = S.SHORT;
uint256 nextInterestCapitalizationDate = computeNextCycleDateFromPrecedingDate(
cycleOfInterestCapitalization,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfInterestPayment : lastScheduleTime
);
uint256 nextInterestCapitalizationDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfInterestPayment
: computeNextCycleDateFromPrecedingDate(cycleOfInterestCapitalization, lastScheduleTime);
if (nextInterestCapitalizationDate == 0) return bytes32(0);
return encodeEvent(EventType.IPCI, nextInterestCapitalizationDate);
}
Expand All @@ -340,21 +338,19 @@ contract ANNEngine is Core, ANNSTF, ANNPOF, IANNEngine {
// fees
if (eventType == EventType.FP) {
if (terms.cycleOfFee.isSet == true && terms.cycleAnchorDateOfFee != 0) {
uint256 nextFeeDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfFee,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfFee : lastScheduleTime
);
uint256 nextFeeDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfFee
: computeNextCycleDateFromPrecedingDate(terms.cycleOfFee, lastScheduleTime);
if (nextFeeDate == 0) return bytes32(0);
return encodeEvent(EventType.FP, nextFeeDate);
}
}

// principal redemption
if (eventType == EventType.PR) {
uint256 nextPrincipalRedemptionDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfPrincipalRedemption,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfPrincipalRedemption : lastScheduleTime
);
uint256 nextPrincipalRedemptionDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfPrincipalRedemption
: computeNextCycleDateFromPrecedingDate(terms.cycleOfPrincipalRedemption, lastScheduleTime);
if (nextPrincipalRedemptionDate == 0) return bytes32(0);
return encodeEvent(EventType.PR, nextPrincipalRedemptionDate);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/actus-solidity/contracts/Engines/CEC/CECEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ contract CECEngine is Core, CECSTF, CECPOF, ICECEngine {
/**
* @notice Computes a schedule segment of cyclic contract events based on the contract terms
* and the specified timestamps.
* @param terms terms of the contract
* @param lastScheduleTime last occurrence of cyclic event
* @param eventType eventType of the cyclic schedule
* param terms terms of the contract
* param lastScheduleTime last occurrence of cyclic event
* param eventType eventType of the cyclic schedule
* @return event schedule segment
*/
function computeNextCyclicEvent(
CECTerms calldata terms,
uint256 lastScheduleTime,
EventType eventType
CECTerms calldata /* terms */,
uint256 /* lastScheduleTime */,
EventType /* eventType */
)
external
pure
Expand Down
7 changes: 3 additions & 4 deletions packages/actus-solidity/contracts/Engines/CEG/CEGEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,9 @@ contract CEGEngine is Core, CEGSTF, CEGPOF, ICEGEngine {
if (eventType == EventType.FP) {
// fees
if (terms.cycleOfFee.isSet == true && terms.cycleAnchorDateOfFee != 0) {
uint256 nextFeeDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfFee,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfFee : lastScheduleTime
);
uint256 nextFeeDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfFee
: computeNextCycleDateFromPrecedingDate(terms.cycleOfFee, lastScheduleTime);
if (nextFeeDate == 0) return bytes32(0);
return encodeEvent(EventType.FP, nextFeeDate);
}
Expand Down
35 changes: 15 additions & 20 deletions packages/actus-solidity/contracts/Engines/CERTF/CERTFEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -314,21 +314,19 @@ contract CERTFEngine is Core, CERTFSTF, CERTFPOF, ICERTFEngine {
{
if (eventType == EventType.CFD) {
if (terms.cycleOfCoupon.isSet == true && terms.cycleAnchorDateOfCoupon != 0) {
uint256 nextCouponDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfCoupon,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfCoupon : lastScheduleTime
);
uint256 nextCouponDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfCoupon
: computeNextCycleDateFromPrecedingDate(terms.cycleOfCoupon, lastScheduleTime);
if (nextCouponDate == uint256(0)) return bytes32(0);
return encodeEvent(EventType.CFD, nextCouponDate);
}
}

if (eventType == EventType.CPD) {
if (terms.cycleOfCoupon.isSet == true && terms.cycleAnchorDateOfCoupon != 0) {
uint256 nextCouponDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfCoupon,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfCoupon : lastScheduleTime
);
uint256 nextCouponDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfCoupon
: computeNextCycleDateFromPrecedingDate(terms.cycleOfCoupon, lastScheduleTime);
if (nextCouponDate == uint256(0)) return bytes32(0);
uint256 couponPaymentDayScheduleTime = getTimestampPlusPeriod(terms.settlementPeriod, nextCouponDate);
return encodeEvent(EventType.CFD, couponPaymentDayScheduleTime);
Expand All @@ -337,21 +335,19 @@ contract CERTFEngine is Core, CERTFSTF, CERTFPOF, ICERTFEngine {

if (eventType == EventType.RFD) {
if (terms.cycleOfRedemption.isSet == true && terms.cycleAnchorDateOfRedemption != 0) {
uint256 nextRedemptionDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfRedemption,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfRedemption : lastScheduleTime
);
uint256 nextRedemptionDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfRedemption
: computeNextCycleDateFromPrecedingDate(terms.cycleOfRedemption, lastScheduleTime);
if (nextRedemptionDate == uint256(0)) return bytes32(0);
return encodeEvent(EventType.RFD, nextRedemptionDate);
}
}

if (eventType == EventType.RPD) {
if (terms.cycleOfRedemption.isSet == true && terms.cycleAnchorDateOfRedemption != 0) {
uint256 nextRedemptionDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfRedemption,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfRedemption : lastScheduleTime
);
uint256 nextRedemptionDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfRedemption
: computeNextCycleDateFromPrecedingDate(terms.cycleOfRedemption, lastScheduleTime);
if (nextRedemptionDate == uint256(0)) return bytes32(0);
uint256 redemptionPaymentDayScheduleTime = getTimestampPlusPeriod(terms.settlementPeriod, nextRedemptionDate);
return encodeEvent(EventType.RPD, redemptionPaymentDayScheduleTime);
Expand All @@ -360,10 +356,9 @@ contract CERTFEngine is Core, CERTFSTF, CERTFPOF, ICERTFEngine {

if (eventType == EventType.XD) {
if (terms.cycleOfRedemption.isSet == true && terms.cycleAnchorDateOfRedemption != 0) {
uint256 nextRedemptionDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfRedemption,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfRedemption : lastScheduleTime
);
uint256 nextRedemptionDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfRedemption
: computeNextCycleDateFromPrecedingDate(terms.cycleOfRedemption, lastScheduleTime);
if (nextRedemptionDate == uint256(0)) return bytes32(0);
if (nextRedemptionDate == terms.maturityDate) return bytes32(0);
uint256 executionDateScheduleTime = getTimestampPlusPeriod(terms.exercisePeriod, nextRedemptionDate);
Expand Down
38 changes: 16 additions & 22 deletions packages/actus-solidity/contracts/Engines/PAM/PAMEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,10 @@ contract PAMEngine is Core, PAMSTF, PAMPOF, IPAMEngine {
{
if (eventType == EventType.IP) {
// interest payment related (starting with PRANX interest is paid following the PR schedule)
if (
terms.cycleOfInterestPayment.isSet == true && terms.cycleAnchorDateOfInterestPayment != 0) {
uint256 nextInterestPaymentDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfInterestPayment,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfInterestPayment : lastScheduleTime
);
if (terms.cycleOfInterestPayment.isSet == true && terms.cycleAnchorDateOfInterestPayment != 0) {
uint256 nextInterestPaymentDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfInterestPayment
: computeNextCycleDateFromPrecedingDate(terms.cycleOfInterestPayment, lastScheduleTime);
if (nextInterestPaymentDate == 0) return bytes32(0);
if (nextInterestPaymentDate <= terms.capitalizationEndDate) return bytes32(0);
return encodeEvent(EventType.IP, nextInterestPaymentDate);
Expand All @@ -346,10 +344,9 @@ contract PAMEngine is Core, PAMSTF, PAMPOF, IPAMEngine {
) {
IPS memory cycleOfInterestCapitalization = terms.cycleOfInterestPayment;
cycleOfInterestCapitalization.s = S.SHORT;
uint256 nextInterestCapitalizationDate = computeNextCycleDateFromPrecedingDate(
cycleOfInterestCapitalization,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfInterestPayment : lastScheduleTime
);
uint256 nextInterestCapitalizationDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfInterestPayment
: computeNextCycleDateFromPrecedingDate(cycleOfInterestCapitalization, lastScheduleTime);
if (nextInterestCapitalizationDate == 0) return bytes32(0);
return encodeEvent(EventType.IPCI, nextInterestCapitalizationDate);
}
Expand All @@ -358,10 +355,9 @@ contract PAMEngine is Core, PAMSTF, PAMPOF, IPAMEngine {
if (eventType == EventType.RR) {
// rate reset
if (terms.cycleOfRateReset.isSet == true && terms.cycleAnchorDateOfRateReset != 0) {
uint256 nextRateResetDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfRateReset,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfRateReset : lastScheduleTime
);
uint256 nextRateResetDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfRateReset
: computeNextCycleDateFromPrecedingDate(terms.cycleOfRateReset, lastScheduleTime);
if (nextRateResetDate == 0) return bytes32(0);
return encodeEvent(EventType.RR, nextRateResetDate);
}
Expand All @@ -371,10 +367,9 @@ contract PAMEngine is Core, PAMSTF, PAMPOF, IPAMEngine {
if (eventType == EventType.FP) {
// fees
if (terms.cycleOfFee.isSet == true && terms.cycleAnchorDateOfFee != 0) {
uint256 nextFeeDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfFee,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfFee : lastScheduleTime
);
uint256 nextFeeDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfFee
: computeNextCycleDateFromPrecedingDate(terms.cycleOfFee, lastScheduleTime);
if (nextFeeDate == 0) return bytes32(0);
return encodeEvent(EventType.FP, nextFeeDate);
}
Expand All @@ -383,10 +378,9 @@ contract PAMEngine is Core, PAMSTF, PAMPOF, IPAMEngine {
if (eventType == EventType.SC) {
// scaling
if ((terms.scalingEffect != ScalingEffect._000) && terms.cycleAnchorDateOfScalingIndex != 0) {
uint256 nextScalingDate = computeNextCycleDateFromPrecedingDate(
terms.cycleOfScalingIndex,
(lastScheduleTime == 0) ? terms.cycleAnchorDateOfScalingIndex : lastScheduleTime
);
uint256 nextScalingDate = (lastScheduleTime == 0)
? terms.cycleAnchorDateOfScalingIndex
: computeNextCycleDateFromPrecedingDate(terms.cycleOfScalingIndex, lastScheduleTime);
if (nextScalingDate == 0) return bytes32(0);
return encodeEvent(EventType.SC, nextScalingDate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,15 @@ abstract contract ScheduleRegistry is

if (asset.schedule.length == 0 && nextCyclicEvent == bytes32(0)) return bytes32(0);

(, uint256 scheduleTimeNextCyclicEvent) = decodeEvent(nextCyclicEvent);
(, uint256 scheduleTimeNextScheduleEvent) = decodeEvent(nextScheduleEvent);
(EventType eventTypeNextCyclicEvent, uint256 scheduleTimeNextCyclicEvent) = decodeEvent(nextCyclicEvent);
(EventType eventTypeNextScheduleEvent, uint256 scheduleTimeNextScheduleEvent) = decodeEvent(nextScheduleEvent);

if (
scheduleTimeNextScheduleEvent == 0
|| (scheduleTimeNextCyclicEvent != 0 && scheduleTimeNextCyclicEvent < scheduleTimeNextScheduleEvent)
(scheduleTimeNextScheduleEvent == 0 || (scheduleTimeNextCyclicEvent != 0 && scheduleTimeNextCyclicEvent < scheduleTimeNextScheduleEvent))
|| (
scheduleTimeNextCyclicEvent == scheduleTimeNextScheduleEvent
&& getEpochOffset(eventTypeNextCyclicEvent) < getEpochOffset(eventTypeNextScheduleEvent)
)
) {
return nextCyclicEvent;
} else {
Expand Down
59 changes: 55 additions & 4 deletions packages/ap-contracts/test/Core/PAM/PAMActor/TestCycles.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract('PAMActor', (accounts) => {
this.terms.settlementCurrency = this.PaymentTokenInstance.address;
this.terms.statusDate = this.terms.contractDealDate;

this.schedule = [];
this.schedule = await generateSchedule(this.PAMEngineInstance, this.terms);
this.state = web3ResponseToState(await this.PAMEngineInstance.computeInitialState(this.terms));

const tx = await this.PAMActorInstance.initialize(
Expand All @@ -56,12 +56,10 @@ contract('PAMActor', (accounts) => {
this.PAMEngineInstance.address,
ZERO_ADDRESS
);

await expectEvent.inTransaction(
tx.tx, PAMActor, 'InitializedAsset'
);

this.assetId = tx.logs[0].args.assetId;
this.assetId = tx.logs[0].args.assetId;

snapshot = await createSnapshot();
});
Expand All @@ -70,6 +68,59 @@ contract('PAMActor', (accounts) => {
await revertToSnapshot(snapshot);
});

it('should process the first non-cyclic event', async () => {
const _event = await this.PAMRegistryInstance.getNextScheduledEvent(web3.utils.toHex(this.assetId));
const eventTime = await getEventTime(_event, this.terms)

const payoff = new BigNumber(await this.PAMEngineInstance.computePayoffForEvent(
this.terms,
this.state,
_event,
web3.utils.toHex(0)
));

const value = web3.utils.toHex((payoff.isGreaterThan(0)) ? payoff : payoff.negated());

// set allowance for Payment Router
await this.PaymentTokenInstance.approve(
this.PAMActorInstance.address,
value,
{ from: (payoff.isGreaterThan(0)) ? counterpartyObligor : creatorObligor }
);

// settle and progress asset state
await mineBlock(eventTime);
const tx = await this.PAMActorInstance.progress(
web3.utils.toHex(this.assetId),
{ from: creatorObligor }
);
const { args: { 0: emittedAssetId } } = await expectEvent.inTransaction(
tx.tx, PAMActor, 'ProgressedAsset'
);

const storedNextState = web3ResponseToState(await this.PAMRegistryInstance.getState(web3.utils.toHex(this.assetId)));
const isEventSettled = await this.PAMRegistryInstance.isEventSettled(web3.utils.toHex(this.assetId), _event);
const projectedNextState = web3ResponseToState(await this.PAMEngineInstance.computeStateForEvent(
this.terms,
this.state,
_event,
web3.utils.toHex(0)
));
const storedNextEvent = await this.PAMRegistryInstance.getNextScheduledEvent(web3.utils.toHex(this.assetId));

assert.equal(emittedAssetId, this.assetId);
assert.notEqual(storedNextEvent, _event);
assert.equal(storedNextState.statusDate, eventTime);
assert.equal(isEventSettled[0], true);
assert.equal(isEventSettled[1].toString(), payoff.toFixed());
assert.deepEqual(storedNextState, projectedNextState);

this.state = storedNextState;

// await revertToSnapshot(snapshot_asset);
// snapshot_asset = await createSnapshot();
});

it('should process the next cyclic event', async () => {
const _event = await this.PAMRegistryInstance.getNextScheduledEvent(web3.utils.toHex(this.assetId));
const eventTime = await getEventTime(_event, this.terms)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ contract('PAMActor', (accounts) => {

it('should process next state with contract status equal to PF', async () => {
const _event = await this.PAMRegistryInstance.getNextScheduledEvent(web3.utils.toHex(this.assetId));
const eventTime = await getEventTime(_event, this.terms)
const eventTime = await getEventTime(_event, this.terms);

const payoff = new BigNumber(await this.PAMEngineInstance.computePayoffForEvent(
this.terms,
Expand Down
Loading

0 comments on commit c38fb0b

Please sign in to comment.