🥷
Tackling Asset Hacks
With BlockVision's original APIs, we are able to estimate the asset loss, decode the hacker's transaction history, and enhance hacking prevention.
On March 29, the biggest theft in DeFi's history occurred. Ronin, the Ethereum sidechain developed by Sky Mavis, the parent company of Axie Infinity, was hacked and lost about 616 million US dollars. According to Ronin's official Twitter, the vulnerability occurred on March 23, but was discovered only after a user feedback failed to extract 5,000 ETH on the 29th. The attack is expected to result in a loss of 173,600 ETH (about US $590 million) and US $25.5 million worth of USDC.
At present, the official has suspended the operation of Ronin Bridge, saying that it is working with all parties to ensure that all funds can be recovered or reimbursed, and pointed out that the current user Axie related assets are now safe, but the current user cannot withdraw or deposit funds into Ronin.
Using the BlockVision API service to trace the source of the profit address chain, you can easily track the hacker's Hack account information, and reproduce the main source of funds for the address and which on-chain addresses went to.
After the attacker stole the asset from the sidechain Ronin, he transferred the asset across the chain to the Ethereum address: 0x098B716B8Aaf21512996dC57EB0615e2383E2f96.

Position Analysis

When the event of hacking attack or exploit on an exchange occurs, the project team would immediately want to evaluate the asset loss caused by the attack and analyze the transaction history of the hacker. BlockVision's computing layer and storage layer have an original solution to position changes of ETH and ERC20 Token, containing not only the current state of the contract and account data, but also the full Snapshot data history.
Developers can use BlockVision's erc20_accountPosition API to check the asset portfolio and the balance of each asset in the hacker's wallet.
1
var data = JSON.stringify({
2
"id": 1,
3
"jsonrpc": "2.0",
4
"method": "erc20_accountPosition",
5
"params": {
6
"accountAddress": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
7
"blockNumber": "",
8
"pageSize": 10,
9
"pageIndex": 1
10
}
11
});
12
13
var config = {
14
method: 'post',
15
url: 'https://api.blockvision.org/v1/<api key>',
16
headers: {
17
'Content-Type': 'application/json'
18
},
19
data : data
20
};
21
22
axios(config)
23
.then(function (response) {
24
console.log(JSON.stringify(response.data));
25
})
26
.catch(function (error) {
27
console.log(error);
28
});
Copied!
Result:
1
{
2
"jsonrpc": "2.0",
3
"id": 1,
4
"result": {
5
"data": [
6
{
7
"value": "420690000000000000000",
8
"contractAddress": "0x3fa400483487A489EC9b1dB29C4129063EEC4654"
9
},
10
{
11
"value": "13300000000000000000000000",
12
"contractAddress": "0x3301Ee63Fb29F863f2333Bd4466acb46CD8323E6"
13
},
14
{
15
"value": "1000000000000000000",
16
"contractAddress": "0xDd1Ad9A21Ce722C151A836373baBe42c868cE9a4"
17
},
18
{
19
"value": "599956120110530000000000000",
20
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92"
21
},
22
{
23
"value": "630000000000000000000",
24
"contractAddress": "0x933cdc9Baf562362BE4C31ad671E954C0f0F1Be2"
25
},
26
{
27
"value": "1000000000000000000",
28
"contractAddress": "0x4B1E80cAC91e2216EEb63e29B957eB91Ae9C2Be8"
29
},
30
{
31
"value": "106781260679439651303396",
32
"contractAddress": "0xEea2fEf22353282fb760d27EA7A1E2f06B3F442d"
33
}
34
],
35
"nextPageIndex": 1
36
}
37
}
Copied!
As we can see, there are seven types of ERC20 Token in the hacker's account and their values.
erc20_accountPosition is currently not open to all users, if you want to use it, please contact us via Discord or email

Transaction Path

After obtaining above-mentioned information, all transaction history of the hacker involving each stolen token from the hack to the present can be obtained by calling the erc20_transfers:
1
var data = JSON.stringify({
2
"id": 1,
3
"jsonrpc":"2.0",
4
"method":"erc20_transfers",
5
"params":[{
6
"blockNumber": 0,
7
"accountAddress": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
8
}]
9
});
10
11
var config = {
12
method: 'post',
13
url: 'https://api.blockvision.org/v1/<api key>',
14
headers: {
15
'Content-Type': 'application/json'
16
},
17
data : data
18
};
19
20
axios(config)
21
.then(function (response) {
22
console.log(JSON.stringify(response.data));
23
})
24
.catch(function (error) {
25
console.log(error);
26
});
Copied!
Result:
1
{
2
"jsonrpc": "2.0",
3
"id": 1,
4
"result": {
5
"data": [
6
{
7
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
8
"blockNumber": 14513028,
9
"txHash": "0x3b3a47f3b22fe610183bbe8f10b186cc0273aafd74a781bbf0fa409c45bf021b",
10
"blockHash": "0x0be7ede4635a2f5f383574a4736d028d9c751a0f6d3e2496c40f84337b79fd0b",
11
"logIndex": 370,
12
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
13
"to": "0x5E7c4E64d145085B0d0f131a91987c76e481f5cD",
14
"value": "1000000000000000000"
15
},
16
{
17
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
18
"blockNumber": 14513028,
19
"txHash": "0x3b3a47f3b22fe610183bbe8f10b186cc0273aafd74a781bbf0fa409c45bf021b",
20
"blockHash": "0x0be7ede4635a2f5f383574a4736d028d9c751a0f6d3e2496c40f84337b79fd0b",
21
"logIndex": 369,
22
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
23
"to": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
24
"value": "9000000000000000000"
25
},
26
{
27
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
28
"blockNumber": 14512066,
29
"txHash": "0xe7c0664ed2ee32d934902d1a93c94741edca91f6fb891674e67d5bf5e20bdbd7",
30
"blockHash": "0x61616bd7c4e02ef4f9063e25618f98b1266fcf7d321b035219c48fc55dd49071",
31
"logIndex": 104,
32
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
33
"to": "0xEEEAe370BFAD18C24475287Ac54B9Ef89DB2Bb51",
34
"value": "9000000000000000000"
35
},
36
{
37
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
38
"blockNumber": 14512066,
39
"txHash": "0xe7c0664ed2ee32d934902d1a93c94741edca91f6fb891674e67d5bf5e20bdbd7",
40
"blockHash": "0x61616bd7c4e02ef4f9063e25618f98b1266fcf7d321b035219c48fc55dd49071",
41
"logIndex": 105,
42
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
43
"to": "0x5E7c4E64d145085B0d0f131a91987c76e481f5cD",
44
"value": "1000000000000000000"
45
},
46
{
47
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
48
"blockNumber": 14512055,
49
"txHash": "0x22751935981948efcc736b2a129a61b04c048d03d4651cc2ca8000bfdcf8c3f5",
50
"blockHash": "0x942faf063b1ec9bf0bb9d931d38615f5fa1f620ea3a5cc8c2dffb0e38a5bee0c",
51
"logIndex": 331,
52
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
53
"to": "0x5E7c4E64d145085B0d0f131a91987c76e481f5cD",
54
"value": "1000000000000000000"
55
},
56
{
57
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
58
"blockNumber": 14512055,
59
"txHash": "0x22751935981948efcc736b2a129a61b04c048d03d4651cc2ca8000bfdcf8c3f5",
60
"blockHash": "0x942faf063b1ec9bf0bb9d931d38615f5fa1f620ea3a5cc8c2dffb0e38a5bee0c",
61
"logIndex": 330,
62
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
63
"to": "0xEEEAe370BFAD18C24475287Ac54B9Ef89DB2Bb51",
64
"value": "9000000000000000000"
65
},
66
{
67
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
68
"blockNumber": 14512040,
69
"txHash": "0x16bb322a4de5e371e615e106e30a99ca935b759864cf6b0dccf2b69e2ff95766",
70
"blockHash": "0x9c422e682dfd5c25aa4195507132cde1043816997623fcac651b4fda5d08569e",
71
"logIndex": 144,
72
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
73
"to": "0x5E7c4E64d145085B0d0f131a91987c76e481f5cD",
74
"value": "1000000000000000000"
75
},
76
{
77
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
78
"blockNumber": 14512040,
79
"txHash": "0x16bb322a4de5e371e615e106e30a99ca935b759864cf6b0dccf2b69e2ff95766",
80
"blockHash": "0x9c422e682dfd5c25aa4195507132cde1043816997623fcac651b4fda5d08569e",
81
"logIndex": 143,
82
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
83
"to": "0x4C036547DBB6B88FBC12f18db1b73eD849964ACF",
84
"value": "9000000000000000000"
85
},
86
{
87
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
88
"blockNumber": 14511390,
89
"txHash": "0xf610bbfbc6c4022d38e53a3aedf9a6fa9784beed02f53070b9cd13698f419b8c",
90
"blockHash": "0xd2f5f7ff6a5372cb5cf6b0d0bf97222338a91705e61c22e0af9fab4714a3baca",
91
"logIndex": 397,
92
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
93
"to": "0x5E7c4E64d145085B0d0f131a91987c76e481f5cD",
94
"value": "1000000000000000000"
95
},
96
{
97
"contractAddress": "0xe00a182284098e9c2ba89634544d51B0179c4C92",
98
"blockNumber": 14511390,
99
"txHash": "0xf610bbfbc6c4022d38e53a3aedf9a6fa9784beed02f53070b9cd13698f419b8c",
100
"blockHash": "0xd2f5f7ff6a5372cb5cf6b0d0bf97222338a91705e61c22e0af9fab4714a3baca",
101
"logIndex": 396,
102
"from": "0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
103
"to": "0x4C036547DBB6B88FBC12f18db1b73eD849964ACF",
104
"value": "9000000000000000000"
105
}
106
],
107
"nextPageIndex": 2
108
}
109
}
Copied!
We can use BlockVision's erc20_transfers API to write a simple trace/trace all programs related to hacker addresses. Here is demo that is written in Go:
1
package main
2
3
import (
4
"encoding/json"
5
"fmt"
6
"io/ioutil"
7
"net/http"
8
"strings"
9
)
10
11
type Key struct {
12
From string
13
To string
14
}
15
16
func getERC20TransferPage(index int) (map[Key]struct{}, bool) {
17
yourApiKey := "25rdPps5I8Xn35RSvP7hobjmmwr"
18
url := fmt.Sprintf("https://apis.blockvision.org/v1/%s", yourApiKey)
19
method := "POST"
20
21
//14442778 blockNumber is where the hack happened
22
params := `{
23
"id": 1,
24
"jsonrpc": "2.0",
25
"method": "erc20_transfers",
26
"params": {
27
"blockNumber": 0,
28
"accountAddress":"0x098B716B8Aaf21512996dC57EB0615e2383E2f96",
29
"pageSize": 10,
30
"pageIndex": %d
31
}
32
}`
33
34
payload := strings.NewReader(fmt.Sprintf(params, index))
35
36
client := &http.Client{}
37
req, err := http.NewRequest(method, url, payload)
38
39
if err != nil {
40
fmt.Println(err)
41
return nil, false
42
}
43
req.Header.Add("Content-Type", "application/json")
44
45
res, err := client.Do(req)
46
if err != nil {
47
fmt.Println(err)
48
return nil, false
49
}
50
defer res.Body.Close()
51
52
body, err := ioutil.ReadAll(res.Body)
53
if err != nil {
54
fmt.Println(err)
55
return nil, false
56
}
57
result := make(map[string]interface{})
58
err = json.Unmarshal(body, &result)
59
if err != nil {
60
fmt.Println(err)
61
return nil, false
62
}
63
data := result["result"].(map[string]interface{})
64
transfers := data["data"].([]interface{})
65
transferMap := make(map[Key]struct{})
66
for from := range transfers {
67
info := transfers[from].(map[string]interface{})
68
key := Key{From: info["from"].(string), To: info["to"].(string)}
69
transferMap[key] = struct{}{}
70
}
71
return transferMap, len(transfers) == 10
72
}
73
74
func main() {
75
totalTransferMap := make(map[Key]struct{})
76
index := 1
77
for {
78
tempTransferMap, hasMore := getERC20TransferPage(index)
79
fmt.Println("get page index success", index)
80
if len(tempTransferMap) == 0 || !hasMore {
81
break
82
}
83
for key := range tempTransferMap {
84
totalTransferMap[key] = struct{}{}
85
}
86
// time.Sleep(time.Second)
87
index++
88
}
89
for key := range totalTransferMap {
90
if strings.EqualFold(key.From, "0x098B716B8Aaf21512996dC57EB0615e2383E2f96") {
91
fmt.Println("from hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96 to ", key.To)
92
}
93
}
94
for key := range totalTransferMap {
95
if strings.EqualFold(key.To, "0x098B716B8Aaf21512996dC57EB0615e2383E2f96") {
96
fmt.Println(key.From, "to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96")
97
}
98
}
99
}
100
Copied!
Result:
1
from hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96 to 0x665660F65e94454A64b96693a67a41D440155617
2
...
3
from hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96 to 0xe708f17240732bBfa1BaA8513F66b665Fbc7ce10
4
...
5
from hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96 to 0x1A2a1c938CE3eC39b6D47113c7955bAa9DD454F2
6
...
7
0xe269D07aCE139330f0832456aC641f2062Aa19B5 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
8
0xF2Cbe54c7f351e0788b54d1924F0Ed2186cCB540 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
9
0x80C5e6908368CB9db503bA968d7ec5A565BFb389 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
10
0xAF0c57295e243f33Cf82f3C65bD49716a71BA59c to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
11
0xA3360E7E50fa5717d135A3EaFC5a50c020938D0E to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
12
0x562680a4dC50ed2f14d75BF31f494cfE0b8D10a1 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
13
0x03Cf40B900971561AC6bd997ef1Fe939DcbC95e2 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
14
0xA8550E06cb1332DBDD93E0FE578e9A63E3B79670 to hacker 0x098B716B8Aaf21512996dC57EB0615e2383E2f96
15
Copied!
Let's make the response prettier:
As we can see from Etherscan, after the hacker stole about 25,000,000 USDC from Ronin Bridge, he/she tried to transfer the token to other accounts. The hacker had already made a profit on March 23, and transferred the 25.5 million USDC and then converted it into ETH
The hacker first dispersed the 6250 ETH and transferred 1220 ETH to FTX, 1 ETH to Crypto.com, 3750 ETH to Huobi.

NFT Tackling

For NFT assets, you can do the same thing with BlockVision's NFT API. For users' convenience, BlockVision provides an integrated API nft_circulations .
Artificial price manipulation is usually done through multiple transactions from multiple wallets increasing prices each time they wash the asset. To help users identify this behavior, BlockVision provides users with historical transfer records for any NFT tokens, while allowing users to view the complete circulation record of an NFT (with a unique tokenid) through nft_circulations.
Just replace your api key and make a simple request in your terminal.
1
curl --location --request POST 'apis.blockvision.org/v1/<your-api-key>' \
2
--header 'Content-Type: application/json' \
3
--data-raw '{
4
"id": 1,
5
"jsonrpc": "2.0",
6
"method": "nft_circulations",
7
"params": {
8
"tokenID": "119",
9
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
10
"accountAddress": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652"
11
}
12
}'
Copied!
Response:
1
{
2
"jsonrpc": "2.0",
3
"id": 1,
4
"result": {
5
"data": [
6
{
7
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
8
"blockNumber": 13500151,
9
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
10
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
11
"logIndex": 131,
12
"from": "0x0000000000000000000000000000000000000000",
13
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
14
"tokenID": "119"
15
},
16
{
17
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
18
"blockNumber": 13500151,
19
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
20
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
21
"logIndex": 130,
22
"from": "0x0000000000000000000000000000000000000000",
23
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
24
"tokenID": "119"
25
},
26
{
27
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
28
"blockNumber": 13500151,
29
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
30
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
31
"logIndex": 132,
32
"from": "0x0000000000000000000000000000000000000000",
33
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
34
"tokenID": "119"
35
},
36
{
37
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
38
"blockNumber": 13500151,
39
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
40
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
41
"logIndex": 126,
42
"from": "0x0000000000000000000000000000000000000000",
43
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
44
"tokenID": "119"
45
},
46
{
47
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
48
"blockNumber": 13500151,
49
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
50
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
51
"logIndex": 128,
52
"from": "0x0000000000000000000000000000000000000000",
53
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
54
"tokenID": "119"
55
},
56
{
57
"contractAddress": "0xc78BfE5d749C8b37626695A1E165a55205b82C3c",
58
"blockNumber": 13500151,
59
"txHash": "0x4aac04ad09b6d5bfa1c31f7c2b643f28015f44e0f6f55f891b9fc5e64031d87e",
60
"blockHash": "0xa08929e926350d058f4ae4aaa8a032659d7b65aea487e47d4dbcaa7fc18848f8",
61
"logIndex": 129,
62
"from": "0x0000000000000000000000000000000000000000",
63
"to": "0x7768FBc67afecF2b4Caee9D1841ad14637D13652",
64
"tokenID": "119"
65
}
66
],
67
"nextPageIndex": 1
68
}
69
}
Copied!