Update client sdk (#207)

* Add bitcoin networks

* Refactor client

* Refactor explorer

* Refactor store

* Refactor wallet

* Refactor sdk client

* Refactor wasm & Update examples

* Move common util funcs to internal/utils

* Move to constants for service types

* Add unit tests

* Parallelize tests

* Lint

* Add job to gh action

* go mod tidy

* Fixes

* Fixes

* Fix compose file

* Fixes

* Fixes after review:
* Drop factory pattern
* Drop password from ark client methods
* Make singlekey wallet manage store and wallet store instead of defining WalletStore as extension of Store
* Move constants to arksdk module
* Drop config and expect directory store and wallet as ark client factory args

* Fix

* Add constants for bitcoin/liquid explorer

* Fix test

* Fix wasm

* Rename client.Client to client.ASPClient

* Rename store.Store to store.ConfigStore

* Rename wallet.Wallet to wallet.WalletService

* Renamings

* Lint

* Fixes

* Move everything to internal/utils & move ComputeVtxoTaprootScript to common

* Go mod tidy
This commit is contained in:
Pietralberto Mazza
2024-07-30 16:08:23 +02:00
committed by GitHub
parent e45bff3c70
commit 89df461623
148 changed files with 8497 additions and 6466 deletions

View File

@@ -2,40 +2,26 @@ package arksdkwasm
import (
"context"
"errors"
"fmt"
"strings"
"syscall/js"
arksdk "github.com/ark-network/ark-sdk"
inmemorystore "github.com/ark-network/ark-sdk/store/inmemory"
"github.com/ark-network/ark-sdk/store"
"github.com/ark-network/ark-sdk/wallet"
liquidwallet "github.com/ark-network/ark-sdk/wallet/singlekey/liquid"
walletstore "github.com/ark-network/ark-sdk/wallet/singlekey/store"
)
var (
arkSdkClient arksdk.ArkClient
inMemoryConfigStore arksdk.ConfigStore
inMemoryWalletStore arksdk.WalletStore
arkSdkClient arksdk.ArkClient
configStore store.ConfigStore
)
func New(ctx context.Context, aspUrl string) error {
var err error
inMemoryConfigStore, err = inmemorystore.New(aspUrl, arksdk.Rest)
if err != nil {
return err
}
inMemoryWalletStore = inmemorystore.NewWalletStore()
wallet, err := arksdk.NewSingleKeyWallet(ctx, inMemoryWalletStore)
if err != nil {
return err
}
arkSdkClient, err = arksdk.New(ctx, wallet, inMemoryConfigStore)
if err != nil {
js.Global().Get("console").Call("error", err.Error())
return err
}
js.Global().Set("connect", ConnectWrapper())
func init() {
js.Global().Set("init", InitWrapper())
js.Global().Set("unlock", UnlockWrapper())
js.Global().Set("lock", LockWrapper())
js.Global().Set("balance", BalanceWrapper())
js.Global().Set("onboard", OnboardWrapper())
js.Global().Set("receive", ReceiveWrapper())
@@ -46,180 +32,68 @@ func New(ctx context.Context, aspUrl string) error {
js.Global().Set("log", LogWrapper())
js.Global().Set("getAspUrl", GetAspUrlWrapper())
js.Global().Set("getAspPubKeyHex", GetAspPubKeyHexWrapper())
js.Global().Set("getTransportProtocol", GetTransportProtocolWrapper())
js.Global().Set("getExplorerUrl", GetExplorerUrlWrapper())
js.Global().Set("getAspPubKeyHex", GetAspPubkeyWrapper())
js.Global().Set("getWalletType", GetWalletTypeWrapper())
js.Global().Set("getClientType", GetClientTypeWrapper())
js.Global().Set("getNetwork", GetNetworkWrapper())
js.Global().Set("setAspUrl", SetAspUrlWrapper())
js.Global().Set("setAspPubKeyHex", SetAspPubKeyHexWrapper())
js.Global().Set("setTransportProtocol", SetTransportProtocolWrapper())
js.Global().Set("setExplorerUrl", SetExplorerUrlWrapper())
js.Global().Set("setNetwork", SetNetworkWrapper())
js.Global().Set("saveConfigStore", SaveWrapper())
js.Global().Set("getRoundLifetime", GetRoundLifetimeWrapper())
js.Global().Set("getUnilateralExitDelay", GetUnilateralExitDelayWrapper())
js.Global().Set("getMinRelayFee", GetMinRelayFeeWrapper())
}
js.Global().Set("createPrivateKey", CreatePrivateKeyWrapper())
js.Global().Set("getPrivateKeyHex", GetPrivateKeyHexWrapper())
js.Global().Set("saveWalletStore", SaveWalletStoreWrapper())
func New(
ctx context.Context, storeSvc store.ConfigStore,
) error {
var err error
data, err := storeSvc.GetData(ctx)
if err != nil {
return err
}
if data == nil {
arkSdkClient, err = arksdk.New(storeSvc)
} else {
var walletSvc wallet.WalletService
switch data.WalletType {
case arksdk.SingleKeyWallet:
walletSvc, err = getSingleKeyWallet(storeSvc, data.Network.Name)
if err != nil {
return err
}
// TODO: Support HD wallet
default:
return fmt.Errorf("unknown wallet type")
}
arkSdkClient, err = arksdk.LoadWithWallet(storeSvc, walletSvc)
}
if err != nil {
js.Global().Get("console").Call("error", err.Error())
return err
}
configStore = storeSvc
select {}
}
func LogWrapper() js.Func {
return js.FuncOf(func(this js.Value, p []js.Value) interface{} {
logMsg(p[0].String())
return nil
})
func getWalletStore(storeType string) (walletstore.WalletStore, error) {
if storeType == LocalStorageStore {
return NewLocalStorageWalletStore()
}
// TODO: Support IndexDB store
return nil, fmt.Errorf("unknown wallet store type")
}
func logMsg(msg string) {
js.Global().Get("console").Call("log", msg)
}
func ConnectWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
err := arkSdkClient.Connect(context.Background())
func getSingleKeyWallet(
configStore store.ConfigStore, network string,
) (wallet.WalletService, error) {
walletStore, err := getWalletStore(configStore.GetType())
if err != nil {
return nil, err
})
}
func BalanceWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
computeExpiryDetails := args[0].Bool()
resp, err := arkSdkClient.Balance(context.Background(), computeExpiryDetails)
if err != nil {
return nil, err
}
var (
onchainBalance int
offchainBalance int
)
if resp == nil {
onchainBalance = 0
offchainBalance = 0
} else {
onchainBalance = int(resp.OnchainBalance.SpendableAmount)
offchainBalance = int(resp.OffchainBalance.Total)
}
result := map[string]interface{}{
"onchain_balance": onchainBalance,
"offchain_balance": offchainBalance,
}
return js.ValueOf(result), nil
})
}
func OnboardWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
if len(args) == 0 {
return nil, errors.New("no amount provided")
}
amount := uint64(args[0].Int())
txID, err := arkSdkClient.Onboard(context.Background(), amount)
if err != nil {
return nil, err
}
return js.ValueOf(txID), nil
})
}
func ReceiveWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
offchainAddr, onchainAddr, err := arkSdkClient.Receive(context.Background())
if err != nil {
return nil, err
}
result := map[string]interface{}{
"offchainAddr": offchainAddr,
"onchainAddr": onchainAddr,
}
return js.ValueOf(result), nil
})
}
func SendOnChainWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
receivers := make([]arksdk.Receiver, args[0].Length())
for i := 0; i < args[0].Length(); i++ {
receiver := args[0].Index(i)
receivers[i] = arksdk.Receiver{
To: receiver.Get("To").String(),
Amount: uint64(receiver.Get("Amount").Int()),
}
}
txID, err := arkSdkClient.SendOnChain(context.Background(), receivers)
if err != nil {
return nil, err
}
return js.ValueOf(txID), nil
})
}
func SendOffChainWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
withExpiryCoinselect := args[0].Bool()
receivers := make([]arksdk.Receiver, args[1].Length())
for i := 0; i < args[1].Length(); i++ {
receiver := args[1].Index(i)
receivers[i] = arksdk.Receiver{
To: receiver.Get("To").String(),
Amount: uint64(receiver.Get("Amount").Int()),
}
}
txID, err := arkSdkClient.SendOffChain(context.Background(), withExpiryCoinselect, receivers)
if err != nil {
return nil, err
}
return js.ValueOf(txID), nil
})
}
func UnilateralRedeemWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
return nil, arkSdkClient.UnilateralRedeem(context.Background())
})
}
func CollaborativeRedeemWrapper() js.Func {
return JSPromise(func(args []js.Value) (interface{}, error) {
addr := args[0].String()
amount := uint64(args[1].Int())
withExpiryCoinselect := args[2].Bool()
txID, err := arkSdkClient.CollaborativeRedeem(context.Background(), addr, amount, withExpiryCoinselect)
if err != nil {
return nil, err
}
return js.ValueOf(txID), nil
})
}
type promise func(args []js.Value) (interface{}, error)
func JSPromise(fn promise) js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
handlerArgs := args
handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
resolve := args[0]
reject := args[1]
go func() {
data, err := fn(handlerArgs)
if err != nil {
errorConstructor := js.Global().Get("Error")
errorObject := errorConstructor.New(err.Error())
reject.Invoke(errorObject)
} else {
resolve.Invoke(data)
}
}()
return nil
})
promiseConstructor := js.Global().Get("Promise")
return promiseConstructor.New(handler)
})
}
if strings.Contains(network, "liquid") {
return liquidwallet.NewWalletService(configStore, walletStore)
}
// TODO: Support bitcoin wallet
return nil, fmt.Errorf("network %s not supported yet", network)
}