I have an issue:
I want to receive some BOKKY tokens to test it. When I use simple wallets I just send ethers and receive tokens, everything works fine.
I also have my own smart contract (multisig wallet) It works fine when I transfer ethers to other accounts, however when I try to receive tokens same way as I did with simple accounts (send ethers from my contract to token contract address ) my transaction fails with error:
Out of gas
The code of smart contract is here:
pragma solidity 0.5.0;
import "./ERC20.sol";
contract MultiSigWallet {
// address private _owner;
mapping(address => uint) private _owners;
uint constant MIN_SIGNATURES = 2;
uint private transactionIdx;
address payable private _commissionAddress;
mapping(uint => address) private tokens;
uint private currentToken;
ERC20 private erc20iface;
struct Transaction {
address from;
address payable to;
address _contract;
uint amount;
uint signatureCount;
uint commission;
mapping(address => uint) signatures;
}
mapping(uint => Transaction) private _transactions;
uint[] private _pendingTransactions;
// modifier isOwner() {
// require(msg.sender == _owner);
// _;
// }
modifier validOwner() {
// require(msg.sender == _owner || _owners[msg.sender] == 1);
require(_owners[msg.sender] == 1);
_;
}
event DepositFunds(address from, uint amount);
event TransactionCreated(address from, address to, uint amount, uint transactionId);
event TransactionCompleted(address from, address to, uint amount, uint transactionId);
event TransactionSigned(address by, uint transactionId);
event TransferFailed(address from, address to, uint amount, uint transactionId);
constructor(address service, address payable commissionAddress, address token) public {
// _owner = msg.sender;
_commissionAddress = commissionAddress;
_owners[msg.sender] = 1;
_owners[service] = 1;
currentToken = 0;
tokens[currentToken] = token;
currentToken++;
}
function () external payable
{
emit DepositFunds(msg.sender, msg.value);
}
function withdraw(uint amount, uint commission, address token)
public
{
transferTo(msg.sender, amount, commission, token);
}
function transferTo(address payable to, uint amount, uint commission, address token)
validOwner
public
{
// require(address(this).balance >= amount);
require(amount > 0);
uint transactionId = transactionIdx++;
Transaction memory transaction;
transaction.from = msg.sender;
transaction.to = to;
transaction._contract = token;
transaction.commission = commission;
transaction.amount = amount;
transaction.signatureCount = 0;
_transactions[transactionId] = transaction;
_pendingTransactions.push(transactionId);
emit TransactionCreated(msg.sender, to, amount, transactionId);
signTransaction(transactionId);
}
function getPendingTransactions()
view
validOwner
public
returns(uint[] memory)
{
return _pendingTransactions;
}
function signTransaction(uint transactionId)
validOwner
public
{
Transaction storage transaction = _transactions[transactionId];
// Transaction must exist
require(0x0000000000000000000000000000000000000000 != transaction.from);
// Creator cannot sign the transaction
// require(msg.sender != transaction.from);
// sender haven't sign it already
require(transaction.signatures[msg.sender] != 1);
transaction.signatures[msg.sender] = 1;
transaction.signatureCount++;
emit TransactionSigned(msg.sender, transactionId);
if(transaction.signatureCount >= MIN_SIGNATURES) {
if(transaction._contract != 0x0000000000000000000000000000000000000000) {
// if(amount_ > ERC20Interface.allowance(transaction.from, address(this))) {
// emit TransferFailed(from_, to_, amount_, transactionId);
// revert();
// }
erc20iface = ERC20(transaction._contract);
erc20iface.transfer(transaction.to, transaction.amount);
erc20iface.transfer(_commissionAddress, transaction.commission);
} else {
require(address(this).balance >= transaction.amount);
(transaction.to).transfer(transaction.amount);
_commissionAddress.transfer(transaction.commission);
}
emit TransactionCompleted(transaction.from, transaction.to, transaction.amount, transactionId);
deleteTransaction(transactionId);
}
}
function deleteTransaction(uint transactionId)
validOwner
public
{
uint replace = 0;
assert(_pendingTransactions.length > 0);
for(uint i = 0; i < _pendingTransactions.length; i++) {
if(replace == 1) {
_pendingTransactions[i-1] = _pendingTransactions[i];
} else if (transactionId == _pendingTransactions[i]) {
replace = 1;
}
}
assert(replace == 1);
delete _pendingTransactions[_pendingTransactions.length - 1];
_pendingTransactions.length--;
delete _transactions[transactionId];
}
function walletBalance()
view
public
returns (uint) {
return address(this).balance;
}
}
Code for web3 (tx creation):
const createMsigTxETH = async options => {
const { targetAddress, contractAddress, amount, commission, initiatorAddress } = options;
const provider = new Web3.providers.HttpProvider(eth);
const web3 = new Web3(provider);
const amountETH = web3.utils.toWei(amount.toString(), 'ether');
const commissionETH = web3.utils.toWei(commission.toString(), 'ether');
const msigWalletContract = new web3.eth.Contract(MSIG_ABI, contractAddress);
const nonce = await web3.eth.getTransactionCount(initiatorAddress);
const TOKEN_ADDR = '0x0000000000000000000000000000000000000000';
const txObj = {
nonce: web3.utils.toHex(nonce),
gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
gasLimit: web3.utils.toHex(GAS),
data: msigWalletContract.methods
.transferTo(targetAddress, amountETH, commissionETH, TOKEN_ADDR)
.encodeABI(),
to: contractAddress
};
const tx = new Tx(txObj);
return tx;
};
Code for Signing tx:
const provider = new Web3.providers.HttpProvider(eth);
const web3 = new Web3(provider);
const msigWalletContract = new web3.eth.Contract(MSIG_ABI, contractAddress);
const nonce = await msigWalletContract.methods
.getPendingTransactions()
.call({ from: serviceAddress });
if (!nonce.length) throw Error('ERROR NONCE ');
const txObj = {
nonce: web3.utils.toHex(nonce[nonce.length - 1]),
gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
gasLimit: web3.utils.toHex(GAS),
data: msigWalletContract.methods.signTransaction(nonce[nonce.length - 1]).encodeABI(),
to: contractAddress
};
const tx = new Tx(txObj);
tx.sign(Buffer.from(servicePrivateKey, 'hex'));
const serializedTx = tx.serialize();
const raw = `0x${serializedTx.toString('hex')}`;
try {
return new Promise((resolve, reject) => {
web3.eth.sendSignedTransaction(raw).on('transactionHash', txHash => {
resolve(txHash);
});
});
} catch (err) {
throw new Error(err);
}
}
Can anyone suggest what it can be?
Thank you!