Estoy tratando de derivar los cambios de almacenamiento de cuentas asignando cuentas (aquí, las cuentas representan la dirección clave en el mapeo de asignación de saldos ERC20 (dirección => uint256) ) a sus claves de almacenamiento correspondientes a partir de un seguimiento de transacción de paridad.
Un seguimiento de ejemplo (obtenido a través de web3.py) de la transacción https://etherscan.io/tx/0x210cfe3d3b62f415ed0327a3c6177086df4937b6280031255360b6d137308554 es:
{
'output': '0x',
'stateDiff': {
'0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5': {
'balance': {
'*': {
'from': '0x122291885d6222bc5ec',
'to': '0x12229193ca3f58565ec'
}
},
'code': '=',
'nonce': '=',
'storage': {}
},
'0xaddba95f769b5d42c02e144102817eab9d00efd3': {
'balance': '=',
'code': '=',
'nonce': '=',
'storage': {
'0x1ded6755a6d7d843883da8cd8948931cf9f8b1e8f8983ad77e1685ece0b92fc2': {
'*': {
'from': '0x0000000000000000000000000000000000000000000000000000000000000000',
'to': '0x000000000000000000000000000000000000000000000000000bfb8d0ebc5000'
}
},
'0x5020d77d5345022a5466af6f78731b10f92d31e17961c23ea6ce5c185dc75d49': {
'*': {
'from': '0x0000000000000000000000000000000000000000000000000000000000000000',
'to': '0x0000000000000000000000000000000000000000000000000000e1412a5f1c00'
}
}
}
},
'0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40': {
'balance': {
'*': {
'from': '0x2c4c7111f4801a8',
'to': '0x2c410434bee61a8'
}
},
'code': '=',
'nonce': {
'*': {
'from': '0x143',
'to': '0x144'
}
},
'storage': {}
}
},
'trace': [{
'action': {
'callType': 'call',
'from': '0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40',
'gas': '0x9008',
'input': '0xa9059cbb000000000000000000000000e034e561ce112c5f261f15d447e8f2436d9625040000000000000000000000000000000000000000000000000000e130de0be000',
'to': '0xaddba95f769b5d42c02e144102817eab9d00efd3',
'value': '0x0'
},
'result': {
'gasUsed': '0x3924',
'output': '0x'
},
'subtraces': 0,
'traceAddress': [],
'type': 'call'
}],
'vmTrace': None
}
Según https://solidity.readthedocs.io/en/v0.4.24/miscellaneous.html#layout-of-state-variables-in-storage , "el valor correspondiente a una clave de mapeo k se encuentra en keccak256(k . p ) donde . es concatenación". Soy consciente del pad izquierdo necesario, de acuerdo con "keccack(LeftPad32(key, 0), LeftPad32(map position, 0))" https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat , aunque las funciones hash parecen manejar esto internamente.
Probé el Web3.sha3() para esta clave de almacenamiento keccak256, y otros problemas en StackOverflow mencionan que Solidity emplea un algoritmo hash ligeramente diferente. Nevertheless, also by using the proper Web3.soliditySha3() I do not arrive at a hash that would present me the key found in the the trace (here, 0x1ded6755a6d7d843883da8cd8948931cf9f8b1e8f8983ad77e1685ece0b92fc2 or 0x5020d77d5345022a5466af6f78731b10f92d31e17961c23ea6ce5c185dc75d49 ) to the account 0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40 .
¿Cuál es la forma correcta (preferiblemente con web3.py) de cifrar la cuenta y la posición para llegar a la clave de almacenamiento de mapas?
Como mencionó @jaime en los comentarios, necesita la position
variable de mapeo para encontrar la relación entre address
y storage key
.
Puede encontrar un código que he escrito para detectar el position
contrato erc20 básico a continuación (usando web3.py):
import json
from web3.auto.infura import w3
from eth_utils import remove_0x_prefix, to_int, to_checksum_address, to_hex
# erc20 contract address
CONTRACT_ADDRESS = '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7'
# address with non zero token balance
HOLDER_ADDRESS = '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb'
def getStorageAtIndex(i):
pos = str(i).rjust(64, '0')
key = remove_0x_prefix(HOLDER_ADDRESS).rjust(64, '0').lower()
storage_key = to_hex(w3.sha3(hexstr=key + pos))
return to_int(w3.eth.getStorageAt(CONTRACT_ADDRESS, storage_key))
for i in range(0, 20):
if getStorageAtIndex(i) != 0:
print("position is {}".format(i))
Resultado:
>>> position is 5
Una vez que tenga el valor correcto de la posición, puede obtener fácilmente los valores almacenados en el contrato.
pos = str(5).rjust(64, '0')
key = remove_0x_prefix(HOLDER_ADDRESS).rjust(64, '0').lower()
storage_key = to_hex(w3.sha3(hexstr=key + pos))
w3.eth.getStorageAt(CONTRACT_ADDRESS, storage_key)
Jaime
Daniel