code.vegaprotocol.io/vega@v0.79.0/core/datasource/external/openoracle/openoracle.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package openoracle
    17  
    18  import (
    19  	"encoding/hex"
    20  	"encoding/json"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/ethereum/go-ethereum/accounts"
    25  	"github.com/ethereum/go-ethereum/accounts/abi"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  )
    28  
    29  type OracleResponse struct {
    30  	Timestamp  string            `json:"timestamp"`
    31  	Messages   []string          `json:"messages"`
    32  	Signatures []string          `json:"signatures"`
    33  	Prices     map[string]string `json:"prices"`
    34  }
    35  
    36  // UnmarshalVerify will unmarshal a json raw payload
    37  // into and OracleResponse
    38  // if the unmarshal is successful then the content is verified.
    39  func UnmarshalVerify(payload []byte, address string) (*OracleResponse, error) {
    40  	oresp, err := Unmarshal(payload)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	_, _, err = Verify(*oresp)
    46  	return oresp, err
    47  }
    48  
    49  func Unmarshal(payload []byte) (*OracleResponse, error) {
    50  	oresp := OracleResponse{}
    51  	err := json.Unmarshal(payload, &oresp)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return &oresp, nil
    56  }
    57  
    58  func Verify(oresp OracleResponse) ([]string, map[string]string, error) {
    59  	typString, err := abi.NewType("string", "", nil)
    60  	if err != nil {
    61  		return nil, nil, err
    62  	}
    63  
    64  	typUint64, err := abi.NewType("uint64", "", nil)
    65  	if err != nil {
    66  		return nil, nil, err
    67  	}
    68  
    69  	args := abi.Arguments([]abi.Argument{
    70  		{
    71  			Name: "kind",
    72  			Type: typString,
    73  		},
    74  		{
    75  			Name: "timestamp",
    76  			Type: typUint64,
    77  		},
    78  		{
    79  			Name: "key",
    80  			Type: typString,
    81  		},
    82  		{
    83  			Name: "value",
    84  			Type: typUint64,
    85  		},
    86  	})
    87  
    88  	// ensure we have as much signature than messages
    89  	if len(oresp.Messages) != len(oresp.Signatures) {
    90  		return nil, nil, fmt.Errorf("got %v signatures, but have %v messages", len(oresp.Signatures), len(oresp.Messages))
    91  	}
    92  
    93  	addresses := map[string]struct{}{}
    94  	keyValues := map[string]string{}
    95  
    96  	for i := 0; i < len(oresp.Messages); i++ {
    97  		sigBytes, err := hex.DecodeString(strings.TrimPrefix(oresp.Signatures[i], "0x"))
    98  		if err != nil {
    99  			return nil, nil, err
   100  		}
   101  		msgBytes, err := hex.DecodeString(strings.TrimPrefix(oresp.Messages[i], "0x"))
   102  		if err != nil {
   103  			return nil, nil, err
   104  		}
   105  		hashDecoded := crypto.Keccak256Hash(msgBytes)
   106  		hashDecodedPadded := accounts.TextHash(hashDecoded.Bytes())
   107  
   108  		if len(sigBytes) > 65 {
   109  			sigBytes[64] = sigBytes[len(sigBytes)-1]
   110  			sigBytes = sigBytes[:65]
   111  		}
   112  		sigBytes[64] = sigBytes[64] - 27
   113  
   114  		// SigToPub actually goes through the verification of the signature
   115  		// before returning the pubkey that we can use to retrieve the address later
   116  		// on. so no need for extra steps in verifying the signature later on.
   117  		sigPublicKeyECDSA, err := crypto.SigToPub(hashDecodedPadded, sigBytes)
   118  		if err != nil {
   119  			return nil, nil, err
   120  		}
   121  
   122  		addrHex := crypto.PubkeyToAddress(*sigPublicKeyECDSA).Hex()
   123  		addresses[addrHex] = struct{}{}
   124  
   125  		m := map[string]interface{}{}
   126  		err = args.UnpackIntoMap(m, msgBytes)
   127  		if err != nil {
   128  			return nil, nil, err
   129  		}
   130  
   131  		keyValues[fmt.Sprintf("%v.%v.value", m["kind"], m["key"])] = fmt.Sprintf("%v", m["value"])
   132  		keyValues[fmt.Sprintf("%v.%v.timestamp", m["kind"], m["key"])] = fmt.Sprintf("%v", m["timestamp"])
   133  	}
   134  
   135  	addressesSlice := make([]string, 0, len(addresses))
   136  	for k := range addresses {
   137  		addressesSlice = append(addressesSlice, k)
   138  	}
   139  
   140  	return addressesSlice, keyValues, nil
   141  }