【Address】
address 可以被用來儲存一個以太坊地址指向的帳戶或智能合約。
pragma solidity ^0.8.11;
contract MyAddress {
address public myAddress = address(0xB42faBF7BCAE8bc5E368716B568a6f8Fdf3F84ec);
address public myContractAddress = address(this);
uint256 public balanceOfMyContract = myContractAddress.balance;
}當我們在宣告 address 時加上 payable 這個修飾詞(modifier)時,則此 address 就會多兩個成員(members),分別為 transfer 和 send。address payable 代表可用於支付的地址,反之 address 就不可用於支付任何 eth,也不包含以上多的兩個成員。
Address具有以下的特性:
任何在Ethereum的互動都是Address based
長度為20 byte
myAddress.balance=> 得到以wei為單位的balancemyAddress.transfer(amountInWei)=> 自智能合約傳送相對應數量(以wei為單位)的ether給指定地址
Address and Msg.Object
---- Outside Ethereum Blockchain ----
Externally Owned Account(EOA)
用於交易資金、初始化交易、佈署智能合約、提領
擁有一個私鑰來管理帳戶
---- Inside Ethereum Blockchain ----
Contract Account
沒有私鑰來管理帳戶,程式碼決定了整個合約帳戶的運作
智能合約的互動與帳戶關係
使用EOA 初始化交易
途徑常為:EOA -> Contract Account -> Contract Account...(EOA as beginner)
途徑不可為:Contract Account -> Contract Account...(Contract Account as beginner)
只要原點是EOA,接下來無論是Contract Account或EOA皆可與彼此交互運作
成員函式與合約之間互動的方法
.balance:可以得到當前地址的餘額,以 wei 為單位。
<address>.balance()
.transfer:有
gas限制,最大2300<address payable>.transfer(uint256 amount)此函式會從合約轉入帳號 amount 價值,wei 單位的 eth
如果執行失敗會拋出錯誤
.send:有
gas限制,最大2300<address payable>.send(uint256 amount) returns (bool)此函式會從合約轉入帳號 amount 價值,wei 單位的 eth
是一個屬於
.transfer的低階部件,如果執行.send失敗的話不會把整個合約停止,而是會 returnfalse。不會改變任何的「狀態」。
.call:沒有
gas限制<address>.call(bytes memory) returns (bool, bytes memory)和
send一樣,如果執行失敗不會停止而是 return false<address>.call.value(amount)()功能類似<address>.transfer會從合約轉入帳號 amount 價值的 eth<address>.call.gas()可以調整供給的gas數量,並且returnns 一個 boolean值
.delegatecall:暫略.staticcall:暫略
雖然 .delegatecall, .staticcall 我們暫時略過,但.call, .delegatecall, .staticcall 以上三者都可以調用 gas 參數,而 value 參數只有 .call 可以使用。此三者都是非常底層的函數,所以我們應該要盡量避免直接 hard-code gas 在我們的智能合約,除非我們十分確定要這麼做。
使用範例:
pragma solidity ^0.8.11;
contract MyPayable {
function transferEth(address payable _user) public payable {
_user.transfer(msg.value);
}
function sendEth(address payable _user) public payable {
bool didSend = _user.send(msg.value);
require(didSend, "This failed to send");
}
function callEth(address payable _user) public payable {
(bool didSend, ) = _user.call{value: msg.value}("");
require(didSend);
// 如果要使用 <address>.call.value() 這個方法,那麼被調用的函數必須添加 payable 修飾符,否則轉帳會失敗
}
function ContractBalance() public view returns(uint){
address contractAccount = address(this);
return contractAccount.balance;
}
function myBalance() public view returns(uint){
address myAccount = msg.sender;
return myAccount.balance;
}
receive() external payable {}
fallback() external payable {}
}如果使用
<address>.transfer(uint amount)、<address>.send(uint amount), 這個<address>代稱的合約地址中必須增加callback回調函數!
address vs. address payable
在這裡更深入地探討 <address> 和 <address payable>。兩者的區別僅在編譯時存在,在編譯後的合約代碼中就沒有區別了。
而在編譯時兩者最大的區別就在型別轉換:
// address payable類型的變量可以顯式或隱式地轉換為address類型
address payable addr1 = msg.sender;
address addr2 = addr1; // 正確
address addr3 = address(addr1); // 正確
// address類型的變量只能顯式地轉換為address payable,需要首先轉換為整數類型(例如uint160),
// 然後再將該整型值轉換為address類型,就可以得到address payable:
address addr1 = msg.sender;
address payable addr2 = addr1; // 錯誤,address不能隱式地轉換為address payable
address payable addr3 = address(uint160(addr1)); // 正確,先轉換為uint160,然後轉換為address payable
address payable addr4 = payable(addr1); // 可以直接使用 payable() 來顯式轉換Last updated
Was this helpful?