Beispiel #1
0
    def send_transaction(
        self, safe_address: str, safe_tx: SafeTx
    ) -> RelaySentTransaction:
        url = urljoin(self.base_url, f"/api/v1/safes/{safe_address}/transactions/")
        signatures = []
        for i in range(len(safe_tx.signatures) // 65):
            v, r, s = signature_split(safe_tx.signatures, i)
            signatures.append(
                {
                    "v": v,
                    "r": r,
                    "s": s,
                }
            )

        data = {
            "to": safe_tx.to,
            "value": safe_tx.value,
            "data": safe_tx.data.hex() if safe_tx.data else None,
            "operation": safe_tx.operation,
            "gasToken": safe_tx.gas_token,
            "safeTxGas": safe_tx.safe_tx_gas,
            "dataGas": safe_tx.base_gas,
            "gasPrice": safe_tx.gas_price,
            "refundReceiver": safe_tx.refund_receiver,
            "nonce": safe_tx.safe_nonce,
            "signatures": signatures,
        }
        response = requests.post(url, json=data)
        if not response.ok:
            raise BaseAPIException(f"Error posting transaction: {response.content}")
        else:
            return RelaySentTransaction(response.json())
Beispiel #2
0
    def send_transaction(self, safe_address: str, safe_tx: SafeTx) -> RelaySentTransaction:
        url = urljoin(self.base_url, f'/api/v1/safes/{safe_address}/transactions/')
        signatures = []
        for i in range(len(safe_tx.signatures) // 65):
            v, r, s = signature_split(safe_tx.signatures, i)
            signatures.append(
                {
                    "v": v,
                    "r": r,
                    "s": s,
                }
            )

        data = {
            'to': safe_tx.to,
            'value': safe_tx.value,
            'data': safe_tx.data.hex() if safe_tx.data else None,
            'operation': safe_tx.operation,
            'gasToken': safe_tx.gas_token,
            'safeTxGas': safe_tx.safe_tx_gas,
            'dataGas': safe_tx.base_gas,
            'gasPrice': safe_tx.gas_price,
            'refundReceiver': safe_tx.refund_receiver,
            'nonce': safe_tx.safe_nonce,
            'signatures': signatures,
        }
        response = requests.post(url, json=data)
        if not response.ok:
            raise BaseAPI(f'Error posting transaction: {response.content}')
        else:
            return RelaySentTransaction(response.json())
Beispiel #3
0
    def parse_signature(
        cls,
        signatures: EthereumBytes,
        safe_tx_hash: EthereumBytes,
        ignore_trailing: bool = True,
    ) -> List["SafeSignature"]:
        """
        :param signatures: One or more signatures appended. EIP1271 data at the end is supported.
        :param safe_tx_hash:
        :param ignore_trailing: Ignore trailing data on the signature. Some libraries pad it and add some zeroes at
            the end
        :return: List of SafeSignatures decoded
        """
        if not signatures:
            return []
        elif isinstance(signatures, str):
            signatures = HexBytes(signatures)

        signature_size = 65  # For contract signatures there'll be some data at the end
        data_position = len(
            signatures
        )  # For contract signatures, to stop parsing at data position

        safe_signatures = []
        for i in range(0, len(signatures), signature_size):
            if (
                i >= data_position
            ):  # If contract signature data position is reached, stop
                break

            signature = signatures[i : i + signature_size]
            if ignore_trailing and len(signature) < 65:
                # Trailing stuff
                break
            v, r, s = signature_split(signature)
            signature_type = SafeSignatureType.from_v(v)
            safe_signature: "SafeSignature"
            if signature_type == SafeSignatureType.CONTRACT_SIGNATURE:
                if s < data_position:
                    data_position = s
                contract_signature_len = int.from_bytes(
                    signatures[s : s + 32], "big"
                )  # Len size is 32 bytes
                contract_signature = signatures[
                    s + 32 : s + 32 + contract_signature_len
                ]  # Skip array size (32 bytes)
                safe_signature = SafeSignatureContract(
                    signature, safe_tx_hash, contract_signature
                )
            elif signature_type == SafeSignatureType.APPROVED_HASH:
                safe_signature = SafeSignatureApprovedHash(signature, safe_tx_hash)
            elif signature_type == SafeSignatureType.EOA:
                safe_signature = SafeSignatureEOA(signature, safe_tx_hash)
            elif signature_type == SafeSignatureType.ETH_SIGN:
                safe_signature = SafeSignatureEthSign(signature, safe_tx_hash)

            safe_signatures.append(safe_signature)
        return safe_signatures
Beispiel #4
0
    def __init__(self, signature: EthereumBytes, safe_tx_hash: EthereumBytes,
                 ethereum_client: EthereumClient):
        assert len(signature) > 65, 'Signature must be at least 65'

        # v = signature type, r = contract, s = offset of dynamic signature data
        self.v, self.r, self.s = signature_split(signature)
        assert self.v == 0, 'v must be 0'

        self.signature = HexBytes(signature)
        self.safe_tx_hash = safe_tx_hash
        self.ethereum_client = ethereum_client
        self.owner = checksum_encode(self.r)
        self.ok = self._check_signature()
    def parse_signature(cls, signatures: EthereumBytes,
                        safe_tx_hash: EthereumBytes) -> List['SafeSignature']:
        """
        :param signatures: One or more signatures appended. EIP1271 data at the end is supported.
        :param safe_tx_hash:
        :return: List of SafeSignatures decoded
        """
        if not signatures:
            return []
        elif isinstance(signatures, str):
            signatures = HexBytes(signatures)

        signature_size = 65  # For contract signatures there'll be some data at the end
        data_position = len(
            signatures
        )  # For contract signatures, to stop parsing at data position

        safe_signatures = []
        for i in range(0, len(signatures), signature_size):
            if i >= data_position:  # If contract signature data position is reached, stop
                break

            signature = signatures[i:i + signature_size]
            v, r, s = signature_split(signature)
            signature_type = SafeSignatureType.from_v(v)
            safe_signature: 'SafeSignature'
            if signature_type == SafeSignatureType.CONTRACT_SIGNATURE:
                if s < data_position:
                    data_position = s
                contract_signature_len = int.from_bytes(
                    signatures[s:s + 32], 'big')  # Len size is 32 bytes
                contract_signature = signatures[
                    s + 32:s + 32 +
                    contract_signature_len]  # Skip array size (32 bytes)
                safe_signature = SafeSignatureContract(signature, safe_tx_hash,
                                                       contract_signature)
            elif signature_type == SafeSignatureType.APPROVED_HASH:
                safe_signature = SafeSignatureApprovedHash(
                    signature, safe_tx_hash)
            elif signature_type == SafeSignatureType.EOA:
                safe_signature = SafeSignatureEOA(signature, safe_tx_hash)
            elif signature_type == SafeSignatureType.ETH_SIGN:
                safe_signature = SafeSignatureEthSign(signature, safe_tx_hash)

            safe_signatures.append(safe_signature)
        return safe_signatures
Beispiel #6
0
 def __init__(self, signature: EthereumBytes, safe_tx_hash: EthereumBytes):
     self.signature = HexBytes(signature)
     self.safe_tx_hash = HexBytes(safe_tx_hash)
     self.v, self.r, self.s = signature_split(self.signature)
Beispiel #7
0
 def __init__(self, signature: EthereumBytes, safe_tx_hash: EthereumBytes):
     self.signature = HexBytes(signature)
     self.v, self.r, self.s = signature_split(self.signature)
     self.signature_type = SafeSignatureType.from_v(self.v)
     self.owner = self.decode_owner(self.v, self.r, self.s, safe_tx_hash)