|
| 1 | +import sys |
| 2 | +import time |
| 3 | +from typing import List |
| 4 | + |
| 5 | +from web3 import Web3 |
| 6 | + |
| 7 | +from sdk.contracts.base_wrapper import BaseWrapper |
| 8 | +from sdk.registry import Registry |
| 9 | + |
| 10 | + |
| 11 | +# TODO: test when other called SC wrappers will be written and callable |
| 12 | +class MultiSig(BaseWrapper): |
| 13 | + """ |
| 14 | + Contract for handling multisig actions |
| 15 | +
|
| 16 | + Attributes: |
| 17 | + web3: Web3 |
| 18 | + Web3 object |
| 19 | + registry: Registry |
| 20 | + Registry object |
| 21 | + address: str |
| 22 | + Contract's address |
| 23 | + abi: list |
| 24 | + Contract's ABI |
| 25 | + wallet: Wallet |
| 26 | + Wallet object to sign transactions |
| 27 | + """ |
| 28 | + |
| 29 | + def __init__(self, web3: Web3, registry: Registry, address: str, abi: list, wallet: 'Wallet' = None): |
| 30 | + super().__init__(web3, registry, wallet=wallet) |
| 31 | + self.web3 = web3 |
| 32 | + self.address = address |
| 33 | + self._contract = self.web3.eth.contract(self.address, abi=abi) |
| 34 | + self.__wallet = wallet |
| 35 | + |
| 36 | + def submit_or_confirm_transaction(self, destination: str, tx_data: str, value: str = '0') -> str: |
| 37 | + """ |
| 38 | + Allows an owner to submit and confirm a transaction. |
| 39 | + If an unexecuted transaction matching `tx_object` exists on the multisig, adds a confirmation to that tx ID. |
| 40 | + Otherwise, submits the `tx_object` to the multisig and add confirmation. |
| 41 | +
|
| 42 | + Parameters: |
| 43 | + destination: str |
| 44 | + tx_object: str |
| 45 | + Transaction data hex string |
| 46 | + value: str |
| 47 | + Returns: |
| 48 | + str |
| 49 | + Transaction hash |
| 50 | + """ |
| 51 | + # sure that data start with 0x |
| 52 | + data = '0x' + tx_data.lstrip('0x') |
| 53 | + transaction_count = self._contract.functions.getTransactionCount( |
| 54 | + True, True).call() |
| 55 | + |
| 56 | + for tx_id in reversed(range(transaction_count)): |
| 57 | + transaction = self._contract.functions.transactions( |
| 58 | + tx_id + 1).call() |
| 59 | + if transaction[2] == data and transaction[0] == destination and transaction[1] == value and not transaction[3]: |
| 60 | + func_call = self._contract.functions.confirmTransaction( |
| 61 | + tx_id + 1) |
| 62 | + return self.__wallet.send_transaction(func_call) |
| 63 | + |
| 64 | + func_call = self._contract.functions.submitTransaction( |
| 65 | + destination, value, tx_data) |
| 66 | + |
| 67 | + return self.__wallet.send_transaction(func_call) |
| 68 | + |
| 69 | + def is_owner(self, owner: str) -> bool: |
| 70 | + return self._contract.functions.isOwner(owner).call() |
| 71 | + |
| 72 | + def get_owners(self) -> List[str]: |
| 73 | + return self._contract.functions.getOwners().call() |
| 74 | + |
| 75 | + def get_required(self) -> int: |
| 76 | + return self._contract.functions.required().call() |
| 77 | + |
| 78 | + def get_internal_required(self) -> int: |
| 79 | + return self._contract.functions.internalRequired().call() |
| 80 | + |
| 81 | + def get_transaction_count(self) -> int: |
| 82 | + return self._contract.functions.transactionCount().call() |
| 83 | + |
| 84 | + def replace_owner(self, owner: str, new_owner: str) -> str: |
| 85 | + func_call = self._contract.functions.replaceOwner(owner, new_owner) |
| 86 | + |
| 87 | + return self.__wallet.send_transaction(func_call) |
| 88 | + |
| 89 | + def get_transaction(self, i: int) -> dict: |
| 90 | + destination, value, data, executed = self._contract.functions.transactions( |
| 91 | + i).call() |
| 92 | + |
| 93 | + confirmations = [] |
| 94 | + for owner in self.get_owners(): |
| 95 | + if self._contract.functions.confirmations(i, owner).call(): |
| 96 | + confirmations.append(owner) |
| 97 | + |
| 98 | + return { |
| 99 | + 'destination': destination, |
| 100 | + 'data': data, |
| 101 | + 'executed': executed, |
| 102 | + 'confirmations': confirmations, |
| 103 | + 'value': value |
| 104 | + } |
| 105 | + |
| 106 | + def get_transactions(self) -> List[dict]: |
| 107 | + tx_count = self.get_transaction_count() |
| 108 | + res = [] |
| 109 | + for i in range(tx_count): |
| 110 | + res.append(self.get_transaction(i)) |
| 111 | + |
| 112 | + return res |
0 commit comments