Dies kann doppelt aussehen, aber ich kann keine richtige Antwort finden. Mein Ziel ist es, einen Vertrag zu entwickeln, bei dem der Vertragsinhaber die Empfänger und die Anzahl der Token festlegen kann, die sie abheben können. Sobald sie eingestellt sind, kann der Empfänger eine Funktion mit Metamask aufrufen, die den Gaspreis trägt, und die Token einlösen.
setBalances
Beim Versuch, die Methode mit nur 2 Elementen in jedem Array auszuführen , führte dies zu einem Fehlertransact to WithDraw.setBalances errored: Error: gas required exceeds allowance or always failing transaction
900000000000
aber immer noch das gleiche Ergebnis.redeem
die auch den gleichen Fehler ergebentransact to WithDraw.redeem errored: Error: gas required exceeds allowance or always failing transaction
Intelligenter Vertragscode
pragma solidity ^0.4.18;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred (address indexed _from, address indexed _to);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public{
owner = msg.sender;
OwnershipTransferred(address(0), owner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
owner = newOwner;
OwnershipTransferred(owner,newOwner);
}
}
/**
* @title Token
* @dev API interface for interacting with the Token contract
*/
interface Token {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
function balanceOf(address _owner) constant external returns (uint256 balance);
}
contract WithDraw is Ownable {
Token token;
mapping(address => uint256) public redeemBalanceOf;
event BalanceSet(address indexed beneficiary, uint256 value);
event Redeemed(address indexed beneficiary, uint256 value);
function WithDraw() public {
address _tokenAddr = MY_TOKEN_ADDR;
token = Token(_tokenAddr);
}
function setBalances(address[] dests, uint256[] values) onlyOwner public {
uint256 i = 0;
while (i < dests.length) {
if(dests[i] == address(0)) continue;
uint256 toSend = values[i] * 10**18;
redeemBalanceOf[dests[i]] += toSend;
i++;
BalanceSet(dests[i],values[i]);
}
}
function redeem(uint256 quantity) external{
uint256 baseUnits = quantity * 10**18;
require(redeemBalanceOf[msg.sender]>=baseUnits);
redeemBalanceOf[msg.sender] -= baseUnits;
token.transferFrom(owner,msg.sender,baseUnits);
Redeemed(msg.sender,quantity);
}
}
Was ist die Ursache des Fehlers? Sollte der Vertragsinhaber derselbe sein wie der Token-Vertragsinhaber?
EDIT1
Basierend auf der @smarx-Antwort haben Sie die setBalances
Methode wie unten geändert.
function setBalances(address[] dests, uint256[] values) onlyOwner public {
for (uint256 i = 0; i < dests.length; i++) {
if(dests[i] != address(0))
{
uint256 toSend = values[i] * 10**18;
redeemBalanceOf[dests[i]] += toSend;
BalanceSet(dests[i],values[i]);
}
i++;
}
}
Wenn ich jetzt zwei Elemente im Array übergebe, um den Wert festzulegen, sehe ich das Ereignisprotokoll nur für das erste Element, und das zweite wurde verpasst. Verwirrt!. Was ist mit der for-Schleife falsch?
Abgesehen von dem Schleifenproblem wird beim Aufrufen der redeem
Funktion auch derselbe Fehler ausgegeben, transact to WithDraw.redeem errored: Error: gas required exceeds allowance or always failing transaction
selbst wenn weniger als die bereits zugewiesene Menge übergeben wird. Muss die approve
Methode vor der Tokenübertragung in dieser Methode aufgerufen werden?
EDIT2
Konnte das Problem nicht mit der for-Schleife lösen. Modifizierte es zurück zu While Back mit Genehmigungsfunktion wie unten. Diesmal setBalances
funktionierte es richtig, die Salden wurden richtig angezeigt.
function setBalances(address[] dests, uint256[] values) onlyOwner public {
uint256 i = 0;
while (i < dests.length){
if(dests[i] != address(0))
{
uint256 toSend = values[i] * 10**18;
redeemBalanceOf[dests[i]] += toSend;
token.approve(dests[i], toSend);
BalanceSet(dests[i],values[i]);
}
i++;
}
}
Aber immer noch, der redeem
wirft den gleichen Fehler. Jede Hilfe wird sehr geschätzt.
BEARBEITEN 3
Habe die Änderungen wie unten vorgenommen. Und dieses Mal haben Sie eine ausreichende Anzahl von Token an diese Vertragsadresse übertragen
function setBalances(address[] dests, uint256[] values) onlyOwner public {
uint256 i = 0;
while (i < dests.length){
if(dests[i] != address(0))
{
uint256 toSend = values[i] * 10**18;
redeemBalanceOf[dests[i]] += toSend;
BalanceSet(dests[i],values[i]);
}
i++;
}
}
function redeem(uint256 quantity) external{
uint256 baseUnits = quantity * 10**18;
uint256 tokensAvailable = token.balanceOf(this);
require(redeemBalanceOf[msg.sender]>=baseUnits);
require( tokensAvailable >= baseUnits);
redeemBalanceOf[msg.sender] -= baseUnits;
token.transfer(msg.sender,baseUnits);
Redeemed(msg.sender,quantity);
}
Aber immer noch das gleiche Problem. Ich vermisse sicherlich etwas, weiß nicht, was es ist. Bitte helfen Sie.
Ich denke, die Ursache Ihres Fehlers ist, dass Sie über das Ende Ihrer Arrays hinaus lesen:
while (i < dests.length) {
// ...
i++;
// On the last iteration, i is dests.length, which is out of bounds.
BalanceSet(dests[i],values[i]);
}
Verschieben Sie das i++
to nach der BalanceSet
Zeile, oder noch besser, verwenden Sie eine for-Schleife:
for (uint256 i = 0; i < dests.length; i++) {
// ...
BalanceSet(dests[i], values[i]);
}
Dadurch wird auch die Endlosschleife vermieden, die Sie derzeit haben, wenn jemand die Adresse 0 übergibt.
if(dests[i] == address(0)) continue;
nur um die Übergabe der Adresse 0 zu verhindern. Dieses Mal ist der Fehler nicht aufgetreten, aber es wird redeemBalanceOf
kein Wert für eines der Elemente angezeigt, die im Array übergeben wurden. Was fehlt nochmal?Obwohl ich meine eigene Frage nicht beantworten möchte, dachte ich, es würde anderen helfen. Die gesamte Arbeitskopie wird unten eingefügt.
Dies kann für Airdrop-Unternehmen nützlich sein, die die zulässigen Token festlegen und die Teilnehmer auffordern können, sich selbst zurückzuziehen.
pragma solidity ^0.4.18;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred (address indexed _from, address indexed _to);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public{
owner = msg.sender;
OwnershipTransferred(address(0), owner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
owner = newOwner;
OwnershipTransferred(owner,newOwner);
}
}
/**
* @title Token
* @dev API interface for interacting with the Token contract
*/
interface Token {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
function balanceOf(address _owner) constant external returns (uint256 balance);
}
contract WithDraw is Ownable {
Token token;
mapping(address => uint256) public redeemBalanceOf;
event BalanceSet(address indexed beneficiary, uint256 value);
event Redeemed(address indexed beneficiary, uint256 value);
function WithDraw() public {
address _tokenAddr = MY_TOKEN_ADDR;
token = Token(_tokenAddr);
}
function setBalances(address[] dests, uint256[] values) onlyOwner public {
uint256 i = 0;
while (i < dests.length){
if(dests[i] != address(0))
{
uint256 toSend = values[i] * 10**18;
redeemBalanceOf[dests[i]] += toSend;
BalanceSet(dests[i],values[i]);
}
i++;
}
}
function redeem(uint256 quantity) external{
uint256 baseUnits = quantity * 10**18;
uint256 senderEligibility = redeemBalanceOf[msg.sender];
uint256 tokensAvailable = token.balanceOf(this);
require(senderEligibility >= baseUnits);
require( tokensAvailable >= baseUnits);
if(token.transfer(msg.sender,baseUnits)){
redeemBalanceOf[msg.sender] -= baseUnits;
Redeemed(msg.sender,quantity);
}
}
function removeBalances(address[] dests, uint256[] values) onlyOwner public {
uint256 i = 0;
while (i < dests.length){
if(dests[i] != address(0))
{
uint256 toRevoke = values[i] * 10**18;
if(redeemBalanceOf[dests[i]]>=toRevoke)
{
redeemBalanceOf[dests[i]] -= toRevoke;
BalanceCleared(dests[i],values[i]);
}
}
i++;
}
}
Benutzer19510
if (dest[i] == address(0)) continue;
? Das wird eine Endlosschleife verursachen, wenn es jemals passiert.Rajesh
Benutzer19510
redeem
Anrufetoken.transferFrom(owner, ...)
. Vielleichtowner
hatapprove
da nicht genug Token, damit das funktioniert? (Versuchen Sie, diese Zeile auszukommentieren, um zu sehen, ob sie die Quelle des Reverts ist.)Benutzer19510
setBalances
auch Anrufetoken.approve
. Ich denke, es gibt einige Verwirrung darüber, wo sich die Token befinden. Es kann keinen Sinn machen, diese beiden Linien zu haben.Rajesh
owner
versehen, die die Auszahlung der Token für die Einlösefunktion genehmigen würden. Fehlt etwas?Benutzer19510
token.approve
(setBalances
da der Vertrag keine Token besitzt), und Sie müssen sicherstellen, dass dieowner
Anrufe ausgeführt werdenapprove(<contract address>, <total amount>)
, bevor jemand versucht, anzurufenredeem
.Benutzer19510
transferFrom
sie funktionieren, muss der Besitzer dieser Tokenapprove
zuerst ihre Übertragung durchführen. (In diesem Fallowner
ist derjenige, der anrufenapprove
muss, da erowner
die Token besitzt.)Rajesh
setBalances
kann nur vom Eigentümer aufgerufen werden, und derapprove
Aufruf erfolgt in dieser Methode. Reicht das nicht?Benutzer19510
approve
bewirkt nichts, da der Vertrag keine Token enthält. Der Eigentümer muss anrufenapprove
.Rajesh
Benutzer19510
Rajesh
setBalances
damit die Einlösung einfach ist.Benutzer19510
transfer
die Token bzw.approve
diese übertragen.Rajesh
Benutzer19510
redeem
zu sehen, was der Fehler ist. Es gibt zweirequire
s und eintransfer
. Einer dieser drei Fehler fällt vermutlich aus, und das sollte Ihnen helfen, auf das Problem hinzuweisen.Rajesh