Example #1
0
 def __init__(self):
     if history:
         self.session = PromptSession(
             history=FileHistory(os.path.join(sys.path[0], '.history')))
     else:
         self.session = PromptSession()
     self.safe_operator = SafeOperator(safe_address, node_url)
     self.prompt_parser = PromptParser(self.safe_operator)
Example #2
0
class SafeCli:
    def __init__(self):
        if history:
            self.session = PromptSession(
                history=FileHistory(os.path.join(sys.path[0], '.history')))
        else:
            self.session = PromptSession()
        self.safe_operator = SafeOperator(safe_address, node_url)
        self.prompt_parser = PromptParser(self.safe_operator)

    def print_startup_info(self):
        print_formatted_text(
            pyfiglet.figlet_format('Gnosis Safe CLI'))  # Print fancy text
        print_formatted_text(
            HTML('<b><ansigreen>Loading Safe information...</ansigreen></b>'))
        self.safe_operator.print_info()

    def get_prompt_text(self):
        return HTML(
            f'<bold><ansiblue>{safe_address}</ansiblue><ansired> > </ansired></bold>'
        )

    def get_bottom_toolbar(self):
        return HTML(
            f'<b><style fg="ansiyellow">network={self.safe_operator.network.name} '
            f'{self.safe_operator.safe_cli_info}</style></b>')

    def loop(self):
        while True:
            try:
                command = self.session.prompt(
                    self.get_prompt_text,
                    auto_suggest=AutoSuggestFromHistory(),
                    bottom_toolbar=self.get_bottom_toolbar,
                    lexer=PygmentsLexer(SafeLexer),
                    completer=SafeCompleter())
                if not command.strip():
                    continue

                self.prompt_parser.process_command(command)
            except EOFError:
                break
            except KeyboardInterrupt:
                continue
            except (argparse.ArgumentError, argparse.ArgumentTypeError,
                    SystemExit):
                pass
Example #3
0
    def loop(self):
        while True:
            try:
                command = self.session.prompt(
                    self.get_prompt_text,
                    auto_suggest=AutoSuggestFromHistory(),
                    bottom_toolbar=self.get_bottom_toolbar,
                    lexer=PygmentsLexer(SafeLexer),
                    completer=SafeCompleter(),
                )
                if not command.strip():
                    continue

                if new_operator := self.parse_operator_mode(command):
                    self.prompt_parser = PromptParser(new_operator)
                    new_operator.refresh_safe_cli_info(
                    )  # ClI info needs to be initialized
                else:
                    self.prompt_parser.process_command(command)
Example #4
0
class SafeCli:
    def __init__(self):
        if history:
            self.session = PromptSession(
                history=FileHistory(os.path.join(sys.path[0], ".history")))
        else:
            self.session = PromptSession()
        self.safe_operator = SafeOperator(safe_address, node_url)
        self.prompt_parser = PromptParser(self.safe_operator)

    def print_startup_info(self):
        print_formatted_text(
            pyfiglet.figlet_format("Gnosis Safe CLI"))  # Print fancy text
        print_formatted_text(
            HTML("<b><ansigreen>Loading Safe information...</ansigreen></b>"))
        self.safe_operator.print_info()

    def get_prompt_text(self):
        if isinstance(self.prompt_parser.safe_operator, SafeRelayOperator):
            return HTML(
                f"<bold><ansiblue>relay-service > {safe_address}</ansiblue><ansired> > </ansired></bold>"
            )
        elif isinstance(self.prompt_parser.safe_operator,
                        SafeTxServiceOperator):
            return HTML(
                f"<bold><ansiblue>tx-service > {safe_address}</ansiblue><ansired> > </ansired></bold>"
            )
        elif isinstance(self.prompt_parser.safe_operator, SafeOperator):
            return HTML(
                f"<bold><ansiblue>blockchain > {safe_address}</ansiblue><ansired> > </ansired></bold>"
            )

    def get_bottom_toolbar(self):
        return HTML(
            f'<b><style fg="ansiyellow">network={self.safe_operator.network.name} '
            f"{self.safe_operator.safe_cli_info}</style></b>")

    def parse_operator_mode(self, command: str) -> Optional[SafeOperator]:
        """
        Parse operator mode to switch between blockchain (default), relay-service, and tx-service
        :param command:
        :return: SafeOperator if detected
        """
        split_command = command.split()
        try:
            if (split_command[0]) == "tx-service":
                print_formatted_text(
                    HTML(
                        "<b><ansigreen>Sending txs to tx service</ansigreen></b>"
                    ))
                return SafeTxServiceOperator(safe_address, node_url)
            elif split_command[0] == "relay-service":
                if len(split_command) == 2 and Web3.isChecksumAddress(
                        split_command[1]):
                    gas_token = split_command[1]
                else:
                    gas_token = None
                print_formatted_text(
                    HTML(
                        f"<b><ansigreen>Sending txs trough relay service gas-token={gas_token}</ansigreen></b>"
                    ))
                return SafeRelayOperator(safe_address,
                                         node_url,
                                         gas_token=gas_token)
            elif split_command[0] == "blockchain":
                print_formatted_text(
                    HTML(
                        "<b><ansigreen>Sending txs to blockchain</ansigreen></b>"
                    ))
                return self.safe_operator
        except SafeServiceNotAvailable:
            print_formatted_text(
                HTML(
                    "<b><ansired>Mode not supported on this network</ansired></b>"
                ))

    def loop(self):
        while True:
            try:
                command = self.session.prompt(
                    self.get_prompt_text,
                    auto_suggest=AutoSuggestFromHistory(),
                    bottom_toolbar=self.get_bottom_toolbar,
                    lexer=PygmentsLexer(SafeLexer),
                    completer=SafeCompleter(),
                )
                if not command.strip():
                    continue

                if new_operator := self.parse_operator_mode(command):
                    self.prompt_parser = PromptParser(new_operator)
                    new_operator.refresh_safe_cli_info(
                    )  # ClI info needs to be initialized
                else:
                    self.prompt_parser.process_command(command)
            except EOFError:
                break
Example #5
0
    def test_safe_cli_happy_path(self):
        accounts = [self.ethereum_test_account, Account.create()]
        account_addresses = [account.address for account in accounts]
        safe_address = self.deploy_test_safe(owners=account_addresses, threshold=2,
                                             initial_funding_wei=self.w3.toWei(1, 'ether')).safe_address
        safe = Safe(safe_address, self.ethereum_client)
        safe_operator = SafeOperator(safe_address, self.ethereum_node_url)
        prompt_parser = PromptParser(safe_operator)
        random_address = Account.create().address

        self.assertEqual(safe_operator.accounts, set())
        prompt_parser.process_command(f'load_cli_owners {self.ethereum_test_account.key.hex()}')
        self.assertEqual(safe_operator.default_sender, self.ethereum_test_account)
        self.assertEqual(safe_operator.accounts, {self.ethereum_test_account})

        prompt_parser.process_command(f'send_ether {random_address} 1')  # No enough signatures
        self.assertEqual(self.ethereum_client.get_balance(random_address), 0)

        value = 123
        prompt_parser.process_command(f'load_cli_owners {accounts[1].key.hex()}')
        prompt_parser.process_command(f'send_ether {random_address} {value}')
        self.assertEqual(self.ethereum_client.get_balance(random_address), value)

        # Change threshold
        self.assertEqual(safe_operator.safe_cli_info.threshold, 2)
        self.assertEqual(safe.retrieve_threshold(), 2)
        prompt_parser.process_command('change_threshold 1')
        self.assertEqual(safe_operator.safe_cli_info.threshold, 1)
        self.assertEqual(safe.retrieve_threshold(), 1)

        # Approve Hash
        safe_tx_hash = Web3.keccak(text='hola')
        self.assertFalse(safe_operator.safe.retrieve_is_hash_approved(accounts[0].address, safe_tx_hash))
        prompt_parser.process_command(f'approve_hash {safe_tx_hash.hex()} {accounts[0].address}')
        self.assertTrue(safe_operator.safe.retrieve_is_hash_approved(accounts[0].address, safe_tx_hash))

        # Remove owner
        self.assertEqual(len(safe_operator.safe_cli_info.owners), 2)
        self.assertEqual(len(safe.retrieve_owners()), 2)
        prompt_parser.process_command(f'remove_owner {accounts[1].address}')
        self.assertEqual(safe_operator.safe_cli_info.owners, [self.ethereum_test_account.address])
        self.assertEqual(safe.retrieve_owners(), [self.ethereum_test_account.address])
Example #6
0
parser.add_argument('node_url', help='Ethereum node url')
args = parser.parse_args()

safe_address = args.safe_address
node_url = args.node_url

session = PromptSession()

if __name__ == '__main__':
    safe_operator = SafeOperator(safe_address, node_url)
    print_formatted_text(
        pyfiglet.figlet_format('Gnosis Safe CLI'))  # Print fancy text
    print_formatted_text(
        HTML(f'<b><ansigreen>Loading Safe information...</ansigreen></b>'))
    safe_operator.print_info()
    prompt_parser = PromptParser(safe_operator)

    def get_prompt_text():
        return HTML(
            f'<bold><ansiblue>{safe_address}</ansiblue><ansired> > </ansired></bold>'
        )

    def bottom_toolbar():
        return HTML(
            f'<b><style fg="ansiyellow">network={safe_operator.network_name} '
            f'{safe_operator.safe_cli_info}</style></b>')

    while True:
        try:
            command = session.prompt(get_prompt_text(),
                                     auto_suggest=AutoSuggestFromHistory(),