delegatable / delegatable-sol Goto Github PK
View Code? Open in Web Editor NEWThis project forked from kamescg/delegatable-sol
Counterfactual revocable-delegation
Home Page: https://delegatable.org
This project forked from kamescg/delegatable-sol
Counterfactual revocable-delegation
Home Page: https://delegatable.org
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.
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.
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.
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.
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
uint128
uint128
Expected terms
bytecode
uint8
uint64
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",
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
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
As a developer I want a UniswapV3TWAPEnforcer
price oracle to control transaction execution conditions.
I may want to execute financial and non-financial transactions using a decentralized price oracle state.
Explore the potential transaction execution conditionals that can be created using Uniswap V3 TWAP i.e. over, under, length of time, etc...
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.
So any diamond can add it to their contract.
Should use diamond storage so it doesn't collide with other diamond contract storage.
https://twitter.com/mudgen/status/1557823174062096386
There are two basic ways:
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.
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.
ethpm, npm, submodule, whatever!
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..."
Was not migrated from the original repo:
https://github.com/delegatable/delegatable-eth/blob/main/packages/hardhat/contracts/caveat-enforcers/RevocationEnforcer.sol
There are two types of delegation:
authority
field is equal to 0
.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.
Should type 1 delegations work in other positions in the delegation chain?
Example:
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.
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
Cons
Examples:
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.
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.
During execution I want to hook into the signing verification process and validate addresses reach certain criteria.
Add hooks in the _invoke
method.
Potential Hook Names
_hookDelegationSigner()
_hookInvoke
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.
delegatable-sol/contracts/Delegatable.sol
Lines 125 to 141 in d12016f
Solution, maybe:
success = i == 0 ?
_invoke(signedInvocation.invocations.batch, invocationSigner) : success && _invoke(signedInvocation.invocations.batch, invocationSigner);
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.
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.
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.
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;
}
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.