Wie wird die Adresse eines Ethereum-Kontrakts berechnet?

Wie wird die Adresse eines Ethereum-Kontrakts berechnet? Welche Anwendungsfälle gibt es, um die Adresse eines Vertrags im Voraus zu kennen?

Zusätzlich zur @eth- Antwort ist zu beachten, dass Sie die letzten 20 Bytes nehmen.

Antworten (7)

EDIT April 2019 : CREATE2Informationen hinzugefügt.

BEARBEITEN Januar 2022 : Solidity-Syntax auf ^0.8.0 aktualisiert.

Die Adresse für einen Ethereum-Vertrag wird deterministisch aus der Adresse seines Erstellers ( sender) und wie viele Transaktionen der Ersteller gesendet hat ( nonce) berechnet. Die senderund noncewerden RLP-codiert und dann mit Keccak-256 gehasht .

Aus Pyethereum:

def mk_contract_address(sender, nonce):
    return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]

In Solidität:

nonce0= address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80))))));
nonce1= address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x01))))));

Beispiel mit etwas Diskussion:

Für den Absender 0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0 werden die folgenden Vertragsadressen erstellt:

nonce0= "0xcd234a471b72ba2f1ccf0a70fcaba648a5eecd8d"
nonce1= "0x343c43a37d37dff08ae8c4a11544c718abb4fcf8"
nonce2= "0xf778b86fa74e846c4f0a1fbd1335fe81c00a0c91"
nonce3= "0xfffd933a0bc612844eaf0c6fe3e5b8e9b6c1d19c"

In Java mit Web3j:

private String calculateContractAddress(String address, long nonce){
    byte[] addressAsBytes = Numeric.hexStringToByteArray(address);

    byte[] calculatedAddressAsBytes =
            Hash.sha3(RlpEncoder.encode(
                    new RlpList(
                            RlpString.create(addressAsBytes),
                            RlpString.create((nonce)))));

    calculatedAddressAsBytes = Arrays.copyOfRange(calculatedAddressAsBytes,
            12, calculatedAddressAsBytes.length);
    String calculatedAddressAsHex = Numeric.toHexString(calculatedAddressAsBytes);
    return calculatedAddressAsHex;
}

Hinweis : Gemäß EIP 161 A Spezifikation werden Vertragskonten mit Nonce = 1 (im Mainnet) initiiert. Daher wird die erste Vertragsadresse, die von einem anderen Vertrag erstellt wurde, mit einer Nonce ungleich Null berechnet.


CREATE2

In EIP-1014 wurde ein neuer Opcode CREATE2hinzugefügt , der eine weitere Möglichkeit darstellt, wie ein Vertrag erstellt werden kann.

Für den Vertrag, der von CREATE2seiner Adresse erstellt wird, wird es sein:

keccak256( 0xff ++ senderAddress ++ salt ++ keccak256(init_code))[12:]

Weitere Informationen werden hier hinzugefügt und für die Zwischenzeit siehe EIP-1014 .

Für den Anwendungsfallteil könnten Sie etwas über Vorfinanzierungsverträge erwähnen
Was ist, wenn der Ersteller selbst ein Vertrag ist? Hat die Adresse auch eine Nonce? Erhöht sie sich durch jeden Anruf oder nur durch das Knüpfen neuer Kontakte? Oder ist die Adresse und Nonce von tx.origin relevant?
@TjadenHess Danke, positiv bewertet, anstatt die Vorfinanzierung mehr zu erklären.
@mKoeppelmann: Gleiche Berechnung, wenn der Ersteller ein Vertrag ist; Nonce erhöht jede einzelne Transaktion, die ein Konto durchführt (neuer Vertrag/Konto würde bei Nonce 0 beginnen), und die Adresse und Nonce früherer Absender (z. B. tx.origin) wirken sich nicht auf die Adresse des neuen Vertrags aus.
@eth: "Nonce erhöht jede einzelne Transaktion" das verwirrt mich, weil in der Definition im Yellowpaper nur von Menschen kontrollierte Konten Transaktionen durchführen können. Eine Transaktion ist etwas, das mit einem privaten Schlüssel signiert wird. Verträge können nur Aufrufe tätigen, die durch Transaktionen ausgelöst werden. Ich frage mich also, welche "Anrufe" die Nonce eines Vertrags erhöhen. Alle Anrufe oder nur Anrufe, die einen neuen Vertrag schaffen?
Ich denke, die Frage, die ich stelle, wird ein bisschen thematisch, also habe ich hier eine neue Frage erstellt: ethereum.stackexchange.com/questions/764/…
Was passiert bei einem vertragsbegründenden Vertrag? Hat ein Vertrag auch eine laufende Nummer?
@StevenRoose Ja, Verträge haben Nonces. Eine Nonce eines Vertrags wird nur erhöht, wenn dieser Vertrag einen anderen Vertrag erstellt. Es ist in einer separaten Frage, die Martin ethereum.stackexchange.com/questions/764/… gestellt hat :)
0xd6, 0x94, 0x80 und 0x01, was sind das für magische Zahlen?
Sie sind Teil der RLP -Kodierung
Hier ist ein Online-Adressenrechner für intelligente Verträge mit vollständiger CREATE2-Unterstützung: toolkit.abdk.consulting/ethereum#contract-address
@MikhailVladimirov Danke, wenn Sie Zeit haben, eine separate Antwort zu posten, in der die verschiedenen Felder erklärt werden / wie Sie Ihren Taschenrechner verwenden, werde ich meine CREATE2-Antwort aktualisieren, um auf Ihre zu verweisen.
Für Solidity ^0.6.0 musste ich address(uint160(uint256(keccak256(abi.encodePacked(byte(0xd6), byte(0x94), _origin, byte(0x80))))))(for nonce0) verwenden.

Dank der Antwort von eth hat es sehr geholfen, das 2000-Dollar-Problem zu lösen.

Gerade Problem mit Geldern gelöst, die im Ethereum-Hauptnetzwerk an die Adresse des Smart Contract gesendet wurden, um das Ethereum-Netzwerk zu testen . Wir haben dieselbe Brieftasche mehrmals verwendet, um verschiedene Smart Contracts im Ethereum-Hauptnetzwerk bereitzustellen, bis das Transaktionsfeld nonce den gleichen Wert 13 erreichte, wie er für die Bereitstellung im Testnetzwerk verwendet wurde. Wir haben eine spezielle Methode für neu bereitgestellte Smart Contracts aufgerufen, um Gelder zurückzufordern. Also wurde Smart Contract eingesetzt, nachdem es wirklich finanziert wurde: https://etherscan.io/address/0x9c86825280b1d6c7dB043D4CC86E1549990149f9

Habe gerade einen Artikel zu diesem Thema fertiggestellt: https://medium.com/@k06a/how-we-sent-eth-to-the-wrong-address-and-successfully-recovered-them-2fc18e09d8f6

Geben Sie hier die Bildbeschreibung ein

Danke .. aber was ist, wenn der Eigentümer des Mainnet-Vertrags einen Strom hat, der höher ist als der, der zum Erstellen des Vertrags im Testnet verwendet wurde? Ich habe die gleiche Situation wie Sie.
Bei den aktuellen Gasgebühren würden Sie ein Vermögen bezahlen, um den Vertrag 12 Mal einzusetzen, bevor Sie 13 Mal erreichten. Warum haben Sie die Nonce nicht sofort auf 13 gesetzt?
@Qwerty können Sie selbst eine Nonce für die Bereitstellung festlegen?
@Sky Ja, in der Metamaske beim Bestätigen der Transaktion. Ich habe es gerade mit REMIX versucht. Wenn Sie es in Metamask nicht sehen, aktivieren Sie erweiterte Optionen.

Hier ist ein node.js-Skript, das eine Ethereum-Vertragsadresse anhand der öffentlichen Adresse und des Nonce-Werts des Vertragserstellers deterministisch berechnet.

Bei Fragen zu Eingaben etc.

// node version: v9.10.0
// module versions:
// rlp@2.0.0
// keccak@1.4.0

const rlp = require("rlp");
const keccak = require("keccak");

var nonce = 0x00; //The nonce must be a hex literal!
var sender = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"; //Requires a hex string as input!

var input_arr = [sender, nonce];
var rlp_encoded = rlp.encode(input_arr);

var contract_address_long = keccak("keccak256")
  .update(rlp_encoded)
  .digest("hex");

var contract_address = contract_address_long.substring(24); //Trim the first 24 characters.
console.log("contract_address: " + contract_address);

Beachten Sie, dass die Nonce normal inkrementiert werden kann, denken Sie nur daran, dass es sich um einen Hex-Wert handelt.

Ausgabe (nonce = 0x00):

contract_address: cd234a471b72ba2f1ccf0a70fcaba648a5eecd8d

Ausgabe (nonce = 0x01):

contract_address: 343c43a37d37dff08ae8c4a11544c718abb4fcf8
Was ist rlp ?
Hier ist eine gute Erklärung: ethereum.stackexchange.com/questions/19092/…

Hier ist die aktualisierte Python-Version für moderne Ethereum-Bibliotheken ( eth-utils):

import rlp
from eth_utils import keccak, to_checksum_address, to_bytes


def mk_contract_address(sender: str, nonce: int) -> str:
    """Create a contract address using eth-utils.

    # https://ethereum.stackexchange.com/a/761/620
    """
    sender_bytes = to_bytes(hexstr=sender)
    raw = rlp.encode([sender_bytes, nonce])
    h = keccak(raw)
    address_bytes = h[12:]
    return to_checksum_address(address_bytes)


print(to_checksum_address(mk_contract_address(to_checksum_address("0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"), 1)))
print("0x343c43a37d37dff08ae8c4a11544c718abb4fcf8")
assert mk_contract_address(to_checksum_address("0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0"), 1) == \
    to_checksum_address("0x343c43a37d37dff08ae8c4a11544c718abb4fcf8")

RLP in Solidität durchgeführt (habe dies jedoch nicht getestet, Vorsicht! nur zum Verständnis):

    function addressFrom(address _origin, uint _nonce) public pure returns (address) {
        if(_nonce == 0x00)     return address(keccak256(byte(0xd6), byte(0x94), _origin, byte(0x80)));
        if(_nonce <= 0x7f)     return address(keccak256(byte(0xd6), byte(0x94), _origin, byte(_nonce)));
        if(_nonce <= 0xff)     return address(keccak256(byte(0xd7), byte(0x94), _origin, byte(0x81), uint8(_nonce)));
        if(_nonce <= 0xffff)   return address(keccak256(byte(0xd8), byte(0x94), _origin, byte(0x82), uint16(_nonce)));
        if(_nonce <= 0xffffff) return address(keccak256(byte(0xd9), byte(0x94), _origin, byte(0x83), uint24(_nonce)));
        return address(keccak256(byte(0xda), byte(0x94), _origin, byte(0x84), uint32(_nonce))); // more than 2^32 nonces not realistic
    }
Danke fürs Teilen, frage mich, woher du diese magischen Zahlen hast: 0x7f, 0xd6, 0x94
Die Nonce kann niemals 0 sein, sodass der erste Test entfernt werden kann.
Nonce beginnt mit Null, siehe Transaktionen auf Etherscan.

Hier ist eine reine ethers.js-Implementierung in TypeScript, die eine Adresse mit Prüfsumme zurückgibt. nonce wird voraussichtlich regelmäßig sein number.

(ethers.js hat auch eine aufgerufene Funktion getContractAddress, kann aber nicht für Nonce verwendet werden)

import { ethers } from 'hardhat';

static getContractAddress(address: string, nonce: number): string {
    const rlp_encoded = ethers.utils.RLP.encode(
        [address, ethers.BigNumber.from(nonce.toString()).toHexString()]
    );
    const contract_address_long = ethers.utils.keccak256(rlp_encoded);
    const contract_address = '0x'.concat(contract_address_long.substring(26));
    return ethers.utils.getAddress(contract_address);
}

Diese Implementierung funktioniert, falls die Nonce größer als 0 ist. Für Nonce = 0 ist das Ergebnis nicht korrekt (siehe Beispiel und vergleiche mit dem Ergebnis der obersten Antwort). Ein einfacher Einzeiler, der in ethers.js korrekt funktioniert, istconst contractAddress = ethers.utils.getContractAddress({from, nonce});
@GongFu ja, besser die eingebaute Funktion verwenden. Ich glaube, ich habe damals eine veraltete Version von Ethers verwendet, die diese Funktion nicht hatte.

Die Vertragsadresse ist typischerweise ein Hash aus der Adresse des Absenders und der Brieftasche des Absenders. Der tatsächliche Vertragscode spielt keine Rolle - der Hash ist unabhängig vom Code derselbe.

Oben habe ich typisch gesagt, weil es andere Möglichkeiten gibt, Verträge einzusetzen. Wenn ein bestehender Vertrag einen Vertrag mit einem speziellen Opcode bereitstellt CREATE2, wird die Vertragsadresse etwas anders berechnet.

Einzelheiten können Sie beispielsweise hier überprüfen: https://medium.com/coinmonks/smart-contract-address-creation-method-difference-between-smart-contract-address-and-wallet-97b421506455

Positiv bewertet, aber mit früherer Frage zusammengeführt, um Antworten zu sammeln.
Ich habe mich schon gefragt, ob ich versehentlich eine Frage mit bereits gültigen vorherigen Antworten beantwortet habe.
Kein Problem! Manchmal hilfreich zum Zusammenführen, manchmal nicht. Danke für all deine Arbeit. (Ich habe viele positiv bewertet, aber viele andere scheinen nicht viel zu wählen.)