feat: add delegates - #41
Conversation
880928f to
1f62100
Compare
d28f656 to
74baeec
Compare
antazoey
left a comment
There was a problem hiding this comment.
Pretty great PR! I had some nits.
Is there anything particular you want me to verify? I can take it for a spin soon.
| for delegates in self.client.get_delegates().values(): | ||
| yield from delegates | ||
|
|
||
| def propose_safe_tx( |
There was a problem hiding this comment.
the propose cli method could probably be refactored to utilize this now
There was a problem hiding this comment.
Looked into this, but seems more complicated than I'm willing to deal with now
Think I will try to refactor that CLI method later
If you can try adding and removing a delegate, I've been doing it and it works for me but curious on the experience (which may improve with ApeWorX/ape#1966) |
|
Thoughts from testing:
but I am wondering if we would wanto enrich those values, like if they are known accounst, use aliases here? btw I would fix the second and fourth items and make tickets for the first and third items |
|
Related to those, on both add / remove, if you slightly mispell the alias, it just comes back as None and tell you to use a keyfile account again and i was confused for a bit. i think most of the annoyance stems from the submitter callback |
|
ohhh , one more thing i just noticed. When i do: for a safe with no delegates, it outputs: feedback: |
Yes I want to do this too. There are some ways to deploy a safe at the same address on all networks, I have done this for one of our safes but not the other. But still need to detect if it is deployed on the network you wish to use |
I am working on a PR for core that'll bypass this issue, and then I'll make it accept a wider range of inputs so you can be more specific with it |
Agree, should really just be INFO |
|
@fubuloubu the signing features we wanted are in Core now, we should update this and get this out. |
74baeec to
7439a4b
Compare
|
|
2, 3, and 4 solved with 2148cf0, I made issues for the 1st one |
6a7537d to
3710d25
Compare
| } | ||
| return self.safe_tx_def(**safe_tx) | ||
|
|
||
| def all_delegates(self) -> Iterator[AddressType]: |
There was a problem hiding this comment.
generators are bad ux in interactive sessions.
change to delegates property and make it return a list or a dict of address->label
moreover, since delegates is a client feature, it should only live in SafeClient exclusively, so might as well remove it from SafeAccount.
There was a problem hiding this comment.
we can have a method for the iterator such as get_all_delegates() and have the delegates property use the iterator to make a dict
There was a problem hiding this comment.
my other point is delegates is not a feature of a safe wallet, but rather a feature of a safe backend api, this it should not be in SafeAccount at all, but rather in SafeClient.
it's completely off-chain and only affects the backend accepting txs from non-owners.
| gas = result.get("safeTxGas") | ||
| return int(HexBytes(gas).hex(), 16) | ||
|
|
||
| def get_delegates(self) -> Dict[AddressType, List[AddressType]]: |
There was a problem hiding this comment.
labels got lost along the way, they are quite useful imo. the current anonymous structure is not immediately clear. maybe it should be a dict of delegates to their metadata like label and delegator. currently delegator is the key, but it's not the primary info here. or it could be a list[dataclass] where str() casts to address.
|
|
||
| return delegates | ||
|
|
||
| def add_delegate(self, delegate: AddressType, label: str, delegator: AccountAPI): |
There was a problem hiding this comment.
instead of delegator we can say owner, should be less confusing.
5e99cd1 to
318f4e9
Compare
| """ | ||
| Add a delegate for a signer in a Safe | ||
| """ | ||
| delegate = cli_ctx.conversion_manager.convert(delegate, AddressType) |
There was a problem hiding this comment.
this could be part of the argument:
@click.argument("delegate", callback=lambda ctx, _, val: ctx.obj.conversion_manager.convert(delegate, AddressType))| @delegates.command(cls=ConnectedProviderCommand) | ||
| @safe_cli_ctx() | ||
| @safe_option | ||
| @click.argument("delegate", type=ChecksumAddress) |
There was a problem hiding this comment.
type=ChecksumAddress is a bit wrong, since this implicitly handles ENS strings and such.
| @delegates.command(cls=ConnectedProviderCommand) | ||
| @safe_cli_ctx() | ||
| @safe_option | ||
| @click.argument("delegate", type=ChecksumAddress) |
There was a problem hiding this comment.
same here re: the type is incorrect (since ENS domains work because we are converting them?)
this may just all be better with the callback validating the value into an address beforehand.
| } | ||
| return self.safe_tx_def(**safe_tx) | ||
|
|
||
| def all_delegates(self) -> Iterator[AddressType]: |
There was a problem hiding this comment.
we can have a method for the iterator such as get_all_delegates() and have the delegates property use the iterator to make a dict
| safe_tx: SafeTx, | ||
| submitter: Union[AccountAPI, AddressType, str, None] = None, | ||
| sigs_by_signer: Optional[dict[AddressType, MessageSignature]] = None, | ||
| contractTransactionHash: Optional[SafeTxID] = None, |
There was a problem hiding this comment.
a note for why this has to be camelCase would be helpful
| data = response.json() | ||
|
|
||
| for delegate_info in map(DelegateInfo.model_validate, data.get("results", [])): | ||
| if delegate_info.delegator not in delegates: |
There was a problem hiding this comment.
idea: we can use defaultdict again here
| "delegate": delegate, | ||
| "delegator": delegator.address, | ||
| "label": label, | ||
| "signature": sig.encode_rsv().hex(), |
There was a problem hiding this comment.
warning: when we move to web3.py 7.0 series, this will not longer have a 0x prefix. I have been trying to use different ways of going to hex-str now in preparation for this
318f4e9 to
18a5a1d
Compare
Co-authored-by: antazoey <admin@antazoey.me>
291f601 to
4cdc386
Compare
What I did
Adds support for delegates to the Client classes (including MockClient), the CLI (via
ape safe delegates ...), as well as to the main accounts class (SafeAccount.propose_safe_txandSafeAccount.propose)fixes: #16
How I did it
How to verify it
Checklist
- [ ] Documentation has been updated