/
abi_encode.go
150 lines (132 loc) · 3.81 KB
/
abi_encode.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
140
141
142
143
144
145
146
147
148
149
150
package types
import (
fmt "fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
oracletypes "github.com/ojo-network/ojo/x/oracle/types"
)
const (
// TypeUnrecognized means coin type is unrecognized
TypeUnrecognized = iota
// TypeGeneralMessage is a pure message
TypeGeneralMessage
// TypeGeneralMessageWithToken is a general message with token
TypeGeneralMessageWithToken
// TypeSendToken is a direct token transfer
TypeSendToken
)
// GmpEncoder is the struct we use to encode the data we want to send to the GMP.
type GmpEncoder struct {
PriceData []PriceData
AssetNames [][32]byte
ContractAddress common.Address
CommandSelector [4]byte
CommandParams []byte
}
// MedianData is the struct that represents the MedianData tuple in Solidity.
type MedianData struct {
BlockNums []*big.Int
Medians []*big.Int
Deviations []*big.Int
}
// PriceData is the struct that represents the PriceData tuple in Solidity.
type PriceData struct {
AssetName [32]byte
Price *big.Int
ResolveTime *big.Int
MedianData MedianData
}
// encoderSpec is the ABI specification for the GMP data.
var encoderSpec = abi.Arguments{
{
Type: priceDataType,
},
{
Type: assetNamesType,
},
{
Type: contractAddressType,
},
{
Type: commandSelectorType,
},
{
Type: commandParamsType,
},
}
// GMPEncode encodes the GMP data into a byte array.
func (g GmpEncoder) GMPEncode() ([]byte, error) {
return encoderSpec.Pack(g.PriceData, g.AssetNames, g.ContractAddress, g.CommandSelector, g.CommandParams)
}
func NewGMPEncoder(
priceData []PriceData,
assetName []string,
contractAddress common.Address,
commandSelector [4]byte,
commandParams []byte,
) GmpEncoder {
return GmpEncoder{
PriceData: priceData,
AssetNames: namesToBytes(assetName),
ContractAddress: contractAddress,
CommandSelector: commandSelector,
CommandParams: commandParams,
}
}
func nameToBytes32(name string) [32]byte {
var nameBytes [32]byte
copy(nameBytes[:], []byte(name))
return nameBytes
}
func namesToBytes(assetNames []string) [][32]byte {
assetNamesBytes := make([][32]byte, len(assetNames))
for i, name := range assetNames {
assetNamesBytes[i] = nameToBytes32(name)
}
return assetNamesBytes
}
func NewPriceData(
assetName string,
price sdk.Dec,
resolveTime *big.Int,
medianData MedianData,
) (PriceData, error) {
assetSlice := []byte(assetName)
if len(assetSlice) > 32 {
return PriceData{}, fmt.Errorf(
"asset name is too long to convert to array: %s", assetName,
)
}
var assetArray [32]byte
copy(assetArray[:], assetSlice)
return PriceData{
AssetName: assetArray,
Price: decToInt(price),
ResolveTime: resolveTime,
MedianData: medianData,
}, nil
}
// DecToInt multiplies amount by rate factor to make it compatible with contracts.
func decToInt(amount sdk.Dec) *big.Int {
return amount.Mul(rateFactor).TruncateInt().BigInt()
}
var rateFactor = sdk.NewDec(10).Power(9)
// NewMedianData creates a MedianData object of medians and deviations and their block numbers.
func NewMedianData(medians oracletypes.PriceStamps, deviations oracletypes.PriceStamps) (MedianData, error) {
if len(medians) != len(deviations) {
return MedianData{}, fmt.Errorf("length of medians and deviations must be equal")
}
medianData := MedianData{
BlockNums: make([]*big.Int, 0, len(medians)),
Medians: make([]*big.Int, 0, len(medians)),
Deviations: make([]*big.Int, 0, len(medians)),
}
for i, median := range medians {
medianData.BlockNums = append(medianData.BlockNums, big.NewInt(int64(median.BlockNum)))
medianData.Medians = append(medianData.Medians, decToInt(median.ExchangeRate.Amount))
medianData.Deviations = append(medianData.Deviations, decToInt(deviations[i].ExchangeRate.Amount))
}
return medianData, nil
}