diff --git a/bchain/coins/bch/bcashparser.go b/bchain/coins/bch/bcashparser.go index 3a732f85..8f6fd53b 100644 --- a/bchain/coins/bch/bcashparser.go +++ b/bchain/coins/bch/bcashparser.go @@ -166,7 +166,7 @@ func (p *BCashParser) outputScriptToAddresses(script []byte) ([]string, bool, er // do not return unknown script type error as error if err.Error() == "unknown script type" { // try OP_RETURN script - or := btc.TryParseOPReturn(script) + or := p.TryParseOPReturn(script) if or != "" { return []string{or}, false, nil } diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 98acc001..b53f7044 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -105,7 +105,7 @@ func (p *BitcoinParser) addressToOutputScript(address string) ([]byte, error) { } // TryParseOPReturn tries to process OP_RETURN script and return its string representation -func TryParseOPReturn(script []byte) string { +func (p *BitcoinParser) TryParseOPReturn(script []byte) string { if len(script) > 1 && script[0] == txscript.OP_RETURN { // trying 2 variants of OP_RETURN data // 1) OP_RETURN OP_PUSHDATA1 @@ -124,8 +124,12 @@ func TryParseOPReturn(script []byte) string { data = script[2:] } if l == len(data) { + var ed string - // TODO try parse OMNI + ed = p.tryOmniParser(data) + if ed != "" { + return ed + } isASCII := true for _, c := range data { @@ -134,7 +138,6 @@ func TryParseOPReturn(script []byte) string { break } } - var ed string if isASCII { ed = "(" + string(data) + ")" } else { @@ -146,6 +149,39 @@ func TryParseOPReturn(script []byte) string { return "" } +var omniCurrencyMap = map[uint32]string{ + 1: "Omni", + 2: "Test Omni", + 31: "TetherUS", +} + +// try to parse Omni transaction from script to human-readable string +func (p *BitcoinParser) tryOmniParser(data []byte) string { + + // Currently only simple send transaction is supported, see + // https://github.com/OmniLayer/spec#transfer-coins-simple-send + if len(data) != 20 && data[0] != 111 { + return "" + } + // omni (4) (2) (2) + omni_header := []byte{111, 109, 110, 105, 0, 0, 0, 0} + if bytes.Compare(data[0:8], omni_header) != 0 { + return "" + } + + currency_id := binary.BigEndian.Uint32(data[8:12]) + currency, ok := omniCurrencyMap[currency_id] + if !ok { + return "" + } + amount := new(big.Int) + amount.SetBytes(data[12:]) + amount_str := p.AmountToDecimalString(amount) + + ed := "OMNI Simple Send " + amount_str + " " + currency + " (#" + strconv.Itoa(int(currency_id)) + ")" + return ed +} + // outputScriptToAddresses converts ScriptPubKey to addresses with a flag that the addresses are searchable func (p *BitcoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { sc, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) @@ -160,7 +196,7 @@ func (p *BitcoinParser) outputScriptToAddresses(script []byte) ([]string, bool, if sc == txscript.PubKeyHashTy || sc == txscript.WitnessV0PubKeyHashTy || sc == txscript.ScriptHashTy || sc == txscript.WitnessV0ScriptHashTy { s = true } else if len(rv) == 0 { - or := TryParseOPReturn(script) + or := p.TryParseOPReturn(script) if or != "" { rv = []string{or} } diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index 1a441393..45468869 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -215,8 +215,27 @@ func TestGetAddressesFromAddrDesc(t *testing.T) { want2: false, wantErr: false, }, - - // TODO test case for omni + { + name: "OP_RETURN omni simple send tether", + args: args{script: "6a146f6d6e69000000000000001f00000709bb647351"}, + want: []string{"OMNI Simple Send 77383.80022609 TetherUS (#31)"}, + want2: false, + wantErr: false, + }, + { + name: "OP_RETURN omni simple send not supported coin", + args: args{script: "6a146f6d6e69000000000000000300000709bb647351"}, + want: []string{"OP_RETURN 6f6d6e69000000000000000300000709bb647351"}, + want2: false, + wantErr: false, + }, + { + name: "OP_RETURN omni not supported version", + args: args{script: "6a146f6d6e69010000000000000300000709bb647351"}, + want: []string{"OP_RETURN 6f6d6e69010000000000000300000709bb647351"}, + want2: false, + wantErr: false, + }, } parser := NewBitcoinParser(GetChainParams("main"), &Configuration{})