Compare commits
	
		
			No commits in common. "7c697394b5e7d37863b0d116aa026286f69f05e0" and "6fc27c7a81cf7f6d27f61c50fb2dd72e9c8746b1" have entirely different histories.
		
	
	
		
			7c697394b5
			...
			6fc27c7a81
		
	
		
							
								
								
									
										531
									
								
								dev/api.go
									
									
									
									
									
								
							
							
						
						
									
										531
									
								
								dev/api.go
									
									
									
									
									
								
							| @ -1,531 +0,0 @@ | ||||
| package dev | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gofrs/uuid" | ||||
| 	"git.defalsify.org/vise.git/logging" | ||||
| 	"git.defalsify.org/vise.git/db" | ||||
| 	fsdb "git.defalsify.org/vise.git/db/fs" | ||||
| 	"git.grassecon.net/grassrootseconomics/sarafu-api/models" | ||||
| 	"git.grassecon.net/grassrootseconomics/sarafu-api/event" | ||||
| 	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	logg = logging.NewVanilla().WithDomain("sarafu-api.devapi") | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	pubKeyLen int = 20 | ||||
| 	hashLen int = 32 | ||||
| 	defaultDecimals = 6 | ||||
| 	zeroAddress string = "0x0000000000000000000000000000000000000000" | ||||
| ) | ||||
| 
 | ||||
| type Tx struct { | ||||
| 	Track string `json: "track"` | ||||
| 	Hsh string `json:"hash"` | ||||
| 	To string `json:"to"` | ||||
| 	From string `json: "from"` | ||||
| 	Voucher string `json: "voucher"` | ||||
| 	Value int `json: "value"` | ||||
| 	When time.Time `json: "when"` | ||||
| } | ||||
| 
 | ||||
| func (t *Tx) ToTransferEvent() event.EventTokenTransfer { | ||||
| 	return event.EventTokenTransfer{ | ||||
| 		To: t.To, | ||||
| 		Value: t.Value, | ||||
| 		VoucherAddress: t.Voucher, | ||||
| 		TxHash: t.Hsh, | ||||
| 		From: t.From, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (t *Tx) ToMintEvent() event.EventTokenMint { | ||||
| 	return event.EventTokenMint{ | ||||
| 		To: t.To, | ||||
| 		Value: t.Value, | ||||
| 		VoucherAddress: t.Voucher, | ||||
| 		TxHash: t.Hsh, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type Account struct { | ||||
| 	Track string `json: "track"` | ||||
| 	Address string `json: "address"` | ||||
| 	Nonce int `json: "nonce"` | ||||
| 	DefaultVoucher string `json: "defaultVoucher"` | ||||
| 	Balances map[string]int `json: "balances"`  | ||||
| 	Alias string | ||||
| 	Txs []string `json: "txs"` | ||||
| } | ||||
| 
 | ||||
| func (a *Account) ToRegistrationEvent() event.EventCustodialRegistration { | ||||
| 	return event.EventCustodialRegistration{ | ||||
| 		Account: a.Address, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type Voucher struct { | ||||
| 	Name string `json: "name"` | ||||
| 	Address string `json: "address"` | ||||
| 	Symbol string `json: "symbol"` | ||||
| 	Decimals int `json: "decimals"` | ||||
| 	Sink string `json: "sink"` | ||||
| 	Commodity string `json: "commodity"` | ||||
| 	Location string `json: "location"` | ||||
| } | ||||
| 
 | ||||
| type DevAccountService struct { | ||||
| 	dir string | ||||
| 	db db.Db | ||||
| 	accounts map[string]Account | ||||
| 	accountsTrack map[string]string | ||||
| 	accountsAlias map[string]string | ||||
| 	vouchers map[string]Voucher | ||||
| 	vouchersAddress map[string]string | ||||
| 	txs map[string]Tx | ||||
| 	txsTrack map[string]string | ||||
| 	toAutoCreate bool | ||||
| 	autoVouchers []string | ||||
| 	autoVoucherValue map[string]int | ||||
| 	defaultAccount string | ||||
| 	emitterFunc event.EmitterFunc | ||||
| //	accountsSession map[string]string
 | ||||
| } | ||||
| 
 | ||||
| func NewDevAccountService(ctx context.Context, d string) *DevAccountService { | ||||
| 	svc := &DevAccountService{ | ||||
| 		dir: d, | ||||
| 		db: fsdb.NewFsDb(), | ||||
| 		accounts: make(map[string]Account), | ||||
| 		accountsTrack: make(map[string]string), | ||||
| 		accountsAlias: make(map[string]string), | ||||
| 		vouchers: make(map[string]Voucher), | ||||
| 		vouchersAddress: make(map[string]string), | ||||
| 		txs: make(map[string]Tx), | ||||
| 		txsTrack: make(map[string]string), | ||||
| 		autoVoucherValue: make(map[string]int), | ||||
| 		defaultAccount: zeroAddress, | ||||
| 	} | ||||
| 	acc := Account{ | ||||
| 		Address: zeroAddress, | ||||
| 	} | ||||
| 	svc.accounts[acc.Address] = acc | ||||
| 	err := svc.db.Connect(ctx, d) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	svc.db.SetPrefix(db.DATATYPE_USERDATA) | ||||
| 	err = svc.loadAll(ctx) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return svc | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) WithEmitter(fn event.EmitterFunc) *DevAccountService { | ||||
| 	das.emitterFunc = fn | ||||
| 	return das | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) loadAccount(ctx context.Context, pubKey string, v []byte) error { | ||||
| 	var acc Account | ||||
| 
 | ||||
| 	err := json.Unmarshal(v, &acc) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("malformed account: %v", pubKey) | ||||
| 	} | ||||
| 	das.accounts[pubKey] = acc | ||||
| 	das.accountsTrack[acc.Track] = pubKey | ||||
| 	if acc.Alias != "" { | ||||
| 		das.accountsAlias[acc.Alias] = pubKey | ||||
| 	} | ||||
| 	logg.TraceCtxf(ctx, "add account", "address", acc.Address) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) loadTx(ctx context.Context, hsh string, v []byte) error { | ||||
| 	var mytx Tx | ||||
| 
 | ||||
| 	err := json.Unmarshal(v, &mytx) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("malformed tx: %v", hsh) | ||||
| 	} | ||||
| 	das.txs[hsh] = mytx | ||||
| 	das.txsTrack[mytx.Track] = hsh | ||||
| 	logg.TraceCtxf(ctx, "add tx", "hash", hsh) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) loadItem(ctx context.Context, k []byte, v []byte) error { | ||||
| 	var err error | ||||
| 	s := string(k) | ||||
| 	ss := strings.SplitN(s, "_", 2) | ||||
| 	if len(ss) != 2 { | ||||
| 		return fmt.Errorf("malformed key: %s", s) | ||||
| 	} | ||||
| 	if ss[0] == "account" { | ||||
| 		err = das.loadAccount(ctx, ss[1], v) | ||||
| 	} else if ss[0] == "tx" { | ||||
| 		err = das.loadTx(ctx, ss[1], v) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // TODO: Add connect tx and account
 | ||||
| // TODO: update balance
 | ||||
| func (das *DevAccountService) loadAll(ctx context.Context) error { | ||||
| 	d, err := os.ReadDir(das.dir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, v := range(d) { | ||||
| 		// TODO: move decoding to vise
 | ||||
| 		fp := v.Name() | ||||
| 		k := []byte(fp[1:]) | ||||
| 		v, err := das.db.Get(ctx, k) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		err = das.loadItem(ctx, k, v) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return das.indexAll(ctx) | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) indexAll(ctx context.Context) error { | ||||
| 	for k, v := range(das.txs) { | ||||
| 		acc := das.accounts[v.From] | ||||
| 		acc.Txs = append(acc.Txs, k) | ||||
| 		logg.TraceCtxf(ctx, "add tx to sender index", "from", v.From, "tx", k) | ||||
| 		if v.From == v.To { | ||||
| 			continue | ||||
| 		} | ||||
| 		acc = das.accounts[v.To] | ||||
| 		acc.Txs = append(acc.Txs, k) | ||||
| 		logg.TraceCtxf(ctx, "add tx to recipient index", "from", v.To, "tx", k) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) WithAutoVoucher(ctx context.Context, symbol string, value int) *DevAccountService { | ||||
| 	err := das.AddVoucher(ctx, symbol) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "cannot add autovoucher %s: %v", symbol, err) | ||||
| 		return das | ||||
| 	} | ||||
| 	das.autoVouchers = append(das.autoVouchers, symbol) | ||||
| 	das.autoVoucherValue[symbol] = value | ||||
| 	return das | ||||
| } | ||||
| 
 | ||||
| // TODO: add persistence for vouchers
 | ||||
| // TODO: set max balance for 0x00 address
 | ||||
| func (das *DevAccountService) AddVoucher(ctx context.Context, symbol string) error { | ||||
| 	if symbol == "" { | ||||
| 		return fmt.Errorf("cannot add empty sym voucher") | ||||
| 	} | ||||
| 	v, ok := das.vouchers[symbol] | ||||
| 	if ok { | ||||
| 		return fmt.Errorf("already have voucher with symbol %s", v.Symbol) | ||||
| 	} | ||||
| 	h := sha1.New() | ||||
| 	h.Write([]byte(symbol)) | ||||
| 	z := h.Sum(nil) | ||||
| 	address := fmt.Sprintf("0x%x", z) | ||||
| 	das.vouchers[symbol] = Voucher{ | ||||
| 		Name: symbol, | ||||
| 		Symbol: symbol, | ||||
| 		Address: address, | ||||
| 	} | ||||
| 	das.vouchersAddress[address] = symbol | ||||
| 	logg.InfoCtxf(ctx, "added dev voucher", "symbol", symbol, "address", address) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // AccountService implementation below
 | ||||
| 
 | ||||
| func (das *DevAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { | ||||
| 	acc, ok := das.accounts[publicKey] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("account not found (publickey): %v", publicKey) | ||||
| 	} | ||||
| 	if acc.DefaultVoucher == "" { | ||||
| 		return nil, fmt.Errorf("no default voucher set for: %v", publicKey) | ||||
| 	} | ||||
| 	bal, ok := acc.Balances[acc.DefaultVoucher] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("balance not found for default token %s pubkey %v", acc.DefaultVoucher, publicKey) | ||||
| 	} | ||||
| 	return &models.BalanceResult { | ||||
| 		Balance: strconv.Itoa(bal), | ||||
| 		Nonce: json.Number(strconv.Itoa(acc.Nonce)), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) balanceAuto(ctx context.Context, pubKey string) error { | ||||
| 	for _, v := range(das.autoVouchers) { | ||||
| 		voucher, ok := das.vouchers[v] | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("balance auto voucher set but not resolved: %s", v) | ||||
| 		} | ||||
| 		value, ok := das.autoVoucherValue[v] | ||||
| 		if !ok { | ||||
| 			value = 0 | ||||
| 		} | ||||
| 		_, err := das.TokenTransfer(ctx, strconv.Itoa(value), das.defaultAccount, pubKey, voucher.Address) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) saveAccount(ctx context.Context, acc Account) error { | ||||
| 	k := "account_" + acc.Address | ||||
| 	v, err := json.Marshal(acc) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return das.db.Put(ctx, []byte(k), v) | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { | ||||
| 	var b [pubKeyLen]byte | ||||
| 	uid, err := uuid.NewV4() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c, err := rand.Read(b[:]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if c != pubKeyLen { | ||||
| 		return nil, fmt.Errorf("short read: %d", c) | ||||
| 	} | ||||
| 	pubKey := fmt.Sprintf("0x%x", b) | ||||
| 	acc := Account{ | ||||
| 		Track: uid.String(), | ||||
| 		Address: pubKey, | ||||
| 	} | ||||
| 
 | ||||
| 	err = das.saveAccount(ctx, acc) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	das.accounts[pubKey] = acc | ||||
| 	das.accountsTrack[uid.String()] = pubKey | ||||
| 	err = das.balanceAuto(ctx, pubKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if das.defaultAccount == zeroAddress { | ||||
| 		das.defaultAccount = pubKey | ||||
| 	} | ||||
| 
 | ||||
| 	if das.emitterFunc != nil { | ||||
| 		msg := event.Msg{ | ||||
| 			Typ: event.EventRegistrationTag, | ||||
| 			Item: acc, | ||||
| 		} | ||||
| 		err = das.emitterFunc(ctx, msg) | ||||
| 		if err != nil { | ||||
| 			logg.ErrorCtxf(ctx, "emitter returned error", "err", err, "msg", msg) | ||||
| 		} | ||||
| 	} | ||||
| 	logg.TraceCtxf(ctx, "account created", "account", acc) | ||||
| 
 | ||||
| 	return &models.AccountResult{ | ||||
| 		PublicKey: pubKey, | ||||
| 		TrackingId: uid.String(), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { | ||||
| 	var ok bool | ||||
| 	_, ok = das.accounts[publicKey] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("account not found (publickey): %v", publicKey) | ||||
| 	} | ||||
| 	return &models.TrackStatusResult{ | ||||
| 		Active: true, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { | ||||
| 	var holdings []dataserviceapi.TokenHoldings | ||||
| 	acc, ok := das.accounts[publicKey] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("account not found (publickey): %v", publicKey) | ||||
| 	} | ||||
| 	for k, v := range(acc.Balances) { | ||||
| 		voucher, ok := das.vouchers[k] | ||||
| 		if !ok { | ||||
| 			return nil, fmt.Errorf("voucher has balance but object not found: %v", k) | ||||
| 		} | ||||
| 		holdings = append(holdings, dataserviceapi.TokenHoldings{ | ||||
| 			ContractAddress: voucher.Address, | ||||
| 			TokenSymbol: voucher.Symbol, | ||||
| 			TokenDecimals: strconv.Itoa(voucher.Decimals), | ||||
| 			Balance: strconv.Itoa(v), | ||||
| 		}) | ||||
| 	} | ||||
| 	return holdings, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { | ||||
| 	var lasttx []dataserviceapi.Last10TxResponse | ||||
| 	acc, ok := das.accounts[publicKey] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("account not found (publickey): %v", publicKey) | ||||
| 	} | ||||
| 	for i, v := range(acc.Txs) { | ||||
| 		mytx := das.txs[v] | ||||
| 		if i == 10 { | ||||
| 			break	 | ||||
| 		} | ||||
| 		voucher, ok := das.vouchers[mytx.Voucher] | ||||
| 		if !ok { | ||||
| 			return nil, fmt.Errorf("voucher %s in tx list but not found in voucher list", mytx.Voucher) | ||||
| 		} | ||||
| 		lasttx = append(lasttx, dataserviceapi.Last10TxResponse{ | ||||
| 			Sender: mytx.From, | ||||
| 			Recipient: mytx.To, | ||||
| 			TransferValue: strconv.Itoa(mytx.Value), | ||||
| 			ContractAddress: voucher.Address, | ||||
| 			TxHash: mytx.Hsh, | ||||
| 			DateBlock: mytx.When, | ||||
| 			TokenSymbol: voucher.Symbol, | ||||
| 			TokenDecimals: strconv.Itoa(voucher.Decimals), | ||||
| 		}) | ||||
| 	} | ||||
| 	return lasttx, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { | ||||
| 	sym, ok := das.vouchersAddress[address] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("voucher address %v not found", address) | ||||
| 	} | ||||
| 	voucher, ok := das.vouchers[sym] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("voucher address %v found but does not resolve", address) | ||||
| 	} | ||||
| 	return &models.VoucherDataResult{ | ||||
| 		TokenName: voucher.Name, | ||||
| 		TokenSymbol: voucher.Symbol, | ||||
| 		TokenDecimals: voucher.Decimals, | ||||
| 		SinkAddress: voucher.Sink, | ||||
| 		TokenCommodity: voucher.Commodity, | ||||
| 		TokenLocation: voucher.Location, | ||||
| 
 | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) saveTokenTransfer(ctx context.Context, mytx Tx) error { | ||||
| 	k := "tx_" + mytx.Hsh | ||||
| 	v, err := json.Marshal(mytx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return das.db.Put(ctx, []byte(k), v) | ||||
| } | ||||
| 
 | ||||
| // TODO: set default voucher on first received
 | ||||
| // TODO: update balance
 | ||||
| func (das *DevAccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { | ||||
| 	var b [hashLen]byte | ||||
| 	value, err := strconv.Atoi(amount) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	accFrom, ok := das.accounts[from] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("sender account %v not found", from)	 | ||||
| 	} | ||||
| 	accTo, ok := das.accounts[to] | ||||
| 	if !ok { | ||||
| 		if !das.toAutoCreate { | ||||
| 			return nil, fmt.Errorf("recipient account %v not found, and not creating", from)	 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sym, ok := das.vouchersAddress[tokenAddress] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("voucher address %v not found", tokenAddress) | ||||
| 	} | ||||
| 	voucher, ok := das.vouchers[sym] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("voucher address %v found but does not resolve", tokenAddress) | ||||
| 	} | ||||
| 
 | ||||
| 	uid, err := uuid.NewV4() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	c, err := rand.Read(b[:]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if c != hashLen { | ||||
| 		return nil, fmt.Errorf("tx hash short read: %d", c) | ||||
| 	} | ||||
| 	hsh := fmt.Sprintf("0x%x", b) | ||||
| 	mytx := Tx{ | ||||
| 		Hsh: hsh, | ||||
| 		To: accTo.Address, | ||||
| 		From: accFrom.Address, | ||||
| 		Voucher: voucher.Symbol, | ||||
| 		Value: value, | ||||
| 		Track: uid.String(), | ||||
| 		When: time.Now(), | ||||
| 	} | ||||
| 	err = das.saveTokenTransfer(ctx, mytx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	das.txs[hsh] = mytx | ||||
| 	if das.emitterFunc != nil { | ||||
| 		msg := event.Msg{ | ||||
| 			Typ: event.EventTokenTransferTag, | ||||
| 			Item: mytx, | ||||
| 		} | ||||
| 		err = das.emitterFunc(ctx, msg) | ||||
| 		if err != nil { | ||||
| 			logg.ErrorCtxf(ctx, "emitter returned error", "err", err, "msg", msg) | ||||
| 		} | ||||
| 	} | ||||
| 	logg.TraceCtxf(ctx, "token transfer created", "tx", mytx) | ||||
| 	return &models.TokenTransferResponse{ | ||||
| 		TrackingId: uid.String(), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (das *DevAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { | ||||
| 	addr, ok := das.accountsAlias[alias] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("alias %s not found", alias) | ||||
| 	} | ||||
| 	acc, ok := das.accounts[addr] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("alias %s found but does not resolve", alias) | ||||
| 	} | ||||
| 	return &dataserviceapi.AliasAddress{ | ||||
| 		Address: acc.Address, | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										66
									
								
								event/msg.go
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								event/msg.go
									
									
									
									
									
								
							| @ -1,66 +0,0 @@ | ||||
| package event | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// TODO: integrate with sarafu-vise-events
 | ||||
| 	EventTokenTransferTag = "TOKEN_TRANSFER" | ||||
| 	EventTokenMintTag = "TOKEN_MINT" | ||||
| 	EventRegistrationTag = "CUSTODIAL_REGISTRATION" | ||||
| ) | ||||
| 
 | ||||
| type Msg struct { | ||||
| 	Typ string | ||||
| 	Item any | ||||
| } | ||||
| 
 | ||||
| type EmitterFunc func(context.Context, Msg) error | ||||
| 
 | ||||
| // fields used for handling custodial registration event.
 | ||||
| type EventCustodialRegistration struct { | ||||
| 	Account string | ||||
| } | ||||
| 
 | ||||
| // fields used for handling token transfer event.
 | ||||
| type EventTokenTransfer struct { | ||||
| 	To string | ||||
| 	Value int | ||||
| 	VoucherAddress string | ||||
| 	TxHash string | ||||
| 	From string | ||||
| } | ||||
| 
 | ||||
| type EventTokenMint struct { | ||||
| 	To string | ||||
| 	Value int | ||||
| 	TxHash string | ||||
| 	VoucherAddress string | ||||
| } | ||||
| 
 | ||||
| type EventsHandlerFunc func(context.Context, any) error | ||||
| 
 | ||||
| type EventsHandler struct { | ||||
| 	handlers map[string]EventsHandlerFunc | ||||
| } | ||||
| 
 | ||||
| func NewEventsHandler() *EventsHandler { | ||||
| 	return &EventsHandler{ | ||||
| 		handlers: make(map[string]EventsHandlerFunc), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (eh *EventsHandler) WithHandler(tag string, fn EventsHandlerFunc) *EventsHandler { | ||||
| 	eh.handlers[tag] = fn | ||||
| 	return eh | ||||
| } | ||||
| 
 | ||||
| func (eh *EventsHandler) Handle(ctx context.Context, tag string, o any) error { | ||||
| 	fn, ok := eh.handlers[tag] | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("Handler not registered for tag: %s", tag) | ||||
| 	} | ||||
| 	return fn(ctx, o) | ||||
| } | ||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @ -3,16 +3,13 @@ module git.grassecon.net/grassrootseconomics/sarafu-api | ||||
| go 1.23.4 | ||||
| 
 | ||||
| require ( | ||||
| 	git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d | ||||
| 	git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250113213325-5228aef0889b | ||||
| 	github.com/gofrs/uuid v4.4.0+incompatible | ||||
| 	git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250112121325-9e4c65c8b4d1 | ||||
| 	github.com/grassrootseconomics/eth-custodial v1.3.0-beta | ||||
| 	github.com/grassrootseconomics/ussd-data-service v1.2.0-beta | ||||
| 	github.com/stretchr/testify v1.9.0 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect | ||||
| 	github.com/joho/godotenv v1.5.1 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | ||||
|  | ||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,13 +1,7 @@ | ||||
| git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSGhfOdcj7kc555f8dc9DmMd2YAyC2AMw= | ||||
| git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= | ||||
| git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250113213325-5228aef0889b h1:6SieNUSEKbkjzquuwazs/lVG56zdEWF10zQQEMRJfMs= | ||||
| git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250113213325-5228aef0889b/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U= | ||||
| github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= | ||||
| github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= | ||||
| git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250112121325-9e4c65c8b4d1 h1:RfU5/WFfPxDptlkyx4MT+4YmO79sY6HvIngUq5uwQPU= | ||||
| git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250112121325-9e4c65c8b4d1/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U= | ||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= | ||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= | ||||
| github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= | ||||
| github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= | ||||
| github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= | ||||
| github.com/grassrootseconomics/ussd-data-service v1.2.0-beta h1:fn1gwbWIwHVEBtUC2zi5OqTlfI/5gU1SMk0fgGixIXk= | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user