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

Feature Request: ERC20 Stream Amount Enforcer #2

Open
kamescg opened this issue Nov 24, 2024 · 0 comments
Open

Feature Request: ERC20 Stream Amount Enforcer #2

kamescg opened this issue Nov 24, 2024 · 0 comments

Comments

@kamescg
Copy link
Contributor

kamescg commented Nov 24, 2024

Context

The Universal wallet uses the MetaMask Delegation Framework for handling wallet delegations, authorizations and intents. The framework includes 20+ enforcer smart contract modules for dictating transaction execution capabilities.

Scope

Create a new enforcer module, similar to ERC20TransferAmountEnforcer to stream X tokens over Y time.

The enforcer module should be named ERC20StreamAmountEnforcer.sol and include complete unit test coverage.

User Story

As a user I want to stream 100 USDC to my friends wallets over a 2 week time period.

Enforcer Terms

Terms are how users control enforcer module behavior.

Below is an example the ERC20TransferAmountEnforcer.sol getTermsInfo function.

function getTermsInfo(bytes calldata _terms) public pure returns (address allowedContract_, uint256 maxTokens_) {
    require(_terms.length == 52, "ERC20TransferAmountEnforcer:invalid-terms-length");

    allowedContract_ = address((bytes20(_terms[:20])));
    maxTokens_ = uint256(bytes32(_terms[20:]));
} 

The new ERC20StreamAmountEnforcer.sol should have a similar structure, but with additional epoch terms arguments.

For example you likely want to include startEpoch_ and endEpoch_ to declare when the stream starts and ends.

function getTermsInfo(bytes calldata _terms) public pure returns (address allowedContract_, uint256 maxTokens_) {
    require(_terms.length == 52, "ERC20TransferAmountEnforcer:invalid-terms-length"); // <- Calculate the new length

    allowedContract_ = address((bytes20(_terms[:20])));
    maxTokens_ = uint256(bytes32(_terms[20:]));
    startEpoch_ = uint128(bytes32(_terms[X:Y])); // <- Calculate the correct bytes length and position
    endEpoch_ = uint128(bytes32(_terms[Y:])); // <- Calculate the correct bytes length and position
} 

The startEpoch_ and endEpoch term inputs will then consume arguments like 1733011200 and 1734134400 packed in bytecode format. Which equates to Sunday, December 1, 2024 12:00:00 AM through Saturday, December 14, 2024 12:00:00 AM for a total of 1123200 seconds i.e. the difference between the start and end times.

Hook Validation

Use the ERC20TransferAmountEnforcer.sol _validateAndIncrease function as a starting point for creating the new ERC20StreamAmountEnforcer.sol validation logic.

Below is commented code for where to start.

function _validateAndIncrease(
        bytes calldata _terms,
        bytes calldata _executionCallData,
        bytes32 _delegationHash
    )
        internal
        returns (uint256 limit_, uint256 spent_)
    {
        (address target_,, bytes calldata callData_) = _executionCallData.decodeSingle();

        require(callData_.length == 68, "ERC20TransferAmountEnforcer:invalid-execution-length");

        address allowedContract_;

        /// TODO: Return the new terms arguments.
        (allowedContract_, limit_) = getTermsInfo(_terms);

        require(allowedContract_ == target_, "ERC20TransferAmountEnforcer:invalid-contract");

        require(bytes4(callData_[0:4]) == IERC20.transfer.selector, "ERC20TransferAmountEnforcer:invalid-method");

        /// TODO: Validate the startEpoch_ and endEpoch_ values against the current block timestamp.
        /// TODO: Validate the limit_ value against the current stream total calculation.

        spent_ = spentMap[msg.sender][_delegationHash] += uint256(bytes32(callData_[36:68]));
        require(spent_ <= limit_, "ERC20TransferAmountEnforcer:allowance-exceeded");
    }

Builders Are Rewarded

Create a secure Delegation Framework Enforcer to stream X amount ERC20 tokens over Y time.

The full scope of the issue might not be captured in this ticket. Do your best to think of all security concerns related to the implementation you choose. Full coverage unit tests are expected.

We increase bounty payouts for work that goes above and beyond!

vishwamartur added a commit to vishwamartur/universal-smart-wallet that referenced this issue Nov 26, 2024
Related to district-labs#2

Add ERC20StreamAmountEnforcer module to stream ERC20 tokens over a specified time period.

* Create `ERC20StreamAmountEnforcer.sol` to implement streaming functionality with `getTermsInfo` and `_validateAndIncrease` methods.
* Add unit tests for `ERC20StreamAmountEnforcer.sol` in `test/ERC20StreamAmountEnforcer.t.sol` to ensure complete coverage.
* Update `script/EnforcersDeploy.s.sol` to include deployment of `ERC20StreamAmountEnforcer`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant