Skip to content

[Audit] Revised Payment Order Struct#703

Closed
marvinkruse wants to merge 19 commits intoaudit-dev-prefrom
audit-payment-order-struct
Closed

[Audit] Revised Payment Order Struct#703
marvinkruse wants to merge 19 commits intoaudit-dev-prefrom
audit-payment-order-struct

Conversation

@marvinkruse
Copy link
Member

@marvinkruse marvinkruse commented Dec 20, 2024

This PR contains changes related to our revised Payment Order Struct. A payment order is a formalized set of information used by payment clients and are sent to a payment processor, who acts based upon the information contained in the order.

What have we done
We revamped the struct and made a distinction between base information (i.e. amount, token, chainId, etc.) and additional information, where we saw that the additional information needs to allow for certain changes over time. We ultimately arrived at this struct:

struct PaymentOrder {
    address recipient;    
    address paymentToken;
    uint amount;
    uint originChainId;
    uint targetChainId;        
    bytes32 flags;
    bytes32[] data;
}

The way the flags and data fields work is as follows:
The flags field encodes which information is contained in the data array. The way this happens is similar to a bit-mask, where each of the bits in the bytes32 variable represents one potential data type. We currently have these slots defined:

    | Flag | Variable type | Name       | Description                         |
    |------|---------------|------------|-------------------------------------|
    | 0    | bytes32       | orderID    | ID of the order.                    |
    | 1    | uint256       | start      | Start date of the streaming period. | 
    | 2    | uint256       | cliff      | Duration of the cliff period.       |
    | 3    | uint256       | end        | Due Date of the order               |
    | ...  | ...           | ...        | (yet unassigned)                    |
    | 255  | .             | .          | (Max Value).                        | 
    |------|---------------|------------|-------------------------------------|

So in this example, if we want to make use of the streamed payment processor and want to encode the start, cliff, and end times, we would set the flags value to be 0000 [...] 0000 1110, so the flags at position 1, 2 and 3 and set to 1, while the rest is set to 0. If the used payment processor allows for start, cliff, and end values, it will check whether these slots are set (i.e. are 1) and - if that is the case - extract these values from the array.

The data array only contains values for slots where the flag is 1, so for the example above (0000 [...] 0000 1110) it would contain three data entries (length of 3), where the first one is from flag 1 and so on.

The documentation around this and the definition of the available slots can be found in IERC20PaymentClientBase_v1.sol.

* chore: adds notes md

* chore: adapts PP Simple

* chore: adapts PP Streaming

* tmp

* chore: adapts recurring pc

* chore: adapts staking lm

* chore: adapts payment router

* chore: compiles

* fix: `ERC20PaymentClientBaseV1Test > testAddPaymentOrders`

* fix: `ERC20PaymentClientBaseV1Test > testAddPaymentOrder`

* fix: `PP_SimpleV1Test` > `test_ValidPaymentOrder`

* fix: `PP_StreamingV1Test` > `test_processPayments`

* fix: `PP_StreamingV1Test`

* chore: removes console logs

* fix: `LM_PC_RecurringPayments_v1`

* fix: `LM_PC_Staking_v1Test`

* chore: fix outstanding tests

* fix: event in pp template

* chore: removes todo

* chore: cleanup I

* fix: always sets cliff flag in payment router

* chore: cleanup II

* chore: fix commented tests

* chore: cleanup III

* chore: adds default values to streaming pp

* chore: renames `original_` => `exposed_`

* chore: uses internal setters for default vals

* chore: sets flags manually in recurring payments

* chore: adds validation for stream time config

* chore: fmt

* chore: turn state vars private

* chore: getter functions in staking and kpi module

* chore: adapt state vars to coding standards

* chore: adds internal validator fn for staking module

* chore: make fmt

* chore: shift flags by one

* chore: fmt

* Feat: Add Wrapper for Mint and Transfer Functions

* Make the issue tokens functionality abstract

* Adapt all inherited contracts

* Revert Mock override

Shouldnt have done that in the first place

* Adapt Tests

* Rename issueTokens to distributeIssuanceToken

* Make distribute collateral functionality abstract

* Rename parameter

* Make naming uniform

* Adapt all inherited contracts

* adapt spelling mistake

* Adapt tests

* Cleanup

* Fix test

* Address Comments: Natspec

* Cleanup

* Rename _distributeIssuanceToken to _handleIssuanceTokenAfterBuy

* Rename _distributeCollateralToken to _handleCollateralTokenAfterSell

* Update FM_BC_Bancor_Redeeming_VirtualSupply_v1.sol

* Update BondingCurveBase_v1.sol

* Update Sections

* Rename Function

* Adapt sections in mocks

* rename _handleIssuanceTokenAfterBuy

* Update comments

* Rename to _collateralTokenAmount

* Update src/modules/fundingManager/bondingCurve/abstracts/BondingCurveBase_v1.sol

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

* Rename _issuanceMintAmount

* Update src/modules/fundingManager/bondingCurve/abstracts/RedeemingBondingCurveBase_v1.sol

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

* Adapt version

---------

Co-authored-by: Marvin <43185740+Zitzak@users.noreply.github.com>
Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

* Sc 848 task copy fee adaption from topos to dev (#700)

* Abstract projectFeeCollected

* Create tests

* Adapt emit test

* convert flags to bytes32

* setter for default times in Streaming_PP + tests

* test bugfix

* refactor flags into PaymentClientBase

* Adaptations to repo CoC

* more CoC update

* even more CoC

* Update tests

* Explainer text

* refactor IERC20PaymentClientBase errors + bugfix

* abstract functions out + update tests

* address review comments

* add init tests to inheritng modules

* typo fix

* Apply comment suggestions from code review

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

* adapt access mock function naming

* Adapt naming of internal variable

* Adapt comments

* Adapt function naming

* Fmt

* Copy over lib subprojects from dev

* Update src/modules/logicModule/LM_PC_RecurringPayments_v1.sol

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

---------

Co-authored-by: Felix Hieser <47272854+FHieser@users.noreply.github.com>
Co-authored-by: Marvin <43185740+Zitzak@users.noreply.github.com>
Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>
Co-authored-by: 0xNuggan <82726722+0xNuggan@users.noreply.github.com>
Co-authored-by: FHieser <felix_hieser@web.de>
@marvinkruse marvinkruse added the audit a feature needs auditing label Dec 20, 2024
uint dataIdx = 0;

bool hasStart = (uint(flags) & (1 << 1)) != 0;
start = hasStart ? uint(data[dataIdx]) : defaultStart;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If default start and end are 0 you may want to have them as block.timestamp, it seems like this option could be useful as you would usually want the default to be whatever block.timestamp is, not a specific date.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks fo the tip! While it makes sense, we've chosen to go against it since being able to default variables to 0 (and therefore create valid payment Orders, even if they are immediately claimable), seems to me better than introducing block.timestamp values that the user might not expect.
I've created a linear issue to track this, in case we choose to look for a different way to handle it.

/*
| Flag | Name | Disclaimer |
|------|------------|-----------------------------------------------------|
| 0 | orderID | The order id should be a hashed value of an |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing the comment update merged into dev, which reverted this comment. We prob need to rebase/merge from dev.

Just something I noticed while working on another branch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good reminder: please rebase from dev so this is up to date. I can also do this if you want (@0xNuggan) - lmk!

Copy link
Member Author

@marvinkruse marvinkruse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adressing my overall comment of the data array ordering thing I mentioned, to me it looks like that was fully addressed. We probably just need to make sure that each payment processor does it like you did it here (i.e. applies the same principle). May be worth to look into creating a library or a base here for payment processors that handles this?

@marvinkruse
Copy link
Member Author

Tagging @0xNuggan - as this is my PR I can't explicitly tag my comments as requests for changes, so just letting you know via this comment that I submitted my review.

Feel free to close any comments that you feel like you properly addressed and just leave anything open you feel like I should look at again/you have comments on/etc.

@0xNuggan
Copy link
Contributor

Thanks for the review! Addressed the comments

@0xNuggan
Copy link
Contributor

About moving the array logic into a library I agree, but I can't think of a good place right now where we shoudl put it. But worth keeping in mind.

Copy link
Member Author

@marvinkruse marvinkruse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just small typos.

}
if (orderBit == false && processorBit == true) {
// the P_P needs the value, but it's missing in the order
// ==> use default value

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it not be better (safer) if this is an error? This after all is not a case where the order does not provide a value, it is a case where the "order type" is different from what is expected (I mean that if the flag value is different, this is not the same as providing a "0" value and have the PP fill that in with a default value)
For example, if the order says "This is an order with no start and end date", then it is it is better that a PP that is made for streaming orders says "Ok, you probably made a istake sending me this order" rather than have it say "O, ok, then I will just make it a streaming order which starts in 17 days and lasts 189 hours"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's intended behavior, since we want to give the PaymentProcessor to build a valid PaymentOrder using its defaults. I've added a check that the resulting PaymentOrder after "reconstruction" is valid.

marvinkruse and others added 5 commits January 28, 2025 14:22
…ders

* Refactor BuyFor

* Refactor SellOrder

* Apply suggestions from code review

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>

---------

Co-authored-by: Marvin Kruse <marvinkruse@users.noreply.github.com>
@0xNuggan
Copy link
Contributor

Closing this in favor or #717

@0xNuggan 0xNuggan closed this Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

audit a feature needs auditing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants