github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/accounts/abi/event_test.go (about) 1 package abi 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "math/big" 8 "reflect" 9 "strings" 10 "testing" 11 12 "github.com/neatio-net/neatio/utilities/common" 13 "github.com/neatio-net/neatio/utilities/crypto" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 var jsonEventTransfer = []byte(`{ 19 "anonymous": false, 20 "inputs": [ 21 { 22 "indexed": true, "name": "from", "type": "address" 23 }, { 24 "indexed": true, "name": "to", "type": "address" 25 }, { 26 "indexed": false, "name": "value", "type": "uint256" 27 }], 28 "name": "Transfer", 29 "type": "event" 30 }`) 31 32 var jsonEventPledge = []byte(`{ 33 "anonymous": false, 34 "inputs": [{ 35 "indexed": false, "name": "who", "type": "address" 36 }, { 37 "indexed": false, "name": "wad", "type": "uint128" 38 }, { 39 "indexed": false, "name": "currency", "type": "bytes3" 40 }], 41 "name": "Pledge", 42 "type": "event" 43 }`) 44 45 var jsonEventMixedCase = []byte(`{ 46 "anonymous": false, 47 "inputs": [{ 48 "indexed": false, "name": "value", "type": "uint256" 49 }, { 50 "indexed": false, "name": "_value", "type": "uint256" 51 }, { 52 "indexed": false, "name": "Value", "type": "uint256" 53 }], 54 "name": "MixedCase", 55 "type": "event" 56 }`) 57 58 var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240" 59 60 var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000" 61 62 var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241" 63 64 func TestEventId(t *testing.T) { 65 var table = []struct { 66 definition string 67 expectations map[string]common.Hash 68 }{ 69 { 70 definition: `[ 71 { "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, 72 { "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } 73 ]`, 74 expectations: map[string]common.Hash{ 75 "Balance": crypto.Keccak256Hash([]byte("Balance(uint256)")), 76 "Check": crypto.Keccak256Hash([]byte("Check(address,uint256)")), 77 }, 78 }, 79 } 80 81 for _, test := range table { 82 abi, err := JSON(strings.NewReader(test.definition)) 83 if err != nil { 84 t.Fatal(err) 85 } 86 87 for name, event := range abi.Events { 88 if event.ID() != test.expectations[name] { 89 t.Errorf("expected id to be %x, got %x", test.expectations[name], event.ID()) 90 } 91 } 92 } 93 } 94 95 func TestEventString(t *testing.T) { 96 var table = []struct { 97 definition string 98 expectations map[string]string 99 }{ 100 { 101 definition: `[ 102 { "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, 103 { "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }, 104 { "type" : "event", "name" : "Transfer", "inputs": [{ "name": "from", "type": "address", "indexed": true }, { "name": "to", "type": "address", "indexed": true }, { "name": "value", "type": "uint256" }] } 105 ]`, 106 expectations: map[string]string{ 107 "Balance": "event Balance(uint256 in)", 108 "Check": "event Check(address t, uint256 b)", 109 "Transfer": "event Transfer(address indexed from, address indexed to, uint256 value)", 110 }, 111 }, 112 } 113 114 for _, test := range table { 115 abi, err := JSON(strings.NewReader(test.definition)) 116 if err != nil { 117 t.Fatal(err) 118 } 119 120 for name, event := range abi.Events { 121 if event.String() != test.expectations[name] { 122 t.Errorf("expected string to be %s, got %s", test.expectations[name], event.String()) 123 } 124 } 125 } 126 } 127 128 func TestEventMultiValueWithArrayUnpack(t *testing.T) { 129 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` 130 type testStruct struct { 131 Value1 [2]uint8 132 Value2 uint8 133 } 134 abi, err := JSON(strings.NewReader(definition)) 135 require.NoError(t, err) 136 var b bytes.Buffer 137 var i uint8 = 1 138 for ; i <= 3; i++ { 139 b.Write(packNum(reflect.ValueOf(i))) 140 } 141 var rst testStruct 142 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 143 require.Equal(t, [2]uint8{1, 2}, rst.Value1) 144 require.Equal(t, uint8(3), rst.Value2) 145 } 146 147 func TestEventTupleUnpack(t *testing.T) { 148 149 type EventTransfer struct { 150 Value *big.Int 151 } 152 153 type EventTransferWithTag struct { 154 value *big.Int 155 Value1 *big.Int `abi:"value"` 156 } 157 158 type BadEventTransferWithSameFieldAndTag struct { 159 Value *big.Int 160 Value1 *big.Int `abi:"value"` 161 } 162 163 type BadEventTransferWithDuplicatedTag struct { 164 Value1 *big.Int `abi:"value"` 165 Value2 *big.Int `abi:"value"` 166 } 167 168 type BadEventTransferWithEmptyTag struct { 169 Value *big.Int `abi:""` 170 } 171 172 type EventPledge struct { 173 Who common.Address 174 Wad *big.Int 175 Currency [3]byte 176 } 177 178 type BadEventPledge struct { 179 Who string 180 Wad int 181 Currency [3]byte 182 } 183 184 type EventMixedCase struct { 185 Value1 *big.Int `abi:"value"` 186 Value2 *big.Int `abi:"_value"` 187 Value3 *big.Int `abi:"Value"` 188 } 189 190 bigint := new(big.Int) 191 bigintExpected := big.NewInt(1000000) 192 bigintExpected2 := big.NewInt(2218516807680) 193 bigintExpected3 := big.NewInt(1000001) 194 addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268") 195 var testCases = []struct { 196 data string 197 dest interface{} 198 expected interface{} 199 jsonLog []byte 200 error string 201 name string 202 }{{ 203 transferData1, 204 &EventTransfer{}, 205 &EventTransfer{Value: bigintExpected}, 206 jsonEventTransfer, 207 "", 208 "Can unpack ERC20 Transfer event into structure", 209 }, { 210 transferData1, 211 &[]interface{}{&bigint}, 212 &[]interface{}{&bigintExpected}, 213 jsonEventTransfer, 214 "", 215 "Can unpack ERC20 Transfer event into slice", 216 }, { 217 transferData1, 218 &EventTransferWithTag{}, 219 &EventTransferWithTag{Value1: bigintExpected}, 220 jsonEventTransfer, 221 "", 222 "Can unpack ERC20 Transfer event into structure with abi: tag", 223 }, { 224 transferData1, 225 &BadEventTransferWithDuplicatedTag{}, 226 &BadEventTransferWithDuplicatedTag{}, 227 jsonEventTransfer, 228 "struct: abi tag in 'Value2' already mapped", 229 "Can not unpack ERC20 Transfer event with duplicated abi tag", 230 }, { 231 transferData1, 232 &BadEventTransferWithSameFieldAndTag{}, 233 &BadEventTransferWithSameFieldAndTag{}, 234 jsonEventTransfer, 235 "abi: multiple variables maps to the same abi field 'value'", 236 "Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable", 237 }, { 238 transferData1, 239 &BadEventTransferWithEmptyTag{}, 240 &BadEventTransferWithEmptyTag{}, 241 jsonEventTransfer, 242 "struct: abi tag in 'Value' is empty", 243 "Can not unpack ERC20 Transfer event with an empty tag", 244 }, { 245 pledgeData1, 246 &EventPledge{}, 247 &EventPledge{ 248 addr, 249 bigintExpected2, 250 [3]byte{'u', 's', 'd'}}, 251 jsonEventPledge, 252 "", 253 "Can unpack Pledge event into structure", 254 }, { 255 pledgeData1, 256 &[]interface{}{&common.Address{}, &bigint, &[3]byte{}}, 257 &[]interface{}{ 258 &addr, 259 &bigintExpected2, 260 &[3]byte{'u', 's', 'd'}}, 261 jsonEventPledge, 262 "", 263 "Can unpack Pledge event into slice", 264 }, { 265 pledgeData1, 266 &[3]interface{}{&common.Address{}, &bigint, &[3]byte{}}, 267 &[3]interface{}{ 268 &addr, 269 &bigintExpected2, 270 &[3]byte{'u', 's', 'd'}}, 271 jsonEventPledge, 272 "", 273 "Can unpack Pledge event into an array", 274 }, { 275 pledgeData1, 276 &[]interface{}{new(int), 0, 0}, 277 &[]interface{}{}, 278 jsonEventPledge, 279 "abi: cannot unmarshal common.Address in to int", 280 "Can not unpack Pledge event into slice with wrong types", 281 }, { 282 pledgeData1, 283 &BadEventPledge{}, 284 &BadEventPledge{}, 285 jsonEventPledge, 286 "abi: cannot unmarshal common.Address in to string", 287 "Can not unpack Pledge event into struct with wrong filed types", 288 }, { 289 pledgeData1, 290 &[]interface{}{common.Address{}, new(big.Int)}, 291 &[]interface{}{}, 292 jsonEventPledge, 293 "abi: insufficient number of elements in the list/array for unpack, want 3, got 2", 294 "Can not unpack Pledge event into too short slice", 295 }, { 296 pledgeData1, 297 new(map[string]interface{}), 298 &[]interface{}{}, 299 jsonEventPledge, 300 "abi: cannot unmarshal tuple into map[string]interface {}", 301 "Can not unpack Pledge event into map", 302 }, { 303 mixedCaseData1, 304 &EventMixedCase{}, 305 &EventMixedCase{Value1: bigintExpected, Value2: bigintExpected2, Value3: bigintExpected3}, 306 jsonEventMixedCase, 307 "", 308 "Can unpack abi variables with mixed case", 309 }} 310 311 for _, tc := range testCases { 312 assert := assert.New(t) 313 tc := tc 314 t.Run(tc.name, func(t *testing.T) { 315 err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert) 316 if tc.error == "" { 317 assert.Nil(err, "Should be able to unpack event data.") 318 assert.Equal(tc.expected, tc.dest, tc.name) 319 } else { 320 assert.EqualError(err, tc.error, tc.name) 321 } 322 }) 323 } 324 } 325 326 func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, assert *assert.Assertions) error { 327 data, err := hex.DecodeString(hexData) 328 assert.NoError(err, "Hex data should be a correct hex-string") 329 var e Event 330 assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI") 331 a := ABI{Events: map[string]Event{"e": e}} 332 return a.Unpack(dest, "e", data) 333 } 334 335 func TestEventUnpackIndexed(t *testing.T) { 336 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` 337 type testStruct struct { 338 Value1 uint8 339 Value2 uint8 340 } 341 abi, err := JSON(strings.NewReader(definition)) 342 require.NoError(t, err) 343 var b bytes.Buffer 344 b.Write(packNum(reflect.ValueOf(uint8(8)))) 345 var rst testStruct 346 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 347 require.Equal(t, uint8(0), rst.Value1) 348 require.Equal(t, uint8(8), rst.Value2) 349 } 350 351 func TestEventIndexedWithArrayUnpack(t *testing.T) { 352 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]` 353 type testStruct struct { 354 Value1 [2]uint8 355 Value2 string 356 } 357 abi, err := JSON(strings.NewReader(definition)) 358 require.NoError(t, err) 359 var b bytes.Buffer 360 stringOut := "abc" 361 362 b.Write(packNum(reflect.ValueOf(32))) 363 b.Write(packNum(reflect.ValueOf(len(stringOut)))) 364 b.Write(common.RightPadBytes([]byte(stringOut), 32)) 365 366 var rst testStruct 367 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 368 require.Equal(t, [2]uint8{0, 0}, rst.Value1) 369 require.Equal(t, stringOut, rst.Value2) 370 }