Skip to content

Commit 2bbd623

Browse files
authored
feat(CLI): create new (#11)
1 parent bef44f7 commit 2bbd623

3 files changed

Lines changed: 83 additions & 32 deletions

File tree

ruffsack/__main__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
1+
import math
2+
13
import click
4+
from ape.cli import ConnectedProviderCommand, account_option
5+
from ape.types import AddressType
6+
7+
from ruffsack import Factory
8+
from ruffsack.packages import MANIFESTS
29

310

411
@click.group()
512
def cli():
613
"""Manage Ruffsack wallets (https://ruffsack.xyz)"""
14+
15+
16+
@cli.command(cls=ConnectedProviderCommand)
17+
@account_option()
18+
@click.option(
19+
"--version",
20+
default=str(max(MANIFESTS)),
21+
help="Version to use when creating the multisig. Defaults to latest in SDK.",
22+
)
23+
@click.option(
24+
"--threshold",
25+
type=int,
26+
default=0,
27+
help="The value to use for the wallet's threshold. "
28+
"Defaults to half the number of signers (rounding up)",
29+
)
30+
@click.option("--tag", default=None)
31+
@click.argument("signers", nargs=-1)
32+
def new(version, threshold, tag, signers, account):
33+
"""Create a new Ruffsack multisig wallet on the given network"""
34+
from ape import accounts, convert
35+
36+
signers = [
37+
accounts.load(s) if s in accounts.aliases else convert(s, AddressType)
38+
for s in signers
39+
]
40+
41+
if len(signers) == 0:
42+
raise click.UsageError("Must provider at least one signer")
43+
44+
elif len(signers) > 11:
45+
raise click.UsageError("Cannot use Ruffsack with more than 11 signers")
46+
47+
if not threshold:
48+
threshold = math.ceil(len(signers) / 2)
49+
50+
elif 0 > threshold or threshold > len(signers):
51+
raise click.UsageError("Cannot use a value higher than number of signers")
52+
53+
factory = Factory()
54+
sack = factory.new(
55+
signers,
56+
threshold=threshold,
57+
version=version,
58+
tag=tag,
59+
sender=account,
60+
)
61+
click.secho(f"New Ruffsack deployed: {sack.address}", fg="yellow")

ruffsack/factory.py

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@
1212

1313
class Factory(ManagerAccessMixin):
1414
def __init__(self, address: AddressType | None = None):
15-
# TODO: Refactor to use deterministic deployment address
16-
self.address = address or self.local_project.RuffsackFactory.deployments[0]
15+
if address:
16+
self.address = address
17+
18+
else:
19+
# TODO: Refactor to use deterministic deployment address
20+
self.address = self.local_project.RuffsackFactory.deployments[0].address
21+
1722
self._cached_releases: dict[Version, "ContractInstance"] = dict()
1823
self._last_cached: int = 0
1924

@@ -29,7 +34,9 @@ def contract(self) -> "ContractInstance":
2934
@property
3035
def releases(self) -> dict[Version, "ContractInstance"]:
3136
if (latest_block := self.chain_manager.blocks.head.number) > self._last_cached:
32-
for log in self.contract.NewRelease.range(self._last_cached, latest_block):
37+
for log in self.contract.NewRelease.range(
38+
self._last_cached, latest_block + 1
39+
):
3340
self._cached_releases[Version(log.version)] = (
3441
self.chain_manager.contracts.instance_at(
3542
log.implementation,
@@ -45,7 +52,7 @@ def new(
4552
signers: list[AddressType],
4653
threshold: int | None = None,
4754
version: Version | str | None = None,
48-
salt: str | bytes | None = None,
55+
tag: str | None = None,
4956
**txn_args,
5057
) -> "ContractInstance":
5158
if threshold is None:
@@ -54,35 +61,20 @@ def new(
5461
if isinstance(version, str):
5562
version = Version(version)
5663

57-
if salt is not None:
58-
if version is None:
59-
version = Version(self.contract.last_version())
60-
61-
receipt = self.contract.new(
62-
signers,
63-
threshold,
64-
str(version),
65-
salt,
66-
**txn_args,
67-
)
64+
args = [signers, threshold]
65+
if tag is not None:
66+
args.extend([str(version) if version else "stable", tag])
6867

6968
elif version is not None:
70-
receipt = self.contract.new(
71-
signers,
72-
threshold,
73-
str(version),
74-
**txn_args,
75-
)
69+
args.append(str(version))
7670

77-
else:
78-
receipt = self.contract.new(
79-
signers,
80-
threshold,
81-
**txn_args,
82-
)
83-
version = Version(self.contract.last_version())
71+
if version is None:
72+
version = Version(self.contract.last_release())
73+
74+
receipt = self.contract.new(*args, **txn_args)
8475

8576
new_ruffsack_address = receipt.events[0].new_sack
77+
# TODO: Refactor to use SDK internal type? (subclassing `AccountAPI`)
8678
return self.chain_manager.contracts.instance_at(
8779
new_ruffsack_address,
8880
contract_type=PackageType.SINGLETON(version),

uv.lock

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)