So übertragen Sie ERC20-Token mit web3js

Ich habe einige Dokumente gelesen, Parität im Docker-Container ausgeführt und in der Lage sein, eine Verbindung herzustellen und das Token-Guthaben eines Kontos abzurufen

const Web3 = require('web3'),
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'));
const contract = new web3.eth.Contract(JSON.parse(config.contract.abi), config.contract.address, { from: '0x...', gas: 100000 });

contract.methods.balanceOf('0x...').call()
    .then(console.log)
    .catch(console.error);

Was ich nicht verstehe, ist, wie ich die Übertragung der Token initiiere?

Laut Doku sollte es ungefähr so ​​sein:

contract.methods.transfer('0x...', web3.utils.toWei(0.001)).send()
    .then(console.log)
    .catch(console.error);

Ich habe es mit Rückrufen, Versprechungen und dem Abhören von Ereignissen versucht, aber auf jeden Fall bleibt mein Skript hängen und wird nicht beendet oder erzeugt keine Ausgabe

Ich erwarte einen Fehler: In diesem Fall nicht autorisiert, und dann würde ich herausfinden, wie ich meinen privaten Schlüssel weitergeben oder ein Konto entsperren kann (nicht wirklich sicher). Konnte nirgendwo ein vollständiges Beispiel finden.

Alles, was ich auf Stackexchange gefunden habe, sieht ähnlich aus

contract.transfer.sendTransaction('0x...', amount, { from: ..., gas: 100000 })

und funktioniert bei mir überhaupt nicht, beschwert sich über undefinierte Methoden: transfer und dann sendTransaction, wenn ich es verwendecontract.methods.transfer

Also, was ist der richtige Weg, das zu tun?

Antworten (4)

Fast alle Dokumente da draußen beziehen sich auf den Zweig 0.20 von web3.js, der der aktuelle stabile Zweig ist. Die Version mit den obigen Versprechungen ist der 1.0.0-Beta-Zweig, den npm seit einigen Tagen standardmäßig installiert.

Was den Beispielcode betrifft, so funktioniert der folgende Code, der fast identisch mit Ihrem ist, für mich von der Knotenkonsole aus korrekt gegen mein eigenes ERC20-Token, das lokal mit testrpc ausgeführt wird.

Der Hauptunterschied ist meiner Meinung nach nur der überwiesene Betrag. Die Methode toWei() ist nicht wirklich auf ERC20-Token anwendbar und kann die Dinge verwirren.

Wenn Sie sich im Mainnet befinden, dauert es außerdem eine Weile, bis send() abgebaut wird, und das Versprechen wird bis dahin nicht aufgelöst. Möglicherweise müssen Sie die gasPrice-Option im Vertrag auf einige GWei einstellen. Bei näherer Betrachtung ist dies definitiv ein Problem. (Die call()-Methoden werden lokal verarbeitet, sodass keine Wartezeiten und keine Benzinkosten anfallen.)

Aber wenn Sie nicht aufgefordert werden, ein Konto zu entsperren, weiß ich nicht ... Es kann sich lohnen, testrpc lokal einzurichten ( testrpc -dist nützlich) und einen ERC20-Vertrag lokal bereitzustellen, um alles ohne die zusätzlichen Komplikationen des Bezahlens zu überprüfen für Benzin usw.

Wie auch immer, vielleicht ist dieses Beispiel für Sie oder andere nützlich.

> const Web3 = require('web3');
undefined
> const web3 = new Web3('http://localhost:8545');
undefined
> web3.version
'1.0.0-beta.11'
> fs = require('fs');
<blah>
> const abi = fs.readFileSync('erc20_abi.json', 'utf-8');
undefined
> const contract = new web3.eth.Contract(JSON.parse(abi), '0xafb7b8a4d90c2df4ce640338029d54a55bedcfc4', { from: '0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1', gas: 100000});
undefined
> contract.methods.balanceOf('0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1').call().then(console.log).catch(console.error);
Promise {...}
> 99997
> contract.methods.transfer('0xffcf8fdee72ac11b5c542428b35eef5769c409f0', 1).send().then(console.log).catch(console.error);
Promise {...}
> { transactionHash: '0xf2d621ba5029a086e212d87fab83be31c3fa41fe47198c378f55c252e5b25d5b',
  transactionIndex: 0,
  blockHash: '0x0e806bf3e88f9335ee9be903303a2393c940ab22f4a73c7e28ca8d9a212ffa4e',
  blockNumber: 429,
  gasUsed: 35206,
  cumulativeGasUsed: 35206,
  contractAddress: null,
  events: 
   { Transfer: 
      { logIndex: 0,
        transactionIndex: 0,
        transactionHash: '0xf2d621ba5029a086e212d87fab83be31c3fa41fe47198c378f55c252e5b25d5b',
        blockHash: '0x0e806bf3e88f9335ee9be903303a2393c940ab22f4a73c7e28ca8d9a212ffa4e',
        blockNumber: 429,
        address: '0xAFB7b8A4d90C2Df4ce640338029d54A55BEDcfC4',
        type: 'mined',
        id: 'log_bfd297b0',
        returnValues: [Object],
        event: 'Transfer',
        signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        raw: [Object] } } }
> contract.methods.balanceOf('0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1').call().then(console.log).catch(console.error);
Promise {...}
> 99996
Das ist großartig, also bin ich auf dem richtigen Weg. Ich kann Ihrem Beispiel jedoch immer noch nicht entnehmen, wie Sie ein Konto authentifizieren/entsperren. Ich bin mir bewusst, dass toWei nicht für Token ist, funktioniert aber hervorragend mit dem, auf dem ich teste.
Um fair zu sein, das war nicht Ihre ursprüngliche Frage ... Es werden Konten freigeschaltet, mit web3.eth.personal.unlockAccount(account, password, unlocktime)denen sie noch nicht zur Dokumentation gekommen sind. Ich weiß nicht, wie das mit einem Ledger Nano S, sagen wir, wahrscheinlich zuerst über die GUI. Ich werde es mir am Wochenende ansehen und die Antwort mit allem Nützlichen aktualisieren.

web3 1.0 API-Änderung.

let myContract = new web3.eth.Contract(abi, contractAddress);
let data = myContract.methods.transfer(toAddress, value).encodeABI();
let rawTx = {
    "nonce": web3.utils.toHex(nonce),
    "gasPrice": "0x3b9aca00",
    "gasLimit": web3.utils.toHex(gasLimit),
    "to": contractAddress,
    "value": "0x00",
    "data": data,
}
const tx = new Tx(rawTx)
tx.sign(privateKey)
let serializedTx = "0x" + tx.serialize().toString('hex');
web3.eth.sendSignedTransaction(serializedTx).on('transactionHash', function (txHash) {

}).on('receipt', function (receipt) {
    console.log("receipt:" + receipt);
}).on('confirmation', function (confirmationNumber, receipt) {
    //console.log("confirmationNumber:" + confirmationNumber + " receipt:" + receipt);
}).on('error', function (error) {

});

Sie können dies sehen: Übertragung von ERC20-Token vom Konto mit web3 über Ropsten

Um Ihre Antwort zu ergänzen, kann die Transaktion auch wie folgt mit der web3-Instanz signiert werden: let signedTx = web3.eth.accounts.signTransaction(rawTx, privateKey)und dannweb3.eth.sendSignedTransaction(signedTx.rawTransaction)

Für alle anderen, die Schwierigkeiten haben, ist dies ein voll funktionsfähiger Code mit web3 1.0.0-beta.51

Die anderen Lösungen auf dieser Seite haben bei mir nicht funktioniert.

Die „contractAddress“ ist der Master-Token-Vertrag – derjenige, der dem Team gehört, das das Projekt ausführt. In meinem Beispiel ist es HST und ihre Vertragsadresse ist https://etherscan.io/token/0x554c20b7c486beee439277b4540a434566dc4c02

const Web3 = require('web3')
const Tx = require('ethereumjs-tx')

const Web3js = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID'))

let tokenAddress = '0x554c20b7c486beee439277b4540a434566dc4c02' // HST contract address
let toAddress = '' // where to send it
let fromAddress = '' // your wallet
let privateKey = Buffer.from('PRIVATE_KEY', 'hex')

let contractABI = [
  // transfer
  {
    'constant': false,
    'inputs': [
      {
        'name': '_to',
        'type': 'address'
      },
      {
        'name': '_value',
        'type': 'uint256'
      }
    ],
    'name': 'transfer',
    'outputs': [
      {
        'name': '',
        'type': 'bool'
      }
    ],
    'type': 'function'
  }
]

let contract = new Web3js.eth.Contract(contractABI, tokenAddress, {from: fromAddress})

// 1e18 === 1 HST
let amount = Web3js.utils.toHex(1e18)

Web3js.eth.getTransactionCount(fromAddress)
  .then((count) => {
    let rawTransaction = {
      'from': fromAddress,
      'gasPrice': Web3js.utils.toHex(20 * 1e9),
      'gasLimit': Web3js.utils.toHex(210000),
      'to': tokenAddress,
      'value': 0x0,
      'data': contract.methods.transfer(toAddress, amount).encodeABI(),
      'nonce': Web3js.utils.toHex(count)
    }
    let transaction = new Tx(rawTransaction)
    transaction.sign(privateKey)
    Web3js.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'))
      .on('transactionHash', console.log)
  })

Für die Übertragung beziehen Sie sich auf den folgenden Code: (ersetzen Sie privateKey durch den Token, von dem das Konto abgezogen wird.

let data = myContract.methods.transfer(dest, amt).encodeABI();
let txObj = {
    gas: config.gas,
    gasPrice: config.gasPrice,
    "to": config.tusdContract,
    "value": "0x00",
    "data": data,
}
web3.eth.accounts.signTransaction(txObj, privateKey, (err, signedTx) => {
if (err) {
    return callback(err);
} else {
    console.log(signedTx);
    return web3.eth.sendSignedTransaction(signedTx.rawTransaction, (err, res) => {
    if (err) {
        console.log(err)
    } else {
        console.log(res);
    }
  });
}
});