Allocates an unique `nonce` and send the transaction to the blockchain. This can fail for a few reasons: - The account doesn't have sufficient Eth to pay for the gas. - The gas price was too low. - Another transaction with the same `nonce` was sent before. This may
(self, transaction: Union[TransactionEstimated, EthTransfer])
| 1157 | return pending.estimate_gas(BLOCK_ID_PENDING) |
| 1158 | |
| 1159 | def transact(self, transaction: Union[TransactionEstimated, EthTransfer]) -> TransactionSent: |
| 1160 | """Allocates an unique `nonce` and send the transaction to the blockchain. |
| 1161 | |
| 1162 | This can fail for a few reasons: |
| 1163 | |
| 1164 | - The account doesn't have sufficient Eth to pay for the gas. |
| 1165 | - The gas price was too low. |
| 1166 | - Another transaction with the same `nonce` was sent before. This may |
| 1167 | happen because: |
| 1168 | - Another application is using the same private key. |
| 1169 | - The node restarted and the `nonce` recovered by |
| 1170 | `discover_next_available_nonce` was too low, which can happend |
| 1171 | because: |
| 1172 | - The transactions currenlty in the pool are not taken into |
| 1173 | account. |
| 1174 | - There was a gap in the `nonce`s of the transaction in the pool, |
| 1175 | once the gap is filled a `nonce` is reused. This is most likely a |
| 1176 | bug. |
| 1177 | """ |
| 1178 | |
| 1179 | # Exposing the JSONRPCClient with a nice name for the instance closure. |
| 1180 | client = self |
| 1181 | |
| 1182 | @dataclass |
| 1183 | class TransactionSlot: |
| 1184 | from_address: Address |
| 1185 | data: Union[SmartContractCall, ByteCode, EthTransfer] |
| 1186 | eth_node: Optional[EthClient] |
| 1187 | extra_log_details: Dict[str, Any] |
| 1188 | startgas: int |
| 1189 | gas_price: int |
| 1190 | nonce: Nonce |
| 1191 | |
| 1192 | def __post_init__(self) -> None: |
| 1193 | self.extra_log_details.setdefault("token", str(uuid4())) |
| 1194 | |
| 1195 | typecheck(self.from_address, T_Address) |
| 1196 | typecheck(self.data, (SmartContractCall, ByteCode, EthTransfer)) |
| 1197 | typecheck(self.startgas, int) |
| 1198 | typecheck(self.gas_price, int) |
| 1199 | typecheck(self.nonce, T_Nonce) |
| 1200 | |
| 1201 | def to_log_details(self) -> Dict[str, Any]: |
| 1202 | log_details = self.data.to_log_details() |
| 1203 | log_details.update(self.extra_log_details) |
| 1204 | log_details.update( |
| 1205 | { |
| 1206 | "node": to_checksum_address(client.address), |
| 1207 | "from_address": to_checksum_address(self.from_address), |
| 1208 | "eth_node": self.eth_node, |
| 1209 | "startgas": self.startgas, |
| 1210 | "gas_price": self.gas_price, |
| 1211 | "nonce": self.nonce, |
| 1212 | } |
| 1213 | ) |
| 1214 | return log_details |
| 1215 | |
| 1216 | # The class is hidden in the method to force this method to be called, |