Giter VIP home page Giter VIP logo

delegatable-sol's People

Contributors

danfinlay avatar fifteen42 avatar gkoum-7 avatar kamescg avatar mcoso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

delegatable-sol's Issues

Delegatable swallows error messages

The current execute method only checks success/failure, and so a contract's error messages are lost when inheriting from the current version of Delegatable.

๐Ÿ”— Enforcer: Governance Proposal Outcomes

As a developer I want a DAOProposalEnforcer to control transaction execution conditions depending on the outcome of on-chain proposal outcomes i.e. pass or no-pass.

Why

I want to unlock DAO contributor permissions depending on the outcome of on-chain proposals. This includes but is not limited to payments, subscriptions and accessing off-chain cryptographic services like LIT protocol.

How

Multiple governance contracts exist (Compound, OpenZeppelin, Moloch, etc...) and each one should probably have a unique enforcer. The V1 DAOProposalEnforcer smart contract should be minimal and only take into account the pass or no-pass results and not be concerned about total number/percentage of votes.

BlockNumberEnforcer: optimize terms bytecode

The current BlockNumberEnforcer.sol smart contract can be optimized further. Specifically, the term field size can be decreased.

BlockNumberEnforcer.sol Smart Contract Code

Current terms bytecode

  • logicOperator = uint128
  • blockExpiration = uint128

Expected terms bytecode

  • logicOperator = uint8
  • blockExpiration = uint64

Term Deconstruction

Review the BlockNumberEnforcer unit tests for a better understanding of the current enforcer term requirements.

/* bytes ---------------------------------------------------------- */
"0x0000000000000000000000000000000000000000000000000000000000000000",

/* uint128 ------------------------ uint128 ------------------------ */
"0x00000000000000000000000000000000 00000000000000000000000000000000",

// The bytes is split in the middle.
// 0: Controls the logicOperator using a boolean flag
// 1: Compared to the block.number at run-time

/* uint128 | before (false) ------- uint128 | block.number 0 ------- */
"0x00000000000000000000000000000000 00000000000000000000000000000000",

/* uint128 | after (true) --------- uint128 | block.number 10 ------ */
"0x00000000000000000000000000000001 0000000000000000000000000000000a",

Solidity Reference

uint128 logicOperator = BytesLib.toUint128(terms, 0);
uint128 blockExpiration = BytesLib.toUint128(terms, 16);

if (logicOperator == 0) {
    if (blockExpiration < block.number) {
        return true;
    } else {
        revert("BlockNumberEnforcer:expired-delegation");
    }
} else {
    if (blockExpiration > block.number) {
        return true;
    } else {
        revert("BlockNumberEnforcer:early-delegation");
    }
}

The logicOperator is a basic boolean flag and can be condensed to a uint8.

The blockExpiration can be compressed to a uint64 for a max block.number comparison of 4294967295


Bytecode Reference

Number of bits Min. value Max. value
8 bit 0 255
16 bit 0 65535
32 bit 0 4294967295

1 | bytes2 | uint16
0x0001

1 | bytes4 | uint32
0x00000001

1 | bytes8 | uint64
0x0000000000000001โ€จ

1 | bytes16 | uint128
0x00000000000000000000000000000001

1 | bytes32 | uint256
0x0000000000000000000000000000000000000000000000000000000000000001

๐Ÿ”— Enforcer: Uniswap V3 TWAP

As a developer I want a UniswapV3TWAPEnforcer price oracle to control transaction execution conditions.

Why

I may want to execute financial and non-financial transactions using a decentralized price oracle state.

How

Explore the potential transaction execution conditionals that can be created using Uniswap V3 TWAP i.e. over, under, length of time, etc...

Ensure caveat enforcers are capable of requiring payment

A user might want to charge for using a permission they have, and this should be supported.

Examples:

This may require a schema change for caveat enforcers which allow them to accept tx-contextual additional information from the caller, to provide things like additional delegations enabling withdrawing a payment, for example.

Add support for eip4337 style initCodes in delegations

EIP 4337 introduced a counterfactual Wallet deployer pattern using initCodes, which allows one to send a transaction from an account that doesn't exist on chain until the tx is processed.

I bet we could support the same initCode + Wallet deployer pattern within the delegation schema to offer some potential. If nothing else, a counterfactual contract account could both receive and issue a delegation.

I'm not sure if there's any benefit for a 4337-style contract account to be the "end of the line" receiver of a delegation, since depending on how the UserOperation was constructed, they could already (under 4337) deploy the contract as part of calling the method.

But, supporting intermediate delegations seems like a good long term feature, so I'm opening this as a possible future enhancement.

Add allowed recipient enforcer

With the new trusted relay method of importing, a single delegatable validator can relay for many contracts. This means we should now also bundle an allowed set of tx.to values. Should be just like the 4byte method allow caveat but split on 20bytes and cast to address instead of 4bytes.

Create delegatable WETH

Just saying: Hex for 10 is A, and so we could be WETHA, and say stuff like "WETHA the WETHA be good, or WETHA the WETHA be bad, we'll be togetha whateva the WETHA..."

Should root delegations work in a chain?

Summary of current status

There are two types of delegation:

  1. Root delegations, where the authority field is equal to 0.
  2. Chained delegations, where the authority field is equal to the hash of a delegation whose delegate is the signer of this one.

All delegation chains start with type 1, and all subsequent delegations in a chain are type 2.

Question

Should type 1 delegations work in other positions in the delegation chain?

Example:

  • Alice signs a type 1 to Bob
  • Bob signs a type 1 to Carol
  • Should Carol be able to invoke methods as Alice?

We could also consider this as a new type, "type 3" delegations, where the invoke method is also delegated, and so delegations can be redeemed by the holder.

Considerations

A type 3 delegation could be seen as either a security issue or as a great scalable composibility benefit.

Issue #7 would be likely to introduce this feature/vulnerability inadvertently if done incorrectly.

Pros

  • Fewer delegation signatures would be needed to maintain a trust graph.
  • Could enable more spontaneous enablement, if done deliberately.

Cons

  • Leaking authority from one context into another one can be a form of context collapse, a sort of "mixing the books", and could result in delegations being used in ways they weren't intended.

Examples:

  • Today, a person issuing an allowance from their own account is strictly issuing access to their own tokens of that type. Those allowances can be delegated too, but can never draw from another user's current balance without an explicit delegation.
  • With this change, a person could issue hypothetical allowances that could later be backed by someone else issuing them allowances.

Part of this comes down to what is being treated as the "object" of the delegation (in a principle of appropriate boundaries sense): If a user is delegating as much of this contract's authority as they can ever have, then this makes sense. If the contract is itself exposing multiple objects of authority which are conceptually distinct, then it makes sense for each user's delegation chain to always have a distinct root.

This may just be a per-application design decision. Some applications might be ones where the thing managed is simpler, and so flatter delegation graphs make sense, while others are meant to be more granular, and more tightly controlled.

Another example: In a phishing report registry, we might want to accept general "claims of being a phisher", and "claims of trusting other reporters", and in that kind of case maintaining "separate books" seems a bit less critical, and it's more important to have good roots of trust, to build out a great list of phishers.

To implement this behavior, this line would be changed to use _msgSender() instead of msg.sender, and then any invocations could be initiated by anyone delegated rights to this contract by the sender.

Method-restriction caveats could still apply, so I partly think "leaving the system more open ended at the low levels" might be the right choice, and just kinda normalize using method restrictions whenever they might apply.

โ›“๏ธ DelegatableCore: Hooks To Lift Signers

As a developer I want (I think) severals hooks in the DelegatableCore.sol invoke method to add custom logic for parsing the transaction directly during execution.

Why

During execution I want to hook into the signing verification process and validate addresses reach certain criteria.

How

Add hooks in the _invoke method.

Potential Hook Names

  • _hookDelegationSigner()
  • _hookInvoke

external function invoke() returns always false

warning[5667]: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
   --> lib/delegatable-sol/contracts/Delegatable.sol:128:18:
    |
128 |         returns (bool success)
    |                  ^^^^^^^^^^^^

Thesis: invoke function will always return false.
Reasoning: success is declared, returned, but never assigned to.

function invoke(SignedInvocation[] calldata signedInvocations)
external
override
returns (bool success)
{
for (uint256 i = 0; i < signedInvocations.length; i++) {
SignedInvocation calldata signedInvocation = signedInvocations[i];
address invocationSigner = verifyInvocationSignature(
signedInvocation
);
_enforceReplayProtection(
invocationSigner,
signedInvocations[i].invocations.replayProtection
);
_invoke(signedInvocation.invocations.batch, invocationSigner);
}
}

Solution, maybe:

success = i == 0 ?
 _invoke(signedInvocation.invocations.batch, invocationSigner) : success && _invoke(signedInvocation.invocations.batch, invocationSigner);

Issues with Delegatable-based Session-Key

Currently, we are considering the possibility of using Delegatable as a Session Key solution for our Contract Wallet (UniPass), but we have some questions that we would like to discuss with you.

1. Gas cost

I noticed that Delegatable is advancing the integration with 4337, delegatable-4337.

At present, 4337 already brings a lot of extra gas overhead, and Delegatable will too. The combination of the two may cause extra gas overhead that users cannot afford.

The question is, what benefits does 4337 compatibility bring to Delegatable? In my opinion, the greatest usefulness of EIP4337 is that there is a mechanism to help users submit transactions after the smart wallet operator stops, but I think full compatibility with 4337 will restrict the ability of Delegatable.

2. CallData & State

Currently, in order to save gas, Delegatable signs the delegation off-chain, and then places it in calldata every time it is used. This gas saving is useful for ETH, but for Layer2, it is likely to cause more gas costs, because Layer2โ€™s calldata need to submit to Layer1.

Perhaps Delegatable can consider adding some mechanisms to adapt to Layer 2. For example, after a Delegation is used for the first time, it will be recorded in the on-chain state, and subsequent uses do not need to continue to occupy calldata. This can be used as an option for contracts that want to integrate Delegatable.

3. Single delegation for multiple txs

The current Delegatable has a corresponding delegation for each transaction, which makes it necessary for the delegate to reuse the same Delegation sequence when he wants to use the delegation to execute multiple transactions, which greatly increases the size of the calldata.

Perhaps the Invocation can be changed to the following:

struct Invocation {
  Transaction[] transactions;
  SignedDelegation[] authority;
}

4. Other issues

  • In the current design of Delegatable, the format of the delegate can only be an address, but in fact, we can give the delegation to a Passkey or Email (verified by DKIM), and the address format restricts the use of new authentication methods.
  • The current CaveatEnforcer can add some verification:
    • firstly, post-verification, that is, some verification of the execution result can be performed.

    • second, the delegate that specifically made this invocation can be used as an input argument, and some verification can also be performed, for example, check that the delegate should own a certain NFT or be a member of a certain Dao.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.