aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-02-06 04:21:14 +0800
committerAlex Beregszaszi <alex@rtfs.hu>2017-02-24 08:17:45 +0800
commit4264625c69a30c4534e977ce3ca709bb95103dad (patch)
tree0cf10fe14784484d2f8ec3acc2d177d303d06067
parent0177d964b1cf0f7a238f11aa9b617d26dddf7caf (diff)
downloaddexon-solidity-4264625c69a30c4534e977ce3ca709bb95103dad.tar.gz
dexon-solidity-4264625c69a30c4534e977ce3ca709bb95103dad.tar.zst
dexon-solidity-4264625c69a30c4534e977ce3ca709bb95103dad.zip
Implement address.transfer()
-rw-r--r--Changelog.md1
-rw-r--r--libsolidity/ast/Types.cpp4
-rw-r--r--libsolidity/ast/Types.h1
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp19
4 files changed, 20 insertions, 5 deletions
diff --git a/Changelog.md b/Changelog.md
index 45aaf04a..37f20c71 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,7 @@
Features:
* 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.
* Inline assembly: Support ``revert`` (EIP140) as an opcode.
* Type system: Support explicit conversion of external function to address.
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 96b3ed17..7fccccbc 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -464,7 +464,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
{"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)},
{"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
return MemberList::MemberMap();
@@ -2097,6 +2098,7 @@ string FunctionType::identifier() const
case Location::BareDelegateCall: id += "baredelegatecall"; break;
case Location::Creation: id += "creation"; break;
case Location::Send: id += "send"; break;
+ case Location::Transfer: id += "transfer"; break;
case Location::SHA3: id += "sha3"; break;
case Location::Selfdestruct: id += "selfdestruct"; break;
case Location::Revert: id += "revert"; break;
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 3546e522..022b67c4 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -826,6 +826,7 @@ public:
BareDelegateCall, ///< DELEGATECALL without function hash
Creation, ///< external call using CREATE
Send, ///< CALL, but without data and gas
+ Transfer, ///< CALL, but without data and throws on error
SHA3, ///< SHA3
Selfdestruct, ///< SELFDESTRUCT
Revert, ///< REVERT
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 2ed19a83..b0031513 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -616,6 +616,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments.front()->accept(*this);
break;
case Location::Send:
+ case Location::Transfer:
_functionCall.expression().accept(*this);
// Provide the gas stipend manually at first because we may send 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,
*function.parameterTypes().front(), true
);
- // gas <- gas * !value
- m_context << Instruction::SWAP1 << Instruction::DUP2;
- m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
+ if (function.location() != Location::Transfer)
+ {
+ // gas <- gas * !value
+ m_context << Instruction::SWAP1 << Instruction::DUP2;
+ m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
+ }
appendExternalFunctionCall(
FunctionType(
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;
case Location::Selfdestruct:
arguments.front()->accept(*this);
@@ -960,6 +970,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
case FunctionType::Location::Bare:
case FunctionType::Location::BareCallCode:
case FunctionType::Location::BareDelegateCall:
+ case FunctionType::Location::Transfer:
_memberAccess.expression().accept(*this);
m_context << funType->externalIdentifier();
break;
@@ -1041,7 +1052,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
);
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(
*_memberAccess.expression().annotation().type,
IntegerType(0, IntegerType::Modifier::Address),