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

Add RepoDriverDataProxy #319

Merged
merged 1 commit into from
Oct 2, 2023
Merged

Add RepoDriverDataProxy #319

merged 1 commit into from
Oct 2, 2023

Conversation

CodeSandwich
Copy link
Collaborator

No description provided.

Comment on lines +165 to +168
function _callRepoDriver(bytes memory data) internal returns (bytes memory returnData) {
return caller.callAs(_msgSender(), address(repoDriver), data);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mhm, I guess you spend some time thinking about it. Can we find a more elegant solution here?

The flow currently would be:
1. User calls Caller (signature check)
2. Caller calls RepoDriverDataProxy
3. RepoDriverDataProxy is authorized to call back Caller and calls Caller.
4. callAs is executed to call RepoDriver with calldata
5. RepoDriver using Context calls Drips

Copy link
Collaborator

Choose a reason for hiding this comment

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

I can see the point, why we can't make this contract the public entry point because we would have to verify some signatures.

Did you consider generalizing Caller with a function that allows to extend calldata with information from a DataStore?

Maybe also a bit complex

Copy link
Collaborator

Choose a reason for hiding this comment

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

One other idea could be to implement the signature verification part as a libary and you are using it here as well.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We would basically allow the signature of the calldata with the hash to be replaced with the actual calldata

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The data proxies are the public entry points. The user needs to approve the data proxy address once, but after that they can call the data proxy directly, even in multiple separate transactions. The actual flow is:

  1. User calls Caller.approve(RepoDriverDataProxy)

(then)

  1. User calls RepoDriverDataProxy
  2. RepoDriverDataProxy is authorized to call Caller and calls Caller.
  3. callAs is executed to call RepoDriver with calldata
  4. RepoDriver using Context calls Drips

Copy link
Collaborator

Choose a reason for hiding this comment

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

Mhm, how would you prevent an attacker calling for another user's account after the approval?

Copy link
Collaborator

Choose a reason for hiding this comment

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

setStreams would also allow to withdraw the funds. 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We would basically allow the signature of the calldata with the hash to be replaced with the actual calldata

I was thinking about storing the entire calldata and not just the configuration lists, but it seems less useful. It's more opaque, so it's more difficult to analyze if it's a part of the proposal. At least the storage streams and splits hashes match the hashes used and emitted by Drips, which too helps with transparency. The Drips API relies a lot on sending the same data multiple times, e.g. you send you splits receivers when setting splits, and then on each splitting, it's similar with streams, you send them at least twice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Mhm, how would you prevent an attacker calling for another user's account after the approval?

In _callRepoDriver helper we have this line: return caller.callAs(_msgSender(), address(repoDriver), data);, which feeds the proper sender into Caller. If the sender is an EOA, then Caller will try to act on behalf of that EOA. If the sender is Caller, then the same sender will be looped back to Caller.

Copy link
Collaborator

@xmxanuel xmxanuel Sep 26, 2023

Choose a reason for hiding this comment

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

I see. Then it makes sense since only the _msgSender() is passed

Copy link
Collaborator

@xmxanuel xmxanuel left a comment

Choose a reason for hiding this comment

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

It looks good in general but I have some questions about potential other designs since we have the callback to Caller

Base automatically changed from igor/nft_driver_data_proxy to main October 2, 2023 09:07
@CodeSandwich CodeSandwich merged commit b6cd2f9 into main Oct 2, 2023
2 checks passed
@CodeSandwich CodeSandwich deleted the igor/repo_driver_data_proxy branch October 2, 2023 09:07
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

Successfully merging this pull request may close these issues.

2 participants