mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Implement address.transfer()
This commit is contained in:
parent
0177d964b1
commit
4264625c69
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
* Add ``assert(condition)``, which throws if condition is false.
|
* Add ``assert(condition)``, which throws if condition is false.
|
||||||
|
* Introduce ``.transfer(value)`` for sending Ether.
|
||||||
* Code generator: Support ``revert()`` to abort with rolling back, but not consuming all gas.
|
* Code generator: Support ``revert()`` to abort with rolling back, but not consuming all gas.
|
||||||
* Inline assembly: Support ``revert`` (EIP140) as an opcode.
|
* Inline assembly: Support ``revert`` (EIP140) as an opcode.
|
||||||
* Type system: Support explicit conversion of external function to address.
|
* Type system: Support explicit conversion of external function to address.
|
||||||
|
@ -464,7 +464,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
|
|||||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true, false, true)},
|
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true, false, true)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true, false, true)},
|
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true, false, true)},
|
||||||
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareDelegateCall, true)},
|
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareDelegateCall, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)},
|
||||||
|
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Location::Transfer)}
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
return MemberList::MemberMap();
|
return MemberList::MemberMap();
|
||||||
@ -2097,6 +2098,7 @@ string FunctionType::identifier() const
|
|||||||
case Location::BareDelegateCall: id += "baredelegatecall"; break;
|
case Location::BareDelegateCall: id += "baredelegatecall"; break;
|
||||||
case Location::Creation: id += "creation"; break;
|
case Location::Creation: id += "creation"; break;
|
||||||
case Location::Send: id += "send"; break;
|
case Location::Send: id += "send"; break;
|
||||||
|
case Location::Transfer: id += "transfer"; break;
|
||||||
case Location::SHA3: id += "sha3"; break;
|
case Location::SHA3: id += "sha3"; break;
|
||||||
case Location::Selfdestruct: id += "selfdestruct"; break;
|
case Location::Selfdestruct: id += "selfdestruct"; break;
|
||||||
case Location::Revert: id += "revert"; break;
|
case Location::Revert: id += "revert"; break;
|
||||||
|
@ -826,6 +826,7 @@ public:
|
|||||||
BareDelegateCall, ///< DELEGATECALL without function hash
|
BareDelegateCall, ///< DELEGATECALL without function hash
|
||||||
Creation, ///< external call using CREATE
|
Creation, ///< external call using CREATE
|
||||||
Send, ///< CALL, but without data and gas
|
Send, ///< CALL, but without data and gas
|
||||||
|
Transfer, ///< CALL, but without data and throws on error
|
||||||
SHA3, ///< SHA3
|
SHA3, ///< SHA3
|
||||||
Selfdestruct, ///< SELFDESTRUCT
|
Selfdestruct, ///< SELFDESTRUCT
|
||||||
Revert, ///< REVERT
|
Revert, ///< REVERT
|
||||||
|
@ -616,6 +616,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
break;
|
break;
|
||||||
case Location::Send:
|
case Location::Send:
|
||||||
|
case Location::Transfer:
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
// Provide the gas stipend manually at first because we may send zero ether.
|
// Provide the gas stipend manually at first because we may send zero ether.
|
||||||
// Will be zeroed if we send more than zero ether.
|
// Will be zeroed if we send more than zero ether.
|
||||||
@ -625,9 +626,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
*arguments.front()->annotation().type,
|
*arguments.front()->annotation().type,
|
||||||
*function.parameterTypes().front(), true
|
*function.parameterTypes().front(), true
|
||||||
);
|
);
|
||||||
// gas <- gas * !value
|
if (function.location() != Location::Transfer)
|
||||||
m_context << Instruction::SWAP1 << Instruction::DUP2;
|
{
|
||||||
m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
|
// gas <- gas * !value
|
||||||
|
m_context << Instruction::SWAP1 << Instruction::DUP2;
|
||||||
|
m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
|
||||||
|
}
|
||||||
appendExternalFunctionCall(
|
appendExternalFunctionCall(
|
||||||
FunctionType(
|
FunctionType(
|
||||||
TypePointers{},
|
TypePointers{},
|
||||||
@ -644,6 +648,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
),
|
),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
if (function.location() == Location::Transfer)
|
||||||
|
{
|
||||||
|
// Check if zero (out of stack or not enough balance).
|
||||||
|
m_context << Instruction::ISZERO;
|
||||||
|
m_context.appendConditionalInvalid();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Location::Selfdestruct:
|
case Location::Selfdestruct:
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
@ -960,6 +970,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
case FunctionType::Location::Bare:
|
case FunctionType::Location::Bare:
|
||||||
case FunctionType::Location::BareCallCode:
|
case FunctionType::Location::BareCallCode:
|
||||||
case FunctionType::Location::BareDelegateCall:
|
case FunctionType::Location::BareDelegateCall:
|
||||||
|
case FunctionType::Location::Transfer:
|
||||||
_memberAccess.expression().accept(*this);
|
_memberAccess.expression().accept(*this);
|
||||||
m_context << funType->externalIdentifier();
|
m_context << funType->externalIdentifier();
|
||||||
break;
|
break;
|
||||||
@ -1041,7 +1052,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
);
|
);
|
||||||
m_context << Instruction::BALANCE;
|
m_context << Instruction::BALANCE;
|
||||||
}
|
}
|
||||||
else if ((set<string>{"send", "call", "callcode", "delegatecall"}).count(member))
|
else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member))
|
||||||
utils().convertType(
|
utils().convertType(
|
||||||
*_memberAccess.expression().annotation().type,
|
*_memberAccess.expression().annotation().type,
|
||||||
IntegerType(0, IntegerType::Modifier::Address),
|
IntegerType(0, IntegerType::Modifier::Address),
|
||||||
|
Loading…
Reference in New Issue
Block a user