【Try/Catch】
try/catch
用於確認外部執行函數和合約建立時(在一個合約裡面建立另外一個合約時)的錯誤,可以利用類條件式選擇來排除錯誤情況。
CATCH
我們有幾種宣告catch
的方法:
catch Error (string memory /*reason*/)
:當我們宣告過了revert("reasonString")
或require(false, "reasonString")
,且這些異常處理被觸發的話,catch
則會被執行。catch Panic(uint errorCode) { ... }
:此類型的catch
會在各種assert
、除以零、異常的陣列取值、運算溢位等情況發生時被執行。catch (bytes memory /*lowLevelData*/)
:當沒有其他符合的catch
子句時,或是在decoding錯誤訊息時出現問題、甚至外部呼叫時出現assertion failing,便會執行此類catch
。如果我們不在乎任何的Error Data,可以使用
catch { ... }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
// External contract used for try / catch examples
contract Foo {
address public owner;
constructor(address _owner) {
require(_owner != address(0), "invalid address");
assert(_owner != 0x0000000000000000000000000000000000000001);
owner = _owner;
}
function myFunc(uint x) public pure returns (string memory) {
require(x != 0, "require failed");
return "my func was called";
}
}
contract Bar {
event Log(string message);
event LogBytes(bytes data);
Foo public foo;
constructor() {
// This Foo contract is used for example of try catch with external call
foo = new Foo(msg.sender);
}
// Example of try / catch with external call
// tryCatchExternalCall(0) => Log("external call failed")
// tryCatchExternalCall(1) => Log("my func was called")
function tryCatchExternalCall(uint _i) public {
try foo.myFunc(_i) returns (string memory result) {
emit Log(result);
} catch {
emit Log("external call failed");
}
}
// Example of try / catch with contract creation
// tryCatchNewContract(0x0000000000000000000000000000000000000000) => Log("invalid address")
// tryCatchNewContract(0x0000000000000000000000000000000000000001) => LogBytes("")
// tryCatchNewContract(0x0000000000000000000000000000000000000002) => Log("Foo created")
function tryCatchNewContract(address _owner) public {
try new Foo(_owner) returns (Foo foo) {
// you can use variable foo here
emit Log("Foo created");
} catch Error(string memory reason) {
// catch failing revert() and require()
emit Log(reason);
} catch (bytes memory reason) {
// catch failing assert()
emit LogBytes(reason);
}
}
}
TRY
try
這個關鍵字必須要根據「外部函式呼叫」或「創建合約」這類的行為來定義,例如:new ContractName()
。
而其中的returns
部份是可有可無的,若需要的話,宣告returns
部份必須要符合外部函式呼叫的回傳型態。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.1;
interface DataFeed { function getData(address token) external returns (uint value); }
contract FeedConsumer {
DataFeed feed;
uint errorCount;
function rate(address token) public returns (uint value, bool success) {
// Permanently disable the mechanism if there are
// more than 10 errors.
require(errorCount < 10);
try feed.getData(token) returns (uint v) {
return (v, true);
} catch Error(string memory /*reason*/) {
// This is executed in case
// revert was called inside getData
// and a reason string was provided.
errorCount++;
return (0, false);
} catch Panic(uint /*errorCode*/) {
// This is executed in case of a panic,
// i.e. a serious error like division by zero
// or overflow. The error code can be used
// to determine the kind of error.
errorCount++;
return (0, false);
} catch (bytes memory /*lowLevelData*/) {
// This is executed in case revert() was used.
errorCount++;
return (0, false);
}
}
}
Last updated
Was this helpful?