Files
ark/common/note/note.go
Louis Singer ff96524f22 Ark Notes (#379)
* ark credits

* rename "ecash" --> "ark credit"

* rework note_test.go

* NewFromString

* create several notes

* note repo: rename "push" to "add"

* RegisterInputsForNextRoundRequest: move "notes" to field #3

* use uint64 as note ID

* rename to voucher

* add nostr notification

* nostr notification test and fixes

* bump badger to 4.3

* allow npub to be registered

* rename poolTxID

* add default relays

* Update server/internal/config/config.go

Co-authored-by: Marco Argentieri <3596602+tiero@users.noreply.github.com>

* fix RedeemVouchers test

* notification = voucher

* WASM wrappers

* fix arkd voucher cmd

* test_utils.go ignore gosec rule G101

* fix permissions

* rename ALL to notes

* add URI prefix

* note.go : fix signature encoding

* fix decode note.Data

* Update server/internal/infrastructure/notifier/nostr/nostr.go

Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com>

* Update pkg/client-sdk/wasm/browser/wrappers.go

Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com>

* Update server/internal/infrastructure/notifier/nostr/nostr.go

Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com>

* rework note and entity db + sqlite implementations

* NOTIFICATION_PREFIX -> NOTE_URI_PREFIX

* validate NOTE_URI_PREFIX

* Update defaults to convenant-less mainnet (#2)

* config: defaults to convenant-less tx builder

* Drop env var for blockchain scanner

---------

Co-authored-by: altafan <18440657+altafan@users.noreply.github.com>

* add // before URI prefix

* add URI prefix in admin CreateNote

* Fixes

* rework nonces encoding (#4)

* rework nonces encoding

* add a check in Musig2Nonce decode function

* musig2_test: increase number of signers to 20

* musig2.json: add a test case with a 35 leaves tree

* GetEventStream REST rework

* fix round phases time intervals

* [SDK] Use server-side streams in rest client

* Fix history

* make the URI optional

* Updates

* Fix settled txs in history

* fix e2e test

* go work sync in sdk unit test

* fix signMessage in btc and liquid sdk wallets

---------

Co-authored-by: Marco Argentieri <3596602+tiero@users.noreply.github.com>
Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com>
2024-11-15 19:07:33 +01:00

128 lines
2.8 KiB
Go

package note
import (
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"fmt"
"strings"
"github.com/btcsuite/btcd/btcutil/base58"
)
const noteHRP = "arknote"
// Note represents a note signed by the issuer
type Note struct {
Data
Signature []byte
}
// Data contains the data of a note
type Data struct {
ID uint64
Value uint32
}
// New generate a new note data struct with a random ID and the given value
// it must be signed by the issuer and then converted to a Note using Data.ToNote(signature)
func New(value uint32) (*Data, error) {
randomBytes := make([]byte, 8)
_, err := rand.Read(randomBytes)
if err != nil {
return nil, fmt.Errorf("failed to generate random ID: %w", err)
}
id := binary.BigEndian.Uint64(randomBytes)
return &Data{
ID: id,
Value: value,
}, nil
}
// NewFromString converts a base58 encoded string with HRP to a Note
func NewFromString(s string) (*Note, error) {
if !strings.HasPrefix(s, noteHRP) {
return nil, fmt.Errorf("invalid human-readable part: expected %s prefix (note '%s')", noteHRP, s)
}
encoded := strings.TrimPrefix(s, noteHRP)
decoded := base58.Decode(encoded)
if len(decoded) == 0 {
return nil, fmt.Errorf("failed to decode base58 string")
}
note := &Note{}
err := note.Deserialize(decoded)
if err != nil {
return nil, fmt.Errorf("failed to deserialize note: %w", err)
}
return note, nil
}
// Serialize converts Data to a byte slice
func (n *Data) Serialize() []byte {
buf := make([]byte, 12)
binary.BigEndian.PutUint64(buf[:8], n.ID)
binary.BigEndian.PutUint32(buf[8:], n.Value)
return buf
}
// Deserialize converts a byte slice to Data
func (n *Data) Deserialize(data []byte) error {
if len(data) != 12 {
return fmt.Errorf("invalid data length: expected 12 bytes, got %d", len(data))
}
n.ID = binary.BigEndian.Uint64(data[:8])
n.Value = binary.BigEndian.Uint32(data[8:])
return nil
}
// Hash returns the SHA256 hash of the serialized Data
func (n *Data) Hash() []byte {
hash := sha256.Sum256(n.Serialize())
return hash[:]
}
// Serialize converts the Note to a byte slice
func (n *Note) Serialize() []byte {
detailsBytes := n.Data.Serialize()
return append(detailsBytes, n.Signature...)
}
// Deserialize converts a byte slice to a Note
func (n *Note) Deserialize(data []byte) error {
if len(data) < 12 {
return fmt.Errorf("invalid data length: expected at least 12 bytes, got %d", len(data))
}
dataCopy := &Data{}
if err := dataCopy.Deserialize(data[:12]); err != nil {
return err
}
n.Data = *dataCopy
if len(data) > 12 {
n.Signature = data[12:]
}
return nil
}
// String converts the Note to a base58 encoded string with HRP
func (n Note) String() string {
return noteHRP + base58.Encode(n.Serialize())
}
// ToNote creates a Note from Data with the given signature
func (n *Data) ToNote(signature []byte) *Note {
return &Note{
Data: *n,
Signature: signature,
}
}