mirror of
https://github.com/grassrootseconomics/cic-custodial.git
synced 2024-11-21 13:56:47 +01:00
xnapshot: 12-02
This commit is contained in:
parent
773474cad9
commit
4f7909e4ee
@ -22,6 +22,10 @@ func initAbis() map[string]*w3.Func {
|
|||||||
"transfer": w3.MustNewFunc("transfer(address,uint256)", "bool"),
|
"transfer": w3.MustNewFunc("transfer(address,uint256)", "bool"),
|
||||||
// Keccak hash -> 0x23b872dd
|
// Keccak hash -> 0x23b872dd
|
||||||
"transferFrom": w3.MustNewFunc("transferFrom(address, address, uint256)", "bool"),
|
"transferFrom": w3.MustNewFunc("transferFrom(address, address, uint256)", "bool"),
|
||||||
|
// Add to account index
|
||||||
|
"add": w3.MustNewFunc("add(address)", "bool"),
|
||||||
|
// giveTo gas refill
|
||||||
|
"giveTo": w3.MustNewFunc("giveTo(address)", "uint256"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +35,8 @@ func initSystemContainer(ctx context.Context, noncestore nonce.Noncestore) (*tas
|
|||||||
// Some custodial system defaults loaded from the config file.
|
// Some custodial system defaults loaded from the config file.
|
||||||
systemContainer := &tasker.SystemContainer{
|
systemContainer := &tasker.SystemContainer{
|
||||||
Abis: initAbis(),
|
Abis: initAbis(),
|
||||||
|
AccountIndexContract: w3.A(ko.MustString("system.account_index")),
|
||||||
|
GasFaucetContract: w3.A(ko.MustString("system.gas_faucet")),
|
||||||
GasRefillThreshold: big.NewInt(ko.MustInt64("system.gas_refill_threshold")),
|
GasRefillThreshold: big.NewInt(ko.MustInt64("system.gas_refill_threshold")),
|
||||||
GasRefillValue: big.NewInt(ko.MustInt64("system.gas_refill_value")),
|
GasRefillValue: big.NewInt(ko.MustInt64("system.gas_refill_value")),
|
||||||
GiftableGasValue: big.NewInt(ko.MustInt64("system.giftable_gas_value")),
|
GiftableGasValue: big.NewInt(ko.MustInt64("system.giftable_gas_value")),
|
||||||
|
@ -66,7 +66,8 @@ func initCeloProvider() (*celo.Provider, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ko.Bool("chain.testnet") {
|
if ko.Bool("chain.testnet") {
|
||||||
providerOpts.ChainId = celo.TestnetChainId
|
// Devnet = 1337
|
||||||
|
providerOpts.ChainId = 1337
|
||||||
} else {
|
} else {
|
||||||
providerOpts.ChainId = celo.MainnetChainId
|
providerOpts.ChainId = celo.MainnetChainId
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ func initTasker(custodialContainer *custodial, redisPool *redis.RedisPool) *task
|
|||||||
taskerServerOpts := tasker.TaskerServerOpts{
|
taskerServerOpts := tasker.TaskerServerOpts{
|
||||||
Concurrency: ko.MustInt("asynq.worker_count"),
|
Concurrency: ko.MustInt("asynq.worker_count"),
|
||||||
Logg: lo,
|
Logg: lo,
|
||||||
|
LogLevel: asynq.ErrorLevel,
|
||||||
RedisPool: redisPool,
|
RedisPool: redisPool,
|
||||||
SystemContainer: custodialContainer.systemContainer,
|
SystemContainer: custodialContainer.systemContainer,
|
||||||
TaskerClient: custodialContainer.taskerClient,
|
TaskerClient: custodialContainer.taskerClient,
|
||||||
@ -34,6 +35,15 @@ func initTasker(custodialContainer *custodial, redisPool *redis.RedisPool) *task
|
|||||||
custodialContainer.taskerClient,
|
custodialContainer.taskerClient,
|
||||||
js,
|
js,
|
||||||
))
|
))
|
||||||
|
taskerServer.RegisterHandlers(tasker.RegisterAccountOnChain, task.RegisterAccountOnChainProcessor(
|
||||||
|
custodialContainer.celoProvider,
|
||||||
|
custodialContainer.lockProvider,
|
||||||
|
custodialContainer.noncestore,
|
||||||
|
custodialContainer.pgStore,
|
||||||
|
custodialContainer.systemContainer,
|
||||||
|
custodialContainer.taskerClient,
|
||||||
|
js,
|
||||||
|
))
|
||||||
taskerServer.RegisterHandlers(tasker.GiftGasTask, task.GiftGasProcessor(
|
taskerServer.RegisterHandlers(tasker.GiftGasTask, task.GiftGasProcessor(
|
||||||
custodialContainer.celoProvider,
|
custodialContainer.celoProvider,
|
||||||
custodialContainer.lockProvider,
|
custodialContainer.lockProvider,
|
||||||
|
43
config.toml
43
config.toml
@ -1,5 +1,5 @@
|
|||||||
[service]
|
[service]
|
||||||
address = ":5000"
|
address = ":5005"
|
||||||
# Exposes Prometheus metrics
|
# Exposes Prometheus metrics
|
||||||
# /metrics endpoint
|
# /metrics endpoint
|
||||||
metrics = true
|
metrics = true
|
||||||
@ -7,26 +7,26 @@ metrics = true
|
|||||||
# System default values
|
# System default values
|
||||||
# Valus are in wei unless otherwise stated
|
# Valus are in wei unless otherwise stated
|
||||||
[system]
|
[system]
|
||||||
# Any account below 1 KES equivalent of CELO is topped up again
|
|
||||||
# 10000000000000000 = 1 KES
|
|
||||||
gas_refill_threshold = 10000000000000000
|
|
||||||
gas_refill_value = 10000000000000000
|
|
||||||
# Every custodial account is given 2 KES worth of CELO
|
|
||||||
giftable_gas_value = 20000000000000000
|
|
||||||
# The giftable token is a training voucher
|
# The giftable token is a training voucher
|
||||||
# Every new user is given 5 DGFT
|
# Every new user is given 5 DGFT
|
||||||
giftable_token_address = "0x486aD10d70107900546455F7a0e022c300F157Bf"
|
gas_faucet = "0x6dE38F79Cf455339e8141D15E208ba09eea634e1"
|
||||||
|
giftable_token_address = "0x4091fc149522d5FE31d0970687078B1aE0625892"
|
||||||
giftable_token_value = 5000000
|
giftable_token_value = 5000000
|
||||||
|
gas_refill_threshold = 100000000000000000
|
||||||
|
gas_refill_value = 100000000000000000
|
||||||
|
# Every custodial account is given 2 KES worth of CELO
|
||||||
|
giftable_gas_value = 2000000000000000000
|
||||||
# System private key
|
# System private key
|
||||||
# Should always be toped up
|
# Should always be toped up
|
||||||
private_key = "a6af6c597c614e3c8ee4b7638ab7c3f737aece3773a5413ca8caf4338e6b06d1"
|
private_key = "d87f322629cf071ccd3ddf17ab5e1abf098a25c4c5d791d7535d265379b2ae37"
|
||||||
lock_prefix = "lock:"
|
lock_prefix = "lock:"
|
||||||
public_key = "0x80097c773B3E83472FC7952c5206a7DB35d42bEF"
|
public_key = "0xe5ab7A5af1f28aA8E9658AC33a6ebF2a8641d948"
|
||||||
token_decimals = 6
|
token_decimals = 6
|
||||||
token_transfer_gas_limit = 100000
|
token_transfer_gas_limit = 200000
|
||||||
|
account_index = "0x70138F458Fa56C034acb19E38d082843327F18A4"
|
||||||
|
|
||||||
[chain]
|
[chain]
|
||||||
rpc_endpoint = "https://alfajores-forno.celo-testnet.org"
|
rpc_endpoint = "http://192.168.0.101:8545"
|
||||||
testnet = true
|
testnet = true
|
||||||
|
|
||||||
[postgres]
|
[postgres]
|
||||||
@ -43,3 +43,22 @@ worker_count = 15
|
|||||||
debug = false
|
debug = false
|
||||||
dsn = "redis://localhost:6379/0"
|
dsn = "redis://localhost:6379/0"
|
||||||
task_retention_hrs = 24
|
task_retention_hrs = 24
|
||||||
|
|
||||||
|
# https://docs.nats.io/
|
||||||
|
[jetstream]
|
||||||
|
endpoint = "nats://localhost:4222"
|
||||||
|
stream_name = "CUSTODIAL"
|
||||||
|
# Duration JetStream should keep the message before remocing it from the persistent store
|
||||||
|
persist_duration_hours = 48
|
||||||
|
# Duration to ignore duplicate transactions (e.g. due to restart)
|
||||||
|
dedup_duration_hours = 6
|
||||||
|
# Stream subjects
|
||||||
|
stream_subjects = [
|
||||||
|
"CUSTODIAL.accountNewNonce",
|
||||||
|
"CUSTODIAL.accountRegister",
|
||||||
|
"CUSTODIAL.giftNewAccountGas",
|
||||||
|
"CUSTODIAL.giftNewAccountVoucher",
|
||||||
|
"CUSTODIAL.dispatchFail",
|
||||||
|
"CUSTODIAL.dispatchSuccess",
|
||||||
|
"CUSTODIAL.transferSign"
|
||||||
|
]
|
@ -30,6 +30,15 @@ services:
|
|||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
nats:
|
||||||
|
image: nats:2.9
|
||||||
|
restart: unless-stopped
|
||||||
|
command: "-js -sd /nats/data"
|
||||||
|
volumes:
|
||||||
|
- cic-custodial-nats:/nats/data
|
||||||
|
ports:
|
||||||
|
- "4222:4222"
|
||||||
|
- "8222:8222"
|
||||||
asynqmon:
|
asynqmon:
|
||||||
image: hibiken/asynqmon
|
image: hibiken/asynqmon
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@ -45,3 +54,5 @@ volumes:
|
|||||||
driver: local
|
driver: local
|
||||||
cic-custodial-redis:
|
cic-custodial-redis:
|
||||||
driver: local
|
driver: local
|
||||||
|
cic-custodial-nats:
|
||||||
|
driver: local
|
||||||
|
@ -24,7 +24,7 @@ func SignTransferHandler(
|
|||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var transferRequest struct {
|
var transferRequest struct {
|
||||||
TrackingId string `json:"trackingId" validate:"required"`
|
TrackingId string `json:"trackingId" validate:"required"`
|
||||||
From string `json:"from" validate:"required,eth_address"`
|
From string `json:"from" validate:"required,eth_addr"`
|
||||||
To string `json:"to" validate:"required,eth_addr"`
|
To string `json:"to" validate:"required,eth_addr"`
|
||||||
VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr"`
|
VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr"`
|
||||||
Amount int64 `json:"amount" validate:"required,numeric"`
|
Amount int64 `json:"amount" validate:"required,numeric"`
|
||||||
|
@ -16,7 +16,6 @@ func (s *PostgresStore) CreateDispatchStatus(ctx context.Context, dispatch Dispa
|
|||||||
s.queries.CreateDispatchStatus,
|
s.queries.CreateDispatchStatus,
|
||||||
dispatch.OtxId,
|
dispatch.OtxId,
|
||||||
dispatch.Status,
|
dispatch.Status,
|
||||||
dispatch.TrackingId,
|
|
||||||
).Scan(&id); err != nil {
|
).Scan(&id); err != nil {
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,14 @@ func (s *PostgresStore) CreateOTX(ctx context.Context, otx OTX) (uint, error) {
|
|||||||
if err := s.db.QueryRow(
|
if err := s.db.QueryRow(
|
||||||
ctx,
|
ctx,
|
||||||
s.queries.CreateOTX,
|
s.queries.CreateOTX,
|
||||||
|
otx.TrackingId,
|
||||||
|
otx.Type,
|
||||||
otx.RawTx,
|
otx.RawTx,
|
||||||
otx.TxHash,
|
otx.TxHash,
|
||||||
otx.From,
|
otx.From,
|
||||||
otx.Data,
|
otx.Data,
|
||||||
otx.GasPrice,
|
otx.GasPrice,
|
||||||
otx.Nonce,
|
otx.Nonce,
|
||||||
otx.TrackingId,
|
|
||||||
).Scan(&id); err != nil {
|
).Scan(&id); err != nil {
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,19 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
OTX struct {
|
OTX struct {
|
||||||
|
TrackingId string
|
||||||
|
Type string
|
||||||
RawTx string
|
RawTx string
|
||||||
TxHash string
|
TxHash string
|
||||||
From string
|
From string
|
||||||
Data string
|
Data string
|
||||||
GasPrice uint64
|
GasPrice uint64
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
TrackingId string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchStatus struct {
|
DispatchStatus struct {
|
||||||
OtxId uint
|
OtxId uint
|
||||||
Status status.Status
|
Status status.Status
|
||||||
TrackingId string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Store interface {
|
Store interface {
|
||||||
|
@ -2,12 +2,12 @@ package task
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/bsm/redislock"
|
||||||
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
celo "github.com/grassrootseconomics/cic-celo-sdk"
|
celo "github.com/grassrootseconomics/cic-celo-sdk"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
@ -30,9 +30,9 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func PrepareAccount(
|
func PrepareAccount(
|
||||||
js nats.JetStreamContext,
|
|
||||||
noncestore nonce.Noncestore,
|
noncestore nonce.Noncestore,
|
||||||
taskerClient *tasker.TaskerClient,
|
taskerClient *tasker.TaskerClient,
|
||||||
|
js nats.JetStreamContext,
|
||||||
) func(context.Context, *asynq.Task) error {
|
) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
@ -48,7 +48,7 @@ func PrepareAccount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := taskerClient.CreateTask(
|
_, err := taskerClient.CreateTask(
|
||||||
tasker.GiftGasTask,
|
tasker.RegisterAccountOnChain,
|
||||||
tasker.DefaultPriority,
|
tasker.DefaultPriority,
|
||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
Payload: t.Payload(),
|
Payload: t.Payload(),
|
||||||
@ -87,14 +87,153 @@ func PrepareAccount(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GiftGasProcessor(
|
func RegisterAccountOnChainProcessor(
|
||||||
celoProvider *celo.Provider,
|
celoProvider *celo.Provider,
|
||||||
js nats.JetStreamContext,
|
|
||||||
lockProvider *redislock.Client,
|
lockProvider *redislock.Client,
|
||||||
noncestore nonce.Noncestore,
|
noncestore nonce.Noncestore,
|
||||||
pg store.Store,
|
pg store.Store,
|
||||||
system *tasker.SystemContainer,
|
system *tasker.SystemContainer,
|
||||||
taskerClient *tasker.TaskerClient,
|
taskerClient *tasker.TaskerClient,
|
||||||
|
js nats.JetStreamContext,
|
||||||
|
) func(context.Context, *asynq.Task) error {
|
||||||
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
|
var (
|
||||||
|
p AccountPayload
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := json.Unmarshal(t.Payload(), &p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lock, err := lockProvider.Obtain(ctx, system.LockPrefix+system.PublicKey, system.LockTimeout, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer lock.Release(ctx)
|
||||||
|
|
||||||
|
nonce, err := noncestore.Acquire(ctx, system.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
input, err := system.Abis["add"].EncodeArgs(w3.A(p.PublicKey))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Review gas params.
|
||||||
|
builtTx, err := celoProvider.SignContractExecutionTx(
|
||||||
|
system.PrivateKey,
|
||||||
|
celo.ContractExecutionTxOpts{
|
||||||
|
ContractAddress: system.AccountIndexContract,
|
||||||
|
InputData: input,
|
||||||
|
GasPrice: big.NewInt(20000000000),
|
||||||
|
GasLimit: system.TokenTransferGasLimit,
|
||||||
|
Nonce: nonce,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTx, err := builtTx.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := pg.CreateOTX(ctx, store.OTX{
|
||||||
|
TrackingId: p.TrackingId,
|
||||||
|
Type: "ACCOUNT_REGISTER",
|
||||||
|
RawTx: hexutil.Encode(rawTx),
|
||||||
|
TxHash: builtTx.Hash().Hex(),
|
||||||
|
From: system.PublicKey,
|
||||||
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
|
GasPrice: builtTx.GasPrice().Uint64(),
|
||||||
|
Nonce: builtTx.Nonce(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
|
OtxId: id,
|
||||||
|
Tx: builtTx,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = taskerClient.CreateTask(
|
||||||
|
tasker.TxDispatchTask,
|
||||||
|
tasker.HighPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: disptachJobPayload,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = taskerClient.CreateTask(
|
||||||
|
tasker.GiftGasTask,
|
||||||
|
tasker.DefaultPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: t.Payload(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
eventPayload := &accountEventPayload{
|
||||||
|
TrackingId: p.TrackingId,
|
||||||
|
}
|
||||||
|
|
||||||
|
eventJson, err := json.Marshal(eventPayload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = js.Publish("CUSTODIAL.accountRegister", eventJson)
|
||||||
|
if err != nil {
|
||||||
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GiftGasProcessor(
|
||||||
|
celoProvider *celo.Provider,
|
||||||
|
lockProvider *redislock.Client,
|
||||||
|
noncestore nonce.Noncestore,
|
||||||
|
pg store.Store,
|
||||||
|
system *tasker.SystemContainer,
|
||||||
|
taskerClient *tasker.TaskerClient,
|
||||||
|
js nats.JetStreamContext,
|
||||||
) func(context.Context, *asynq.Task) error {
|
) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
@ -144,12 +283,14 @@ func GiftGasProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id, err := pg.CreateOTX(ctx, store.OTX{
|
id, err := pg.CreateOTX(ctx, store.OTX{
|
||||||
RawTx: hex.EncodeToString(rawTx),
|
TrackingId: p.TrackingId,
|
||||||
TxHash: builtTx.Hash().Hex(),
|
Type: "GIFT_GAS",
|
||||||
From: system.PublicKey,
|
RawTx: hexutil.Encode(rawTx),
|
||||||
Data: string(builtTx.Data()),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
From: system.PublicKey,
|
||||||
Nonce: builtTx.Nonce(),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
|
GasPrice: builtTx.GasPrice().Uint64(),
|
||||||
|
Nonce: builtTx.Nonce(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
@ -160,9 +301,8 @@ func GiftGasProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
OtxId: id,
|
OtxId: id,
|
||||||
TrackingId: p.TrackingId,
|
Tx: builtTx,
|
||||||
Tx: builtTx,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
@ -211,12 +351,12 @@ func GiftGasProcessor(
|
|||||||
|
|
||||||
func GiftTokenProcessor(
|
func GiftTokenProcessor(
|
||||||
celoProvider *celo.Provider,
|
celoProvider *celo.Provider,
|
||||||
js nats.JetStreamContext,
|
|
||||||
lockProvider *redislock.Client,
|
lockProvider *redislock.Client,
|
||||||
noncestore nonce.Noncestore,
|
noncestore nonce.Noncestore,
|
||||||
pg store.Store,
|
pg store.Store,
|
||||||
system *tasker.SystemContainer,
|
system *tasker.SystemContainer,
|
||||||
taskerClient *tasker.TaskerClient,
|
taskerClient *tasker.TaskerClient,
|
||||||
|
js nats.JetStreamContext,
|
||||||
) func(context.Context, *asynq.Task) error {
|
) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
@ -271,12 +411,14 @@ func GiftTokenProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id, err := pg.CreateOTX(ctx, store.OTX{
|
id, err := pg.CreateOTX(ctx, store.OTX{
|
||||||
RawTx: hex.EncodeToString(rawTx),
|
TrackingId: p.TrackingId,
|
||||||
TxHash: builtTx.Hash().Hex(),
|
Type: "GIFT_VOUCHER",
|
||||||
From: system.PublicKey,
|
RawTx: hexutil.Encode(rawTx),
|
||||||
Data: string(builtTx.Data()),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
From: system.PublicKey,
|
||||||
Nonce: builtTx.Nonce(),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
|
GasPrice: builtTx.GasPrice().Uint64(),
|
||||||
|
Nonce: builtTx.Nonce(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
@ -287,9 +429,8 @@ func GiftTokenProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
OtxId: id,
|
OtxId: id,
|
||||||
TrackingId: p.TrackingId,
|
Tx: builtTx,
|
||||||
Tx: builtTx,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
if err := noncestore.Return(ctx, system.PublicKey); err != nil {
|
||||||
|
@ -16,14 +16,13 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
TxPayload struct {
|
TxPayload struct {
|
||||||
OtxId uint `json:"otxId"`
|
OtxId uint `json:"otxId"`
|
||||||
TrackingId string `json:"trackingId"`
|
Tx *types.Transaction `json:"tx"`
|
||||||
Tx *types.Transaction `json:"tx"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEventPayload struct {
|
dispatchEventPayload struct {
|
||||||
TrackingId string
|
OtxId uint
|
||||||
TxHash string
|
TxHash string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,12 +43,11 @@ func TxDispatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatchStatus := store.DispatchStatus{
|
dispatchStatus := store.DispatchStatus{
|
||||||
OtxId: p.OtxId,
|
OtxId: p.OtxId,
|
||||||
TrackingId: p.TrackingId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eventPayload := &dispatchEventPayload{
|
eventPayload := &dispatchEventPayload{
|
||||||
TrackingId: p.TrackingId,
|
OtxId: p.OtxId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := celoProvider.Client.CallCtx(
|
if err := celoProvider.Client.CallCtx(
|
||||||
@ -77,7 +75,12 @@ func TxDispatch(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchStatus.TrackingId = status.Successful
|
dispatchStatus.Status = status.Successful
|
||||||
|
_, err := pg.CreateDispatchStatus(ctx, dispatchStatus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
eventPayload.TxHash = txHash.Hex()
|
eventPayload.TxHash = txHash.Hex()
|
||||||
|
|
||||||
eventJson, err := json.Marshal(eventPayload)
|
eventJson, err := json.Marshal(eventPayload)
|
||||||
@ -85,7 +88,7 @@ func TxDispatch(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = js.Publish("CUSTODIAL.dispatchSuccessful", eventJson, nats.MsgId(txHash.Hex()))
|
_, err = js.Publish("CUSTODIAL.dispatchSuccess", eventJson, nats.MsgId(txHash.Hex()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ package task
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/bsm/redislock"
|
||||||
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
celo "github.com/grassrootseconomics/cic-celo-sdk"
|
celo "github.com/grassrootseconomics/cic-celo-sdk"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/keystore"
|
"github.com/grassrootseconomics/cic-custodial/internal/keystore"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
||||||
@ -108,12 +108,14 @@ func SignTransfer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id, err := pg.CreateOTX(ctx, store.OTX{
|
id, err := pg.CreateOTX(ctx, store.OTX{
|
||||||
RawTx: hex.EncodeToString(rawTx),
|
TrackingId: p.TrackingId,
|
||||||
TxHash: builtTx.Hash().Hex(),
|
Type: "TRANSFER",
|
||||||
From: p.From,
|
RawTx: hexutil.Encode(rawTx),
|
||||||
Data: string(builtTx.Data()),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
From: p.From,
|
||||||
Nonce: builtTx.Nonce(),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
|
GasPrice: builtTx.GasPrice().Uint64(),
|
||||||
|
Nonce: builtTx.Nonce(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, p.From); err != nil {
|
if err := noncestore.Return(ctx, p.From); err != nil {
|
||||||
@ -124,9 +126,8 @@ func SignTransfer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
OtxId: id,
|
OtxId: id,
|
||||||
TrackingId: p.TrackingId,
|
Tx: builtTx,
|
||||||
Tx: builtTx,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := noncestore.Return(ctx, p.From); err != nil {
|
if err := noncestore.Return(ctx, p.From); err != nil {
|
||||||
|
@ -17,6 +17,8 @@ type (
|
|||||||
|
|
||||||
type SystemContainer struct {
|
type SystemContainer struct {
|
||||||
Abis map[string]*w3.Func
|
Abis map[string]*w3.Func
|
||||||
|
AccountIndexContract common.Address
|
||||||
|
GasFaucetContract common.Address
|
||||||
GasRefillThreshold *big.Int
|
GasRefillThreshold *big.Int
|
||||||
GasRefillValue *big.Int
|
GasRefillValue *big.Int
|
||||||
GiftableGasValue *big.Int
|
GiftableGasValue *big.Int
|
||||||
@ -37,6 +39,7 @@ type Task struct {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
PrepareAccountTask TaskName = "sys:prepare_account"
|
PrepareAccountTask TaskName = "sys:prepare_account"
|
||||||
|
RegisterAccountOnChain TaskName = "sys:register_account"
|
||||||
GiftGasTask TaskName = "sys:gift_gas"
|
GiftGasTask TaskName = "sys:gift_gas"
|
||||||
GiftTokenTask TaskName = "sys:gift_token"
|
GiftTokenTask TaskName = "sys:gift_token"
|
||||||
RefillGasTask TaskName = "admin:refill_gas"
|
RefillGasTask TaskName = "admin:refill_gas"
|
||||||
|
@ -5,4 +5,4 @@ CREATE TABLE IF NOT EXISTS keystore (
|
|||||||
private_key TEXT NOT NULL,
|
private_key TEXT NOT NULL,
|
||||||
active BOOLEAN DEFAULT true,
|
active BOOLEAN DEFAULT true,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
);
|
@ -2,22 +2,22 @@
|
|||||||
CREATE TABLE IF NOT EXISTS otx (
|
CREATE TABLE IF NOT EXISTS otx (
|
||||||
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
tracking_id TEXT NOT NULL,
|
tracking_id TEXT NOT NULL,
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
raw_tx TEXT NOT NULL,
|
raw_tx TEXT NOT NULL,
|
||||||
tx_hash TEXT NOT NULL,
|
tx_hash TEXT NOT NULL,
|
||||||
from TEXT NOT NULL,
|
"from" TEXT NOT NULL,
|
||||||
data TEXT NOT NULL,
|
"data" TEXT NOT NULL,
|
||||||
gas_price bigint NOT NULL,
|
gas_price bigint NOT NULL,
|
||||||
nonce int NOT NULL,
|
nonce int NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
);
|
||||||
CREATE INDEX IF NOT EXISTS tx_hash_idx ON otx USING hash(tx_hash);
|
CREATE INDEX IF NOT EXISTS tx_hash_idx ON otx USING hash(tx_hash);
|
||||||
CREATE INDEX IF NOT EXISTS from_idx ON otx USING hash(from);
|
CREATE INDEX IF NOT EXISTS from_idx ON otx USING hash("from");
|
||||||
|
|
||||||
-- Dispatch status table
|
-- Dispatch status table
|
||||||
CREATE TABLE IF NOT EXISTS dispatch (
|
CREATE TABLE IF NOT EXISTS dispatch (
|
||||||
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
otx_id INT REFERENCES otx(id),
|
otx_id INT REFERENCES otx(id),
|
||||||
status TEXT NOT NULL,
|
"status" TEXT NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
);
|
||||||
CREATE INDEX IF NOT EXISTS dispatch_receipt_idx ON dispatch USING hash(dispatch_receipt);
|
|
||||||
|
36
queries.sql
36
queries.sql
@ -9,28 +9,30 @@ INSERT INTO keystore(public_key, private_key) VALUES($1, $2) RETURNING id
|
|||||||
--name: load-key-pair
|
--name: load-key-pair
|
||||||
-- Load saved key pair
|
-- Load saved key pair
|
||||||
-- $1: public_key
|
-- $1: public_key
|
||||||
SELECT private_key FROM keystore WHERE id=$1
|
SELECT private_key FROM keystore WHERE public_key=$1
|
||||||
|
|
||||||
-- OTX queries
|
-- OTX queries
|
||||||
|
|
||||||
--name: create-otx
|
--name: create-otx
|
||||||
-- Create a new locally originating tx
|
-- Create a new locally originating tx
|
||||||
-- $1: raw_tx
|
-- $1: tracking_id
|
||||||
-- $2: tx_hash
|
-- $2: type
|
||||||
-- $3: from
|
-- $3: raw_tx
|
||||||
-- $4: data
|
-- $4: tx_hash
|
||||||
-- $5: gas_price
|
-- $5: from
|
||||||
-- $6: nonce
|
-- $6: data
|
||||||
-- $7: tracking_id
|
-- $7: gas_price
|
||||||
|
-- $8: nonce
|
||||||
INSERT INTO otx(
|
INSERT INTO otx(
|
||||||
|
tracking_id,
|
||||||
|
"type",
|
||||||
raw_tx,
|
raw_tx,
|
||||||
tx_hash,
|
tx_hash,
|
||||||
from,
|
"from",
|
||||||
data,
|
"data",
|
||||||
gas_price,
|
gas_price,
|
||||||
nonce,
|
nonce
|
||||||
tracking_id
|
) VALUES($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id
|
||||||
) VALUES($1, $2, $3, $4, $5, $6, $7) RETURNING id
|
|
||||||
|
|
||||||
|
|
||||||
-- Dispatch status queries
|
-- Dispatch status queries
|
||||||
@ -39,9 +41,7 @@ INSERT INTO otx(
|
|||||||
-- Create a new dispatch status
|
-- Create a new dispatch status
|
||||||
-- $1: otx_id
|
-- $1: otx_id
|
||||||
-- $2: status
|
-- $2: status
|
||||||
-- £3: tracking_id
|
INSERT INTO dispatch(
|
||||||
INSERT INTO otx(
|
|
||||||
otx_id,
|
otx_id,
|
||||||
status,
|
"status"
|
||||||
tracking_id
|
) VALUES($1, $2) RETURNING id
|
||||||
) VALUES($1, $2, $3) RETURNING id
|
|
Loading…
Reference in New Issue
Block a user