/
asset_data_decoder.go
139 lines (122 loc) · 4.51 KB
/
asset_data_decoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package zeroex
import (
"errors"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
log "github.com/sirupsen/logrus"
)
// ERC20AssetDataID is the assetDataId for ERC20 tokens
const ERC20AssetDataID = "f47261b0"
// ERC721AssetDataID is the assetDataId for ERC721 tokens
const ERC721AssetDataID = "02571792"
// ERC1155AssetDataID is the assetDataId for ERC721 tokens
const ERC1155AssetDataID = "a7cb5fb7"
// MultiAssetDataID is the assetDataId for multiAsset tokens
const MultiAssetDataID = "94cfcdd7"
const erc20AssetDataAbi = "[{\"inputs\":[{\"name\":\"address\",\"type\":\"address\"}],\"name\":\"ERC20Token\",\"type\":\"function\"}]"
const erc721AssetDataAbi = "[{\"inputs\":[{\"name\":\"address\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721Token\",\"type\":\"function\"}]"
const erc1155AssetDataAbi = "[{\"constant\":false,\"inputs\":[{\"name\":\"address\",\"type\":\"address\"},{\"name\":\"ids\",\"type\":\"uint256[]\"},{\"name\":\"values\",\"type\":\"uint256[]\"},{\"name\":\"callbackData\",\"type\":\"bytes\"}],\"name\":\"ERC1155Assets\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
const multiAssetDataAbi = "[{\"inputs\":[{\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"name\":\"nestedAssetData\",\"type\":\"bytes[]\"}],\"name\":\"MultiAsset\",\"type\":\"function\"}]"
// ERC20AssetData represents an ERC20 assetData
type ERC20AssetData struct {
Address common.Address
}
// ERC721AssetData represents an ERC721 assetData
type ERC721AssetData struct {
Address common.Address
TokenId *big.Int
}
// ERC1155AssetData represents an ERC1155 assetData
type ERC1155AssetData struct {
Address common.Address
Ids []*big.Int
Values []*big.Int
CallbackData []byte
}
// MultiAssetData represents an MultiAssetData
type MultiAssetData struct {
Amounts []*big.Int
NestedAssetData [][]byte
}
type assetDataInfo struct {
name string
abi abi.ABI
}
// AssetDataDecoder decodes 0x order asset data
type AssetDataDecoder struct {
idToAssetDataInfo map[string]assetDataInfo
}
// NewAssetDataDecoder instantiates a new asset data decoder
func NewAssetDataDecoder() *AssetDataDecoder {
erc20AssetDataABI, err := abi.JSON(strings.NewReader(erc20AssetDataAbi))
if err != nil {
log.WithField("erc20AssetDataAbi", erc20AssetDataAbi).Panic("erc20AssetDataAbi should be ABI parsable")
}
erc721AssetDataABI, err := abi.JSON(strings.NewReader(erc721AssetDataAbi))
if err != nil {
log.WithField("erc721AssetDataAbi", erc721AssetDataAbi).Panic("erc721AssetDataAbi should be ABI parsable")
}
erc1155AssetDataABI, err := abi.JSON(strings.NewReader(erc1155AssetDataAbi))
if err != nil {
log.WithField("erc1155AssetDataAbi", erc1155AssetDataAbi).Panic("erc1155AssetDataAbi should be ABI parsable")
}
multiAssetDataABI, err := abi.JSON(strings.NewReader(multiAssetDataAbi))
if err != nil {
log.WithField("erc20AssetDataAbi", erc20AssetDataAbi).Panic("erc20AssetDataAbi should be ABI parsable")
}
idToAssetDataInfo := map[string]assetDataInfo{
ERC20AssetDataID: assetDataInfo{
name: "ERC20Token",
abi: erc20AssetDataABI,
},
ERC721AssetDataID: assetDataInfo{
name: "ERC721Token",
abi: erc721AssetDataABI,
},
ERC1155AssetDataID: assetDataInfo{
name: "ERC1155Assets",
abi: erc1155AssetDataABI,
},
MultiAssetDataID: assetDataInfo{
name: "MultiAsset",
abi: multiAssetDataABI,
},
}
decoder := &AssetDataDecoder{
idToAssetDataInfo: idToAssetDataInfo,
}
return decoder
}
// GetName returns the name of the assetData type
func (a *AssetDataDecoder) GetName(assetData []byte) (string, error) {
if len(assetData) < 4 {
return "", errors.New("assetData must be at least 4 bytes long")
}
id := assetData[:4]
idHex := common.Bytes2Hex(id)
info, ok := a.idToAssetDataInfo[idHex]
if !ok {
return "", errors.New(fmt.Sprintf("Unrecognized assetData with prefix: %s", idHex))
}
return info.name, nil
}
// Decode decodes an encoded asset data into it's sub-components
func (a *AssetDataDecoder) Decode(assetData []byte, decodedAssetData interface{}) error {
if len(assetData) < 4 {
return errors.New("assetData must be at least 4 bytes long")
}
id := assetData[:4]
idHex := common.Bytes2Hex(id)
info, ok := a.idToAssetDataInfo[idHex]
if !ok {
return errors.New(fmt.Sprintf("Unrecognized assetData with prefix: %s", idHex))
}
err := info.abi.Methods[info.name].Inputs.Unpack(decodedAssetData, assetData[4:])
if err != nil {
return err
}
return nil
}