Add first version of client SDK (#193)

* Add gRPC, REST, and gRPC-Web clients for server access

This commit introduces clients for gRPC, REST, and gRPC-Web to access the server.

- gRPC client: Includes additional argument opts ...grpc.CallOption in the interface for future extensibility.
- REST client: Factory function accepts http.Client as an argument to allow user customization.
- gRPC-Web client: Added a Log method for fast debugging in JavaScript.

The decision to use different interfaces for each client type is to accommodate specific features and extensibility requirements for each protocol.

* remove grpc web

* generate rest

* use grpc sdk in CLI

* temp wasm

* ark sdk

* renaming

* pr review refactor

* pr review refactor

* walletStore & configStore

* ark sdk wasm wrapper

* handle event stream with rest

* wip on supporting rest

* store init

* simulate event stream with rest

* fix rest sdk wip

* Fix returning forfeit txs in round event

* wasm first working e2e example

* pr review refactor

* pr review refactor

* pr review refactor

* Fixes

---------

Co-authored-by: altafan <18440657+altafan@users.noreply.github.com>
This commit is contained in:
Dusan Sekulic
2024-07-18 16:27:14 +02:00
committed by GitHub
parent 498394a191
commit 1f42843a69
110 changed files with 11738 additions and 86 deletions

View File

@@ -0,0 +1,225 @@
package arksdkwasm
import (
"context"
"errors"
"syscall/js"
arksdk "github.com/ark-network/ark-sdk"
inmemorystore "github.com/ark-network/ark-sdk/store/inmemory"
)
var (
arkSdkClient arksdk.ArkClient
inMemoryConfigStore arksdk.ConfigStore
inMemoryWalletStore arksdk.WalletStore
)
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())
js.Global().Set("balance", BalanceWrapper())
js.Global().Set("onboard", OnboardWrapper())
js.Global().Set("receive", ReceiveWrapper())
js.Global().Set("sendOnChain", SendOnChainWrapper())
js.Global().Set("sendOffChain", SendOffChainWrapper())
js.Global().Set("unilateralRedeem", UnilateralRedeemWrapper())
js.Global().Set("collaborativeRedeem", CollaborativeRedeemWrapper())
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("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("createPrivateKey", CreatePrivateKeyWrapper())
js.Global().Set("getPrivateKeyHex", GetPrivateKeyHexWrapper())
js.Global().Set("saveWalletStore", SaveWalletStoreWrapper())
select {}
}
func LogWrapper() js.Func {
return js.FuncOf(func(this js.Value, p []js.Value) interface{} {
logMsg(p[0].String())
return nil
})
}
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())
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)
})
}