From 5652a08628a952c6707b129ddda889a5fff3b9b3 Mon Sep 17 00:00:00 2001 From: Patryk Kalinowski Date: Tue, 12 Mar 2024 18:10:49 +0100 Subject: [PATCH] deps: update webrpc & go-sequence (#31) --- go.mod | 5 +- go.sum | 10 +- proto/authenticator.gen.go | 187 +- proto/clients/authenticator.gen.go | 186 +- proto/clients/authenticator.gen.ts | 6 +- proto/proto.go | 4 +- .../go-sequence/intents/intent.gen.go | 93 +- .../go-sequence/intents/intent.gen.ts | 49 +- .../go-sequence/intents/intent.ridl | 42 +- ...intent_data_get_transaction_receipt_ext.go | 23 + .../go-sequence/intents/intent_ext.go | 3 + .../go-sequence/intents/intent_typed.go | 4 + .../0xsequence/go-sequence/relayer.go | 33 +- .../go-sequence/relayer/proto/relayer.gen.go | 397 +++- .../0xsequence/go-sequence/wallet.go | 77 +- .../github.com/shopspring/decimal/.gitignore | 9 + .../github.com/shopspring/decimal/.travis.yml | 19 + .../shopspring/decimal/CHANGELOG.md | 49 + vendor/github.com/shopspring/decimal/LICENSE | 45 + .../github.com/shopspring/decimal/README.md | 130 ++ .../shopspring/decimal/decimal-go.go | 415 ++++ .../github.com/shopspring/decimal/decimal.go | 1904 +++++++++++++++++ .../github.com/shopspring/decimal/rounding.go | 160 ++ .../github.com/webrpc/webrpc/gen/funcmap.go | 1 + .../webrpc/webrpc/gen/funcmap_types.go | 28 +- .../webrpc/webrpc/gen/template_source.go | 15 +- .../webrpc/schema/ridl/definition_parser.go | 1 + .../webrpc/webrpc/schema/ridl/enum_parser.go | 3 + .../webrpc/webrpc/schema/ridl/parser.go | 59 +- .../webrpc/webrpc/schema/ridl/parser_node.go | 24 +- .../webrpc/webrpc/schema/ridl/ridl.go | 44 +- .../webrpc/schema/ridl/service_parser.go | 7 +- .../webrpc/schema/ridl/struct_parser.go | 6 +- .../webrpc/webrpc/schema/ridl/tokenizer.go | 37 +- .../github.com/webrpc/webrpc/schema/schema.go | 4 +- .../webrpc/webrpc/schema/service.go | 8 +- .../github.com/webrpc/webrpc/schema/type.go | 21 +- .../webrpc/webrpc/schema/var_type.go | 5 +- vendor/github.com/webrpc/webrpc/version.go | 2 +- vendor/modules.txt | 7 +- 40 files changed, 3869 insertions(+), 253 deletions(-) create mode 100644 vendor/github.com/0xsequence/go-sequence/intents/intent_data_get_transaction_receipt_ext.go create mode 100644 vendor/github.com/shopspring/decimal/.gitignore create mode 100644 vendor/github.com/shopspring/decimal/.travis.yml create mode 100644 vendor/github.com/shopspring/decimal/CHANGELOG.md create mode 100644 vendor/github.com/shopspring/decimal/LICENSE create mode 100644 vendor/github.com/shopspring/decimal/README.md create mode 100644 vendor/github.com/shopspring/decimal/decimal-go.go create mode 100644 vendor/github.com/shopspring/decimal/decimal.go create mode 100644 vendor/github.com/shopspring/decimal/rounding.go diff --git a/go.mod b/go.mod index 1bf44157..2edb93bc 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21.5 require ( github.com/0xsequence/ethkit v1.23.0 - github.com/0xsequence/go-sequence v0.29.0 + github.com/0xsequence/go-sequence v0.29.2 github.com/0xsequence/nitrocontrol v0.3.0 github.com/BurntSushi/toml v1.3.2 github.com/aws/aws-sdk-go-v2 v1.25.2 @@ -24,7 +24,7 @@ require ( github.com/mdlayher/vsock v1.2.1 github.com/rs/zerolog v1.32.0 github.com/stretchr/testify v1.8.4 - github.com/webrpc/webrpc v0.14.0 + github.com/webrpc/webrpc v0.15.2 golang.org/x/sync v0.6.0 ) @@ -101,6 +101,7 @@ require ( github.com/redis/go-redis/v9 v9.5.1 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect + github.com/shopspring/decimal v1.3.1 // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/go.sum b/go.sum index 8c8921e7..e674f7b6 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/0xsequence/ethkit v1.23.0 h1:QrxgyyzFpnsBnZComIcj7H5EuN+yoIxTrO86Pdrp github.com/0xsequence/ethkit v1.23.0/go.mod h1:a7uC7bUyFODaQhz+d46/oeXhwKTF+KtHF0aGmcxX5Hg= github.com/0xsequence/go-ethauth v0.13.0 h1:ZaqFEEqy574A2b1P7vjpcy5tb4W/izn+A3swwOYi9wA= github.com/0xsequence/go-ethauth v0.13.0/go.mod h1:f3kx39S9F+W+qvZEB6bkKKbpUstmyB7goUntO3wvlhg= -github.com/0xsequence/go-sequence v0.29.0 h1:OZ/JExeI2feUc6QVk/LAgdFIQCrzBXfw4htAtUfbTcs= -github.com/0xsequence/go-sequence v0.29.0/go.mod h1:e/O48g6ejYr18aOeiuVedvqYSvYUxk9Poq6dIOVSVQA= +github.com/0xsequence/go-sequence v0.29.2 h1:lAiGRWXHAxwq6IXaItKnm3Aqxh7FZSbzHBoUCPUjKGw= +github.com/0xsequence/go-sequence v0.29.2/go.mod h1:gZnfEzmC67Fr6Tp1TKVQP9Ic+grjV7TSzDW26vvQ/J8= github.com/0xsequence/nitrocontrol v0.3.0 h1:D0/gX576zQhitrJnBfBrOFFufEOzh6f2jO/+2ynwIUA= github.com/0xsequence/nitrocontrol v0.3.0/go.mod h1:sTG5akVPzoVr3unv/7h9aZGaT+BVGmvUMOdwXFeIEEA= github.com/0xsequence/nsm v0.1.0 h1:gVOViRWPUW/c5VEmGy2gCw1az/nqP3gY7VD9V2+069k= @@ -352,6 +352,8 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= @@ -390,8 +392,8 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/uber-go/tally/v4 v4.1.11 h1:ktRXNpbia2cKbyAOIEdNdgkfPBzwCzIYJ20Kn6qQr7w= github.com/uber-go/tally/v4 v4.1.11/go.mod h1:RW5DgqsyEPs0lA4b0YNf4zKj7DveKHd73hnO6zVlyW0= -github.com/webrpc/webrpc v0.14.0 h1:71xZP8APUY3NKDgO/HJISq6TYsQrLt4AUoq/WT7Af68= -github.com/webrpc/webrpc v0.14.0/go.mod h1:/XwWjfVHHzXPtB8UaX+viElNtAEAq0J7Mf7ZjnF4d9k= +github.com/webrpc/webrpc v0.15.2 h1:kGIHJh6X0QlC8kmZWBmu+rwGr26HMy7uL1YDJ8i7fm4= +github.com/webrpc/webrpc v0.15.2/go.mod h1:/XwWjfVHHzXPtB8UaX+viElNtAEAq0J7Mf7ZjnF4d9k= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= diff --git a/proto/authenticator.gen.go b/proto/authenticator.gen.go index 3fec520b..202fce5c 100644 --- a/proto/authenticator.gen.go +++ b/proto/authenticator.gen.go @@ -1,8 +1,8 @@ -// sequence-waas-authenticator v0.1.0 a753d63c2d2bbb862ca2c9efb16ba355b19a81aa +// sequence-waas-authenticator v0.1.0 3f8465a3a233581e35b46bda830d8b31e2e71bde // -- -// Code generated by webrpc-gen@v0.14.0-dev with golang@v0.13.6 generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.15.2-dev with golang@v0.14.1 generator. DO NOT EDIT. // -// webrpc-gen -schema=authenticator.ridl -target=golang@v0.13.6 -pkg=proto -server -client -out=./authenticator.gen.go +// webrpc-gen -schema=authenticator.ridl -target=golang@v0.14.1 -pkg=proto -server -client -out=./authenticator.gen.go package proto import ( @@ -34,7 +34,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "a753d63c2d2bbb862ca2c9efb16ba355b19a81aa" + return "3f8465a3a233581e35b46bda830d8b31e2e71bde" } // @@ -113,6 +113,7 @@ type Version struct { } type RuntimeStatus struct { + // overall status , true/false HealthOK bool `json:"healthOK"` StartTime time.Time `json:"startTime"` Uptime uint64 `json:"uptime"` @@ -191,6 +192,26 @@ type SessionData struct { ExpiresAt time.Time `json:"expiresAt"` } +var WebRPCServices = map[string][]string{ + "WaasAuthenticator": { + "RegisterSession", + "SendIntent", + "ChainList", + }, + "WaasAuthenticatorAdmin": { + "Version", + "RuntimeStatus", + "Clock", + "GetTenant", + "CreateTenant", + "UpdateTenant", + }, +} + +// +// Server types +// + type WaasAuthenticator interface { RegisterSession(ctx context.Context, intent *Intent, friendlyName string) (*Session, *IntentResponse, error) SendIntent(ctx context.Context, intent *Intent) (*IntentResponse, error) @@ -206,20 +227,23 @@ type WaasAuthenticatorAdmin interface { UpdateTenant(ctx context.Context, projectId uint64, upgradeCode string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, error) } -var WebRPCServices = map[string][]string{ - "WaasAuthenticator": { - "RegisterSession", - "SendIntent", - "ChainList", - }, - "WaasAuthenticatorAdmin": { - "Version", - "RuntimeStatus", - "Clock", - "GetTenant", - "CreateTenant", - "UpdateTenant", - }, +// +// Client types +// + +type WaasAuthenticatorClient interface { + RegisterSession(ctx context.Context, intent *Intent, friendlyName string) (*Session, *IntentResponse, error) + SendIntent(ctx context.Context, intent *Intent) (*IntentResponse, error) + ChainList(ctx context.Context) ([]*Chain, error) +} + +type WaasAuthenticatorAdminClient interface { + Version(ctx context.Context) (*Version, error) + RuntimeStatus(ctx context.Context) (*RuntimeStatus, error) + Clock(ctx context.Context) (time.Time, error) + GetTenant(ctx context.Context, projectId uint64) (*Tenant, error) + CreateTenant(ctx context.Context, projectId uint64, waasAccessToken string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, string, error) + UpdateTenant(ctx context.Context, projectId uint64, upgradeCode string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, error) } // @@ -717,6 +741,7 @@ func (s *waasAuthenticatorAdminServer) sendErrorJSON(w http.ResponseWriter, r *h respBody, _ := json.Marshal(rpcErr) w.Write(respBody) } + func RespondWithError(w http.ResponseWriter, err error) { rpcErr, ok := err.(WebRPCError) if !ok { @@ -742,7 +767,7 @@ type waasAuthenticatorClient struct { urls [3]string } -func NewWaasAuthenticatorClient(addr string, client HTTPClient) WaasAuthenticator { +func NewWaasAuthenticatorClient(addr string, client HTTPClient) WaasAuthenticatorClient { prefix := urlBase(addr) + WaasAuthenticatorPathPrefix urls := [3]string{ prefix + "RegisterSession", @@ -765,7 +790,14 @@ func (c *waasAuthenticatorClient) RegisterSession(ctx context.Context, intent *I Ret1 *IntentResponse `json:"response"` }{} - err := doJSONRequest(ctx, c.client, c.urls[0], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, out.Ret1, err } @@ -777,7 +809,14 @@ func (c *waasAuthenticatorClient) SendIntent(ctx context.Context, intent *Intent Ret0 *IntentResponse `json:"response"` }{} - err := doJSONRequest(ctx, c.client, c.urls[1], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -786,7 +825,14 @@ func (c *waasAuthenticatorClient) ChainList(ctx context.Context) ([]*Chain, erro Ret0 []*Chain `json:"chains"` }{} - err := doJSONRequest(ctx, c.client, c.urls[2], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -795,7 +841,7 @@ type waasAuthenticatorAdminClient struct { urls [6]string } -func NewWaasAuthenticatorAdminClient(addr string, client HTTPClient) WaasAuthenticatorAdmin { +func NewWaasAuthenticatorAdminClient(addr string, client HTTPClient) WaasAuthenticatorAdminClient { prefix := urlBase(addr) + WaasAuthenticatorAdminPathPrefix urls := [6]string{ prefix + "Version", @@ -816,7 +862,14 @@ func (c *waasAuthenticatorAdminClient) Version(ctx context.Context) (*Version, e Ret0 *Version `json:"version"` }{} - err := doJSONRequest(ctx, c.client, c.urls[0], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -825,7 +878,14 @@ func (c *waasAuthenticatorAdminClient) RuntimeStatus(ctx context.Context) (*Runt Ret0 *RuntimeStatus `json:"status"` }{} - err := doJSONRequest(ctx, c.client, c.urls[1], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -834,7 +894,14 @@ func (c *waasAuthenticatorAdminClient) Clock(ctx context.Context) (time.Time, er Ret0 time.Time `json:"serverTime"` }{} - err := doJSONRequest(ctx, c.client, c.urls[2], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -846,7 +913,14 @@ func (c *waasAuthenticatorAdminClient) GetTenant(ctx context.Context, projectId Ret0 *Tenant `json:"tenant"` }{} - err := doJSONRequest(ctx, c.client, c.urls[3], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[3], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -862,7 +936,14 @@ func (c *waasAuthenticatorAdminClient) CreateTenant(ctx context.Context, project Ret1 string `json:"upgradeCode"` }{} - err := doJSONRequest(ctx, c.client, c.urls[4], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[4], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, out.Ret1, err } @@ -877,7 +958,14 @@ func (c *waasAuthenticatorAdminClient) UpdateTenant(ctx context.Context, project Ret0 *Tenant `json:"tenant"` }{} - err := doJSONRequest(ctx, c.client, c.urls[5], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[5], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -905,7 +993,7 @@ func urlBase(addr string) string { // newRequest makes an http.Request from a client, adding common headers. func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) { - req, err := http.NewRequest("POST", url, reqBody) + req, err := http.NewRequestWithContext(ctx, "POST", url, reqBody) if err != nil { return nil, err } @@ -921,65 +1009,55 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType return req, nil } -// doJSONRequest is common code to make a request to the remote service. -func doJSONRequest(ctx context.Context, client HTTPClient, url string, in, out interface{}) error { +// doHTTPRequest is common code to make a request to the remote service. +func doHTTPRequest(ctx context.Context, client HTTPClient, url string, in, out interface{}) (*http.Response, error) { reqBody, err := json.Marshal(in) if err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to marshal JSON body: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to marshal JSON body: %w", err)) } if err = ctx.Err(); err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) } req, err := newRequest(ctx, url, bytes.NewBuffer(reqBody), "application/json") if err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("could not build request: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("could not build request: %w", err)) } + resp, err := client.Do(req) if err != nil { - return ErrWebrpcRequestFailed.WithCause(err) - } - - defer func() { - cerr := resp.Body.Close() - if err == nil && cerr != nil { - err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) - } - }() - - if err = ctx.Err(); err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(err) } if resp.StatusCode != 200 { respBody, err := io.ReadAll(resp.Body) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read server error response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read server error response body: %w", err)) } var rpcErr WebRPCError if err := json.Unmarshal(respBody, &rpcErr); err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal server error: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal server error: %w", err)) } if rpcErr.Cause != "" { rpcErr.cause = errors.New(rpcErr.Cause) } - return rpcErr + return nil, rpcErr } if out != nil { respBody, err := io.ReadAll(resp.Body) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read response body: %w", err)) } err = json.Unmarshal(respBody, &out) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal JSON response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal JSON response body: %w", err)) } } - return nil + return resp, nil } func WithHTTPRequestHeaders(ctx context.Context, h http.Header) (context.Context, error) { @@ -1073,6 +1151,9 @@ func (e WebRPCError) Error() string { } func (e WebRPCError) Is(target error) bool { + if target == nil { + return false + } if rpcErr, ok := target.(WebRPCError); ok { return rpcErr.Code == e.Code } diff --git a/proto/clients/authenticator.gen.go b/proto/clients/authenticator.gen.go index 705ba3d1..57fa2a11 100644 --- a/proto/clients/authenticator.gen.go +++ b/proto/clients/authenticator.gen.go @@ -1,8 +1,8 @@ -// sequence-waas-authenticator v0.1.0 a753d63c2d2bbb862ca2c9efb16ba355b19a81aa +// sequence-waas-authenticator v0.1.0 3f8465a3a233581e35b46bda830d8b31e2e71bde // -- -// Code generated by webrpc-gen@v0.14.0-dev with golang@v0.13.6 generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.15.2-dev with golang@v0.14.1 generator. DO NOT EDIT. // -// webrpc-gen -schema=authenticator.ridl -target=golang@v0.13.6 -pkg=proto -client -out=./clients/authenticator.gen.go +// webrpc-gen -schema=authenticator.ridl -target=golang@v0.14.1 -pkg=proto -client -out=./clients/authenticator.gen.go package proto import ( @@ -33,7 +33,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "a753d63c2d2bbb862ca2c9efb16ba355b19a81aa" + return "3f8465a3a233581e35b46bda830d8b31e2e71bde" } // @@ -112,6 +112,7 @@ type Version struct { } type RuntimeStatus struct { + // overall status , true/false HealthOK bool `json:"healthOK"` StartTime time.Time `json:"startTime"` Uptime uint64 `json:"uptime"` @@ -190,6 +191,26 @@ type SessionData struct { ExpiresAt time.Time `json:"expiresAt"` } +var WebRPCServices = map[string][]string{ + "WaasAuthenticator": { + "RegisterSession", + "SendIntent", + "ChainList", + }, + "WaasAuthenticatorAdmin": { + "Version", + "RuntimeStatus", + "Clock", + "GetTenant", + "CreateTenant", + "UpdateTenant", + }, +} + +// +// Server types +// + type WaasAuthenticator interface { RegisterSession(ctx context.Context, intent *Intent, friendlyName string) (*Session, *IntentResponse, error) SendIntent(ctx context.Context, intent *Intent) (*IntentResponse, error) @@ -205,20 +226,23 @@ type WaasAuthenticatorAdmin interface { UpdateTenant(ctx context.Context, projectId uint64, upgradeCode string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, error) } -var WebRPCServices = map[string][]string{ - "WaasAuthenticator": { - "RegisterSession", - "SendIntent", - "ChainList", - }, - "WaasAuthenticatorAdmin": { - "Version", - "RuntimeStatus", - "Clock", - "GetTenant", - "CreateTenant", - "UpdateTenant", - }, +// +// Client types +// + +type WaasAuthenticatorClient interface { + RegisterSession(ctx context.Context, intent *Intent, friendlyName string) (*Session, *IntentResponse, error) + SendIntent(ctx context.Context, intent *Intent) (*IntentResponse, error) + ChainList(ctx context.Context) ([]*Chain, error) +} + +type WaasAuthenticatorAdminClient interface { + Version(ctx context.Context) (*Version, error) + RuntimeStatus(ctx context.Context) (*RuntimeStatus, error) + Clock(ctx context.Context) (time.Time, error) + GetTenant(ctx context.Context, projectId uint64) (*Tenant, error) + CreateTenant(ctx context.Context, projectId uint64, waasAccessToken string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, string, error) + UpdateTenant(ctx context.Context, projectId uint64, upgradeCode string, oidcProviders []*OpenIdProvider, allowedOrigins []string) (*Tenant, error) } // @@ -233,7 +257,7 @@ type waasAuthenticatorClient struct { urls [3]string } -func NewWaasAuthenticatorClient(addr string, client HTTPClient) WaasAuthenticator { +func NewWaasAuthenticatorClient(addr string, client HTTPClient) WaasAuthenticatorClient { prefix := urlBase(addr) + WaasAuthenticatorPathPrefix urls := [3]string{ prefix + "RegisterSession", @@ -256,7 +280,14 @@ func (c *waasAuthenticatorClient) RegisterSession(ctx context.Context, intent *I Ret1 *IntentResponse `json:"response"` }{} - err := doJSONRequest(ctx, c.client, c.urls[0], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, out.Ret1, err } @@ -268,7 +299,14 @@ func (c *waasAuthenticatorClient) SendIntent(ctx context.Context, intent *Intent Ret0 *IntentResponse `json:"response"` }{} - err := doJSONRequest(ctx, c.client, c.urls[1], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -277,7 +315,14 @@ func (c *waasAuthenticatorClient) ChainList(ctx context.Context) ([]*Chain, erro Ret0 []*Chain `json:"chains"` }{} - err := doJSONRequest(ctx, c.client, c.urls[2], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -286,7 +331,7 @@ type waasAuthenticatorAdminClient struct { urls [6]string } -func NewWaasAuthenticatorAdminClient(addr string, client HTTPClient) WaasAuthenticatorAdmin { +func NewWaasAuthenticatorAdminClient(addr string, client HTTPClient) WaasAuthenticatorAdminClient { prefix := urlBase(addr) + WaasAuthenticatorAdminPathPrefix urls := [6]string{ prefix + "Version", @@ -307,7 +352,14 @@ func (c *waasAuthenticatorAdminClient) Version(ctx context.Context) (*Version, e Ret0 *Version `json:"version"` }{} - err := doJSONRequest(ctx, c.client, c.urls[0], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[0], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -316,7 +368,14 @@ func (c *waasAuthenticatorAdminClient) RuntimeStatus(ctx context.Context) (*Runt Ret0 *RuntimeStatus `json:"status"` }{} - err := doJSONRequest(ctx, c.client, c.urls[1], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[1], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -325,7 +384,14 @@ func (c *waasAuthenticatorAdminClient) Clock(ctx context.Context) (time.Time, er Ret0 time.Time `json:"serverTime"` }{} - err := doJSONRequest(ctx, c.client, c.urls[2], nil, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[2], nil, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -337,7 +403,14 @@ func (c *waasAuthenticatorAdminClient) GetTenant(ctx context.Context, projectId Ret0 *Tenant `json:"tenant"` }{} - err := doJSONRequest(ctx, c.client, c.urls[3], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[3], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -353,7 +426,14 @@ func (c *waasAuthenticatorAdminClient) CreateTenant(ctx context.Context, project Ret1 string `json:"upgradeCode"` }{} - err := doJSONRequest(ctx, c.client, c.urls[4], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[4], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, out.Ret1, err } @@ -368,7 +448,14 @@ func (c *waasAuthenticatorAdminClient) UpdateTenant(ctx context.Context, project Ret0 *Tenant `json:"tenant"` }{} - err := doJSONRequest(ctx, c.client, c.urls[5], in, &out) + resp, err := doHTTPRequest(ctx, c.client, c.urls[5], in, &out) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + return out.Ret0, err } @@ -396,7 +483,7 @@ func urlBase(addr string) string { // newRequest makes an http.Request from a client, adding common headers. func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) { - req, err := http.NewRequest("POST", url, reqBody) + req, err := http.NewRequestWithContext(ctx, "POST", url, reqBody) if err != nil { return nil, err } @@ -412,65 +499,55 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType return req, nil } -// doJSONRequest is common code to make a request to the remote service. -func doJSONRequest(ctx context.Context, client HTTPClient, url string, in, out interface{}) error { +// doHTTPRequest is common code to make a request to the remote service. +func doHTTPRequest(ctx context.Context, client HTTPClient, url string, in, out interface{}) (*http.Response, error) { reqBody, err := json.Marshal(in) if err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to marshal JSON body: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to marshal JSON body: %w", err)) } if err = ctx.Err(); err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) } req, err := newRequest(ctx, url, bytes.NewBuffer(reqBody), "application/json") if err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("could not build request: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(fmt.Errorf("could not build request: %w", err)) } + resp, err := client.Do(req) if err != nil { - return ErrWebrpcRequestFailed.WithCause(err) - } - - defer func() { - cerr := resp.Body.Close() - if err == nil && cerr != nil { - err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) - } - }() - - if err = ctx.Err(); err != nil { - return ErrWebrpcRequestFailed.WithCause(fmt.Errorf("aborted because context was done: %w", err)) + return nil, ErrWebrpcRequestFailed.WithCause(err) } if resp.StatusCode != 200 { respBody, err := io.ReadAll(resp.Body) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read server error response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read server error response body: %w", err)) } var rpcErr WebRPCError if err := json.Unmarshal(respBody, &rpcErr); err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal server error: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal server error: %w", err)) } if rpcErr.Cause != "" { rpcErr.cause = errors.New(rpcErr.Cause) } - return rpcErr + return nil, rpcErr } if out != nil { respBody, err := io.ReadAll(resp.Body) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to read response body: %w", err)) } err = json.Unmarshal(respBody, &out) if err != nil { - return ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal JSON response body: %w", err)) + return nil, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to unmarshal JSON response body: %w", err)) } } - return nil + return resp, nil } func WithHTTPRequestHeaders(ctx context.Context, h http.Header) (context.Context, error) { @@ -558,6 +635,9 @@ func (e WebRPCError) Error() string { } func (e WebRPCError) Is(target error) bool { + if target == nil { + return false + } if rpcErr, ok := target.(WebRPCError); ok { return rpcErr.Code == e.Code } diff --git a/proto/clients/authenticator.gen.ts b/proto/clients/authenticator.gen.ts index be0ce965..3f9c8a0e 100644 --- a/proto/clients/authenticator.gen.ts +++ b/proto/clients/authenticator.gen.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -// sequence-waas-authenticator v0.1.0 a753d63c2d2bbb862ca2c9efb16ba355b19a81aa +// sequence-waas-authenticator v0.1.0 3f8465a3a233581e35b46bda830d8b31e2e71bde // -- -// Code generated by webrpc-gen@v0.14.0-dev with typescript generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.15.2-dev with typescript generator. DO NOT EDIT. // // webrpc-gen -schema=authenticator.ridl -target=typescript -client -out=./clients/authenticator.gen.ts @@ -12,7 +12,7 @@ export const WebRPCVersion = "v1" export const WebRPCSchemaVersion = "v0.1.0" // Schema hash generated from your RIDL schema -export const WebRPCSchemaHash = "a753d63c2d2bbb862ca2c9efb16ba355b19a81aa" +export const WebRPCSchemaHash = "3f8465a3a233581e35b46bda830d8b31e2e71bde" // // Types diff --git a/proto/proto.go b/proto/proto.go index 1628b719..c4ea7e42 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -1,8 +1,8 @@ // Server -//go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authenticator.ridl -target=golang@v0.13.6 -pkg=proto -server -client -out=./authenticator.gen.go +//go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authenticator.ridl -target=golang@v0.14.1 -pkg=proto -server -client -out=./authenticator.gen.go // Clients -//go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authenticator.ridl -target=golang@v0.13.6 -pkg=proto -client -out=./clients/authenticator.gen.go +//go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authenticator.ridl -target=golang@v0.14.1 -pkg=proto -client -out=./clients/authenticator.gen.go //go:generate go run github.com/webrpc/webrpc/cmd/webrpc-gen -schema=authenticator.ridl -target=typescript -client -out=./clients/authenticator.gen.ts package proto diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.go b/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.go index 18fb65db..aec15674 100644 --- a/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.go +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.go @@ -1,6 +1,6 @@ -// sequence-waas-intents v0.1.0 e8e022f41dd9c03ff373c616d8f484fbefdfe7d9 +// sequence-waas-intents v0.1.0 2c4dea0eacfd30c622628970fba756e9f4a21e61 // -- -// Code generated by webrpc-gen@v0.14.0-dev with golang generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.15.0-dev with golang generator. DO NOT EDIT. // // webrpc-gen -schema=intent.ridl -target=golang -pkg=intents -client -out=./intent.gen.go package intents @@ -25,13 +25,58 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "e8e022f41dd9c03ff373c616d8f484fbefdfe7d9" + return "2c4dea0eacfd30c622628970fba756e9f4a21e61" } // // Types // +type FeeTokenType uint32 + +const ( + FeeTokenType_unknown FeeTokenType = 0 + FeeTokenType_erc20Token FeeTokenType = 1 + FeeTokenType_erc1155Token FeeTokenType = 2 +) + +var FeeTokenType_name = map[uint32]string{ + 0: "unknown", + 1: "erc20Token", + 2: "erc1155Token", +} + +var FeeTokenType_value = map[string]uint32{ + "unknown": 0, + "erc20Token": 1, + "erc1155Token": 2, +} + +func (x FeeTokenType) String() string { + return FeeTokenType_name[uint32(x)] +} + +func (x FeeTokenType) MarshalText() ([]byte, error) { + return []byte(FeeTokenType_name[uint32(x)]), nil +} + +func (x *FeeTokenType) UnmarshalText(b []byte) error { + *x = FeeTokenType(FeeTokenType_value[string(b)]) + return nil +} + +func (x *FeeTokenType) Is(values ...FeeTokenType) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + type Intent struct { Version string `json:"version"` Name string `json:"name"` @@ -84,13 +129,27 @@ type IntentDataSignMessage struct { Message string `json:"message"` } -type IntentDataSendTransaction struct { +type IntentDataFeeOptions struct { Network string `json:"network"` Wallet string `json:"wallet"` Identifier string `json:"identifier"` Transactions []json.RawMessage `json:"transactions"` } +type IntentDataSendTransaction struct { + Network string `json:"network"` + Wallet string `json:"wallet"` + Identifier string `json:"identifier"` + Transactions []json.RawMessage `json:"transactions"` + TransactionsFeeQuote *string `json:"transactionsFeeQuote,omitempty"` +} + +type IntentDataGetTransactionReceipt struct { + Network string `json:"network"` + Wallet string `json:"wallet"` + MetaTxHash string `json:"metaTxHash"` +} + type TransactionRaw struct { Type string `json:"type"` To string `json:"to"` @@ -177,6 +236,29 @@ type IntentResponseSignedMessage struct { Message string `json:"message"` } +type FeeOption struct { + Token *FeeToken `json:"token"` + To string `json:"to"` + Value string `json:"value"` + GasLimit uint `json:"gasLimit"` +} + +type FeeToken struct { + ChainId uint64 `json:"chainId"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type FeeTokenType `json:"type"` + Decimals *uint32 `json:"decimals"` + LogoURL string `json:"logoURL"` + ContractAddress *string `json:"contractAddress"` + TokenID *string `json:"tokenID"` +} + +type IntentResponseFeeOptions struct { + FeeOptions []*FeeOption `json:"feeOptions"` + FeeQuote *string `json:"feeQuote,omitempty"` +} + type IntentResponseTransactionReceipt struct { Request interface{} `json:"request"` TxHash string `json:"txHash"` @@ -251,6 +333,9 @@ func (e WebRPCError) Error() string { } func (e WebRPCError) Is(target error) bool { + if target == nil { + return false + } if rpcErr, ok := target.(WebRPCError); ok { return rpcErr.Code == e.Code } diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.ts b/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.ts index 67ff992d..f1252044 100644 --- a/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.ts +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent.gen.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -// sequence-waas-intents v0.1.0 e8e022f41dd9c03ff373c616d8f484fbefdfe7d9 +// sequence-waas-intents v0.1.0 2c4dea0eacfd30c622628970fba756e9f4a21e61 // -- -// Code generated by webrpc-gen@v0.14.0-dev with typescript generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.15.0-dev with typescript generator. DO NOT EDIT. // // webrpc-gen -schema=intent.ridl -target=typescript -client -out=./intent.gen.ts @@ -12,13 +12,19 @@ export const WebRPCVersion = "v1" export const WebRPCSchemaVersion = "v0.1.0" // Schema hash generated from your RIDL schema -export const WebRPCSchemaHash = "e8e022f41dd9c03ff373c616d8f484fbefdfe7d9" +export const WebRPCSchemaHash = "2c4dea0eacfd30c622628970fba756e9f4a21e61" // // Types // +export enum FeeTokenType { + unknown = 'unknown', + erc20Token = 'erc20Token', + erc1155Token = 'erc1155Token' +} + export interface Intent { version: string name: string @@ -71,11 +77,25 @@ export interface IntentDataSignMessage { message: string } +export interface IntentDataFeeOptions { + network: string + wallet: string + identifier: string + transactions: Array +} + export interface IntentDataSendTransaction { network: string wallet: string identifier: string transactions: Array + transactionsFeeQuote?: string +} + +export interface IntentDataGetTransactionReceipt { + network: string + wallet: string + metaTxHash: string } export interface TransactionRaw { @@ -164,6 +184,29 @@ export interface IntentResponseSignedMessage { message: string } +export interface FeeOption { + token: FeeToken + to: string + value: string + gasLimit: number +} + +export interface FeeToken { + chainId: number + name: string + symbol: string + type: FeeTokenType + decimals?: number + logoURL: string + contractAddress?: string + tokenID?: string +} + +export interface IntentResponseFeeOptions { + feeOptions: Array + feeQuote?: string +} + export interface IntentResponseTransactionReceipt { request: any txHash: string diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent.ridl b/vendor/github.com/0xsequence/go-sequence/intents/intent.ridl index b00796c4..2e650452 100644 --- a/vendor/github.com/0xsequence/go-sequence/intents/intent.ridl +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent.ridl @@ -27,6 +27,7 @@ struct Signature # - getSession # - signMessage # - sendTransaction +# - getTransactionReceipt struct IntentDataOpenSession - sessionId: string @@ -56,7 +57,6 @@ struct IntentDataFinishValidateSession struct IntentDataListSessions - wallet: string - struct IntentDataGetSession - sessionId: string + go.field.name = SessionID @@ -67,12 +67,26 @@ struct IntentDataSignMessage - wallet: string - message: string +struct IntentDataFeeOptions + - network: string + - wallet: string + - identifier: string # is used to generate nonce space + - transactions: []any + + go.field.type = []json.RawMessage + struct IntentDataSendTransaction - network: string - wallet: string - identifier: string # is used to generate nonce space - transactions: []any + go.field.type = []json.RawMessage + - transactionsFeeQuote?: string + + go.tag.json = transactionsFeeQuote,omitempty + +struct IntentDataGetTransactionReceipt + - network: string + - wallet: string + - metaTxHash: string struct TransactionRaw - type: string @@ -168,6 +182,32 @@ struct IntentResponseSignedMessage - signature: string - message: string +struct FeeOption + - token: FeeToken + - to: string + - value: string + - gasLimit: uint + +struct FeeToken + - chainId: uint64 + - name: string + - symbol: string + - type: FeeTokenType + - decimals?: uint32 + - logoURL: string + - contractAddress?: string + - tokenID?: string + +enum FeeTokenType: uint32 + - unknown + - erc20Token + - erc1155Token + +struct IntentResponseFeeOptions + - feeOptions: []FeeOption + - feeQuote?: string + + go.tag.json = feeQuote,omitempty + struct IntentResponseTransactionReceipt - request: any - txHash: string diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent_data_get_transaction_receipt_ext.go b/vendor/github.com/0xsequence/go-sequence/intents/intent_data_get_transaction_receipt_ext.go new file mode 100644 index 00000000..321884c2 --- /dev/null +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent_data_get_transaction_receipt_ext.go @@ -0,0 +1,23 @@ +package intents + +import ( + "fmt" + "math/big" + + "github.com/0xsequence/ethkit/go-ethereum/common" + + "github.com/0xsequence/go-sequence" +) + +func (p *IntentDataGetTransactionReceipt) chainID() (*big.Int, error) { + n, ok := sequence.ParseHexOrDec(p.Network) + if !ok { + return nil, fmt.Errorf("invalid network id '%s'", p.Network) + } + + return n, nil +} + +func (p *IntentDataGetTransactionReceipt) wallet() common.Address { + return common.HexToAddress(p.Wallet) +} diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent_ext.go b/vendor/github.com/0xsequence/go-sequence/intents/intent_ext.go index 6e2fac10..c5f0314e 100644 --- a/vendor/github.com/0xsequence/go-sequence/intents/intent_ext.go +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent_ext.go @@ -19,7 +19,9 @@ const ( IntentNameListSessions = "listSessions" IntentNameGetSession = "getSession" IntentNameSignMessage = "signMessage" + IntentNameFeeOptions = "feeOptions" IntentNameSendTransaction = "sendTransaction" + IntentNameGetTransactionReceipt = "getTransactionReceipt" ) const ( @@ -28,6 +30,7 @@ const ( IntentResponseCodeValidationStarted = "validationStarted" IntentResponseCodeValidationFinished = "validationFinished" IntentResponseCodeSignedMessage = "signedMessage" + IntentResponseCodeFeeOptions = "feeOptions" IntentResponseCodeTransactionReceipt = "transactionReceipt" IntentResponseCodeTransactionFailed = "transactionFailed" IntentResponseCodeGetSessionResponse = "getSessionResponse" diff --git a/vendor/github.com/0xsequence/go-sequence/intents/intent_typed.go b/vendor/github.com/0xsequence/go-sequence/intents/intent_typed.go index 2369bb0e..8617ce83 100644 --- a/vendor/github.com/0xsequence/go-sequence/intents/intent_typed.go +++ b/vendor/github.com/0xsequence/go-sequence/intents/intent_typed.go @@ -23,8 +23,12 @@ func IntentDataTypeToName[T any](t *T) string { return IntentNameGetSession case *IntentDataSignMessage: return IntentNameSignMessage + case *IntentDataFeeOptions: + return IntentNameFeeOptions case *IntentDataSendTransaction: return IntentNameSendTransaction + case *IntentDataGetTransactionReceipt: + return IntentNameGetTransactionReceipt default: return "" } diff --git a/vendor/github.com/0xsequence/go-sequence/relayer.go b/vendor/github.com/0xsequence/go-sequence/relayer.go index 75832dec..19211c01 100644 --- a/vendor/github.com/0xsequence/go-sequence/relayer.go +++ b/vendor/github.com/0xsequence/go-sequence/relayer.go @@ -27,6 +27,34 @@ type RelayerSimulateResult struct { GasLimit uint } +type RelayerFeeTokenType uint32 + +const ( + UNKNOWN RelayerFeeTokenType = iota + ERC20_TOKEN + ERC1155_TOKEN +) + +type RelayerFeeToken struct { + ChainID *big.Int + Name string + Symbol string + Type RelayerFeeTokenType + Decimals *uint32 + LogoURL string + ContractAddress *common.Address + TokenID *big.Int +} + +type RelayerFeeOption struct { + Token RelayerFeeToken + To common.Address + Value *big.Int + GasLimit *big.Int +} + +type RelayerFeeQuote string + type Relayer interface { // .. GetProvider() *ethrpc.Provider @@ -43,7 +71,10 @@ type Relayer interface { // Relay will submit the Sequence signed meta transaction to the relayer. The method will block until the relayer // responds with the native transaction hash (*types.Transaction), which means the relayer has submitted the transaction // request to the network. Clients can use WaitReceipt to wait until the metaTxnID has been mined. - Relay(ctx context.Context, signedTxs *SignedTransactions) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) + Relay(ctx context.Context, signedTxs *SignedTransactions, quote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) + + // + FeeOptions(ctx context.Context, signedTxs *SignedTransactions) ([]*RelayerFeeOption, *RelayerFeeQuote, error) // .. Wait(ctx context.Context, metaTxnID MetaTxnID, optTimeout ...time.Duration) (MetaTxnStatus, *types.Receipt, error) diff --git a/vendor/github.com/0xsequence/go-sequence/relayer/proto/relayer.gen.go b/vendor/github.com/0xsequence/go-sequence/relayer/proto/relayer.gen.go index e69e48a7..e163db8a 100644 --- a/vendor/github.com/0xsequence/go-sequence/relayer/proto/relayer.gen.go +++ b/vendor/github.com/0xsequence/go-sequence/relayer/proto/relayer.gen.go @@ -1,7 +1,8 @@ -// sequence-relayer v0.4.0 59a862f763edcaca2fb2e11901b24873c4c02034 +// sequence-relayer v0.4.0 876833b8b84f37adc43adf71fb80404e604fb67c // -- -// This file has been generated by https://github.com/webrpc/webrpc using gen/golang -// Do not edit by hand. Update your webrpc schema and re-generate. +// Code generated by webrpc-gen@v0.12.x-dev with golang@v0.10.0 generator. DO NOT EDIT. +// +// webrpc-gen -schema=relayer.ridl -target=golang@v0.10.0 -pkg=proto -client -out=./clients/relayer.gen.go package proto import ( @@ -17,6 +18,7 @@ import ( "time" "github.com/0xsequence/go-sequence/lib/prototyp" + "github.com/shopspring/decimal" ) // WebRPC description and code-gen version @@ -31,7 +33,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "59a862f763edcaca2fb2e11901b24873c4c02034" + return "876833b8b84f37adc43adf71fb80404e604fb67c" } // @@ -228,25 +230,33 @@ type Version struct { } type RuntimeStatus struct { - HealthOK bool `json:"healthOK"` - StartTime time.Time `json:"startTime"` - Uptime uint64 `json:"uptime"` - Ver string `json:"ver"` - Branch string `json:"branch"` - CommitHash string `json:"commitHash"` - Senders []*SenderStatus `json:"senders"` - Checks *RuntimeChecks `json:"checks"` + HealthOK bool `json:"healthOK"` + StartTime time.Time `json:"startTime"` + Uptime uint64 `json:"uptime"` + Ver string `json:"ver"` + Branch string `json:"branch"` + CommitHash string `json:"commitHash"` + Senders []*SenderStatus `json:"senders"` + Checks *RuntimeChecks `json:"checks"` + NumTxnsRelayed *NumTxnsRelayed `json:"numTxnsRelayed"` } type SenderStatus struct { - Index uint32 `json:"index"` - Address string `json:"address"` - Active bool `json:"active"` + Index uint32 `json:"index"` + Address string `json:"address"` + EtherBalance float64 `json:"etherBalance"` + Active bool `json:"active"` } type RuntimeChecks struct { } +type NumTxnsRelayed struct { + Prev uint64 `json:"prev"` + Current uint64 `json:"current"` + Period uint64 `json:"period"` +} + type SequenceContext struct { Factory string `json:"factory"` MainModule string `json:"mainModule"` @@ -255,16 +265,46 @@ type SequenceContext struct { Utils string `json:"utils"` } -type WalletConfig struct { - Address string `json:"address"` - Signers []*WalletSigner `json:"signers"` - Threshold uint16 `json:"threshold"` - ChainId *uint64 `json:"chainId"` -} - -type WalletSigner struct { - Address string `json:"address"` - Weight uint8 `json:"weight"` +type GasTank struct { + ID uint64 `json:"id" db:"id,omitempty"` + Name string `json:"name" db:"name"` + CurrentBalance decimal.Decimal `json:"currentBalance" db:"current_balance"` + Unlimited bool `json:"unlimited" db:"unlimited"` + FeeMarkupFactor decimal.Decimal `json:"feeMarkupFactor" db:"fee_markup_factor"` + UpdatedAt *time.Time `json:"updatedAt" db:"updated_at,omitempty"` + CreatedAt *time.Time `json:"createdAt" db:"created_at,omitempty"` +} + +type GasTankBalanceAdjustment struct { + GasTankID uint64 `json:"gasTankId" db:"gas_tank_id"` + Nonce uint64 `json:"nonce" db:"nonce"` + Amount decimal.Decimal `json:"amount" db:"amount"` + TotalBalance decimal.Decimal `json:"totalBalance" db:"total_balance"` + BalanceTimestamp time.Time `json:"balanceTimestamp" db:"balance_timestamp"` + CreatedAt *time.Time `json:"createdAt" db:"created_at,omitempty"` +} + +type GasSponsor struct { + ID uint64 `json:"id" db:"id,omitempty"` + GasTankID uint64 `json:"gasTankId" db:"gas_tank_id"` + Address prototyp.Hash `json:"address" db:"address"` + Name string `json:"name" db:"name"` + Active bool `json:"active" db:"active"` + UpdatedAt *time.Time `json:"updatedAt" db:"updated_at,omitempty"` + CreatedAt *time.Time `json:"createdAt" db:"created_at,omitempty"` + DeletedAt *time.Time `json:"-" db:"deleted_at,omitempty"` +} + +type GasSponsorUsage struct { + Name string `json:"name" db:"name"` + ID uint64 `json:"id" db:"gas_sponsor_id,omitempty"` + TotalGasUsed int64 `json:"totalGasUsed" db:"total_gas_used"` + TotalTxnFees float64 `json:"totalTxnFees" db:"total_txn_fees"` + TotalTxnFeesUSD decimal.Decimal `json:"totalTxnFeesUsd" db:"total_txn_fees_usd"` + AvgGasPrice float64 `json:"avgGasPrice" db:"avg_gas_price"` + TotalTxns int64 `json:"totalTxns" db:"total_txns"` + StartTime *time.Time `json:"startTime"` + EndTime *time.Time `json:"endTime"` } type MetaTxn struct { @@ -280,6 +320,10 @@ type MetaTxnLog struct { MetaTxnID *string `json:"metaTxnID" db:"meta_txn_id"` TxnStatus ETHTxnStatus `json:"txnStatus" db:"txn_status"` TxnRevertReason string `json:"txnRevertReason" db:"txn_revert_reason"` + Requeues uint `json:"requeues" db:"requeues"` + QueuedAt *time.Time `json:"queuedAt" db:"queued_at,omitempty"` + SentAt *time.Time `json:"sentAt" db:"sent_at,omitempty"` + MinedAt *time.Time `json:"minedAt" db:"mined_at,omitempty"` Target prototyp.Hash `json:"target" db:"target"` Input prototyp.Hash `json:"input" db:"input"` TxnArgs map[string]interface{} `json:"txnArgs" db:"txn_args"` @@ -289,6 +333,12 @@ type MetaTxnLog struct { GasLimit uint64 `json:"gasLimit" db:"gas_limit"` GasPrice prototyp.BigInt `json:"gasPrice" db:"gas_price"` GasUsed uint64 `json:"gasUsed" db:"gas_used"` + GasEstimated uint64 `json:"gasEstimated" db:"gas_estimated"` + GasFeeMarkup *uint64 `json:"gasFeeMarkup" db:"gas_fee_markup"` + UsdRate prototyp.BigInt `json:"usdRate" db:"usd_rate"` + IsWhitelisted bool `json:"isWhitelisted" db:"is_whitelisted,omitempty"` + GasSponsor *uint64 `json:"gasSponsor" db:"gas_sponsor_id,omitempty"` + GasTank *uint64 `json:"gasTank" db:"gas_tank_id,omitempty"` UpdatedAt *time.Time `json:"updatedAt" db:"updated_at,omitempty"` CreatedAt *time.Time `json:"createdAt" db:"created_at,omitempty"` } @@ -372,7 +422,6 @@ type FeeToken struct { Decimals *uint32 `json:"decimals"` LogoURL string `json:"logoURL"` ContractAddress *string `json:"contractAddress"` - OriginAddress *string `json:"originAddress"` TokenID *string `json:"tokenID"` } @@ -397,15 +446,29 @@ type Relayer interface { RuntimeStatus(ctx context.Context) (*RuntimeStatus, error) GetSequenceContext(ctx context.Context) (*SequenceContext, error) GetChainID(ctx context.Context) (uint64, error) - SendMetaTxn(ctx context.Context, call *MetaTxn) (bool, string, error) + SendMetaTxn(ctx context.Context, call *MetaTxn, quote *string) (bool, string, error) GetMetaTxnNonce(ctx context.Context, walletContractAddress string, space *string) (string, error) GetMetaTxnReceipt(ctx context.Context, metaTxID string) (*MetaTxnReceipt, error) - UpdateMetaTxnGasLimits(ctx context.Context, walletAddress string, walletConfig *WalletConfig, payload string) (string, error) + Simulate(ctx context.Context, wallet string, transactions string) ([]*SimulateResult, error) + UpdateMetaTxnGasLimits(ctx context.Context, walletAddress string, walletConfig interface{}, payload string) (string, error) FeeTokens(ctx context.Context) (bool, []*FeeToken, error) - GetMetaTxnNetworkFeeOptions(ctx context.Context, walletConfig *WalletConfig, payload string) ([]*FeeOption, error) + FeeOptions(ctx context.Context, wallet string, to string, data string, simulate *bool) ([]*FeeOption, bool, *string, error) + GetMetaTxnNetworkFeeOptions(ctx context.Context, walletConfig interface{}, payload string) ([]*FeeOption, error) SentTransactions(ctx context.Context, filter *SentTransactionsFilter, page *Page) (*Page, []*Transaction, error) PendingTransactions(ctx context.Context, page *Page) (*Page, []*Transaction, error) - Simulate(ctx context.Context, wallet string, transactions string) ([]*SimulateResult, error) + GetGasTank(ctx context.Context, id uint64) (*GasTank, error) + AddGasTank(ctx context.Context, name string, feeMarkupFactor float64, unlimited *bool) (bool, *GasTank, error) + UpdateGasTank(ctx context.Context, id uint64, name *string, feeMarkupFactor *float64, unlimited *bool) (bool, *GasTank, error) + GetGasSponsor(ctx context.Context, id uint64) (*GasSponsor, error) + ListGasSponsors(ctx context.Context, gasTankId uint64, page *Page) (*Page, []*GasSponsor, error) + AddGasSponsor(ctx context.Context, gasTankId uint64, address string, name *string, active *bool) (bool, *GasSponsor, error) + UpdateGasSponsor(ctx context.Context, id uint64, name *string, active *bool) (bool, *GasSponsor, error) + RemoveGasSponsor(ctx context.Context, id uint64) (bool, error) + ReportGasSponsorUsage(ctx context.Context, gasTankId uint64, startTime *time.Time, endTime *time.Time) ([]*GasSponsorUsage, error) + NextGasTankBalanceAdjustmentNonce(ctx context.Context, id uint64) (uint64, error) + AdjustGasTankBalance(ctx context.Context, id uint64, nonce uint64, amount float64) (bool, *GasTankBalanceAdjustment, error) + GetGasTankBalanceAdjustment(ctx context.Context, id uint64, nonce uint64) (*GasTankBalanceAdjustment, error) + ListGasTankBalanceAdjustments(ctx context.Context, id uint64, page *Page) (*Page, []*GasTankBalanceAdjustment, error) } var WebRPCServices = map[string][]string{ @@ -418,12 +481,26 @@ var WebRPCServices = map[string][]string{ "SendMetaTxn", "GetMetaTxnNonce", "GetMetaTxnReceipt", + "Simulate", "UpdateMetaTxnGasLimits", "FeeTokens", + "FeeOptions", "GetMetaTxnNetworkFeeOptions", "SentTransactions", "PendingTransactions", - "SimulateResult", + "GetGasTank", + "AddGasTank", + "UpdateGasTank", + "GetGasSponsor", + "ListGasSponsors", + "AddGasSponsor", + "UpdateGasSponsor", + "RemoveGasSponsor", + "ReportGasSponsorUsage", + "NextGasTankBalanceAdjustmentNonce", + "AdjustGasTankBalance", + "GetGasTankBalanceAdjustment", + "ListGasTankBalanceAdjustments", }, } @@ -435,12 +512,12 @@ const RelayerPathPrefix = "/rpc/Relayer/" type relayerClient struct { client HTTPClient - urls [14]string + urls [28]string } func NewRelayerClient(addr string, client HTTPClient) Relayer { prefix := urlBase(addr) + RelayerPathPrefix - urls := [14]string{ + urls := [28]string{ prefix + "Ping", prefix + "Version", prefix + "RuntimeStatus", @@ -449,12 +526,26 @@ func NewRelayerClient(addr string, client HTTPClient) Relayer { prefix + "SendMetaTxn", prefix + "GetMetaTxnNonce", prefix + "GetMetaTxnReceipt", + prefix + "Simulate", prefix + "UpdateMetaTxnGasLimits", prefix + "FeeTokens", + prefix + "FeeOptions", prefix + "GetMetaTxnNetworkFeeOptions", prefix + "SentTransactions", prefix + "PendingTransactions", - prefix + "Simulate", + prefix + "GetGasTank", + prefix + "AddGasTank", + prefix + "UpdateGasTank", + prefix + "GetGasSponsor", + prefix + "ListGasSponsors", + prefix + "AddGasSponsor", + prefix + "UpdateGasSponsor", + prefix + "RemoveGasSponsor", + prefix + "ReportGasSponsorUsage", + prefix + "NextGasTankBalanceAdjustmentNonce", + prefix + "AdjustGasTankBalance", + prefix + "GetGasTankBalanceAdjustment", + prefix + "ListGasTankBalanceAdjustments", } return &relayerClient{ client: client, @@ -507,10 +598,11 @@ func (c *relayerClient) GetChainID(ctx context.Context) (uint64, error) { return out.Ret0, err } -func (c *relayerClient) SendMetaTxn(ctx context.Context, call *MetaTxn) (bool, string, error) { +func (c *relayerClient) SendMetaTxn(ctx context.Context, call *MetaTxn, quote *string) (bool, string, error) { in := struct { Arg0 *MetaTxn `json:"call"` - }{call} + Arg1 *string `json:"quote"` + }{call, quote} out := struct { Ret0 bool `json:"status"` Ret1 string `json:"txnHash"` @@ -545,17 +637,30 @@ func (c *relayerClient) GetMetaTxnReceipt(ctx context.Context, metaTxID string) return out.Ret0, err } -func (c *relayerClient) UpdateMetaTxnGasLimits(ctx context.Context, walletAddress string, walletConfig *WalletConfig, payload string) (string, error) { +func (c *relayerClient) Simulate(ctx context.Context, wallet string, transactions string) ([]*SimulateResult, error) { + in := struct { + Arg0 string `json:"wallet"` + Arg1 string `json:"transactions"` + }{wallet, transactions} + out := struct { + Ret0 []*SimulateResult `json:"results"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[8], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) UpdateMetaTxnGasLimits(ctx context.Context, walletAddress string, walletConfig interface{}, payload string) (string, error) { in := struct { - Arg0 string `json:"walletAddress"` - Arg1 *WalletConfig `json:"walletConfig"` - Arg2 string `json:"payload"` + Arg0 string `json:"walletAddress"` + Arg1 interface{} `json:"walletConfig"` + Arg2 string `json:"payload"` }{walletAddress, walletConfig, payload} out := struct { Ret0 string `json:"payload"` }{} - err := doJSONRequest(ctx, c.client, c.urls[8], in, &out) + err := doJSONRequest(ctx, c.client, c.urls[9], in, &out) return out.Ret0, err } @@ -565,20 +670,37 @@ func (c *relayerClient) FeeTokens(ctx context.Context) (bool, []*FeeToken, error Ret1 []*FeeToken `json:"tokens"` }{} - err := doJSONRequest(ctx, c.client, c.urls[9], nil, &out) + err := doJSONRequest(ctx, c.client, c.urls[10], nil, &out) return out.Ret0, out.Ret1, err } -func (c *relayerClient) GetMetaTxnNetworkFeeOptions(ctx context.Context, walletConfig *WalletConfig, payload string) ([]*FeeOption, error) { +func (c *relayerClient) FeeOptions(ctx context.Context, wallet string, to string, data string, simulate *bool) ([]*FeeOption, bool, *string, error) { + in := struct { + Arg0 string `json:"wallet"` + Arg1 string `json:"to"` + Arg2 string `json:"data"` + Arg3 *bool `json:"simulate"` + }{wallet, to, data, simulate} + out := struct { + Ret0 []*FeeOption `json:"options"` + Ret1 bool `json:"sponsored"` + Ret2 *string `json:"quote"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[11], in, &out) + return out.Ret0, out.Ret1, out.Ret2, err +} + +func (c *relayerClient) GetMetaTxnNetworkFeeOptions(ctx context.Context, walletConfig interface{}, payload string) ([]*FeeOption, error) { in := struct { - Arg0 *WalletConfig `json:"walletConfig"` - Arg1 string `json:"payload"` + Arg0 interface{} `json:"walletConfig"` + Arg1 string `json:"payload"` }{walletConfig, payload} out := struct { Ret0 []*FeeOption `json:"options"` }{} - err := doJSONRequest(ctx, c.client, c.urls[10], in, &out) + err := doJSONRequest(ctx, c.client, c.urls[12], in, &out) return out.Ret0, err } @@ -592,7 +714,7 @@ func (c *relayerClient) SentTransactions(ctx context.Context, filter *SentTransa Ret1 []*Transaction `json:"transactions"` }{} - err := doJSONRequest(ctx, c.client, c.urls[11], in, &out) + err := doJSONRequest(ctx, c.client, c.urls[13], in, &out) return out.Ret0, out.Ret1, err } @@ -605,23 +727,190 @@ func (c *relayerClient) PendingTransactions(ctx context.Context, page *Page) (*P Ret1 []*Transaction `json:"transactions"` }{} - err := doJSONRequest(ctx, c.client, c.urls[12], in, &out) + err := doJSONRequest(ctx, c.client, c.urls[14], in, &out) return out.Ret0, out.Ret1, err } -func (c *relayerClient) Simulate(ctx context.Context, wallet string, transactions string) ([]*SimulateResult, error) { +func (c *relayerClient) GetGasTank(ctx context.Context, id uint64) (*GasTank, error) { in := struct { - Arg0 string `json:"wallet"` - Arg1 string `json:"transactions"` - }{wallet, transactions} + Arg0 uint64 `json:"id"` + }{id} out := struct { - Ret0 []*SimulateResult `json:"results"` + Ret0 *GasTank `json:"gasTank"` }{} - err := doJSONRequest(ctx, c.client, c.urls[13], in, &out) + err := doJSONRequest(ctx, c.client, c.urls[15], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) AddGasTank(ctx context.Context, name string, feeMarkupFactor float64, unlimited *bool) (bool, *GasTank, error) { + in := struct { + Arg0 string `json:"name"` + Arg1 float64 `json:"feeMarkupFactor"` + Arg2 *bool `json:"unlimited"` + }{name, feeMarkupFactor, unlimited} + out := struct { + Ret0 bool `json:"status"` + Ret1 *GasTank `json:"gasTank"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[16], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) UpdateGasTank(ctx context.Context, id uint64, name *string, feeMarkupFactor *float64, unlimited *bool) (bool, *GasTank, error) { + in := struct { + Arg0 uint64 `json:"id"` + Arg1 *string `json:"name"` + Arg2 *float64 `json:"feeMarkupFactor"` + Arg3 *bool `json:"unlimited"` + }{id, name, feeMarkupFactor, unlimited} + out := struct { + Ret0 bool `json:"status"` + Ret1 *GasTank `json:"gasTank"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[17], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) GetGasSponsor(ctx context.Context, id uint64) (*GasSponsor, error) { + in := struct { + Arg0 uint64 `json:"id"` + }{id} + out := struct { + Ret0 *GasSponsor `json:"gasSponsor"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[18], in, &out) return out.Ret0, err } +func (c *relayerClient) ListGasSponsors(ctx context.Context, gasTankId uint64, page *Page) (*Page, []*GasSponsor, error) { + in := struct { + Arg0 uint64 `json:"gasTankId"` + Arg1 *Page `json:"page"` + }{gasTankId, page} + out := struct { + Ret0 *Page `json:"page"` + Ret1 []*GasSponsor `json:"gasSponsors"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[19], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) AddGasSponsor(ctx context.Context, gasTankId uint64, address string, name *string, active *bool) (bool, *GasSponsor, error) { + in := struct { + Arg0 uint64 `json:"gasTankId"` + Arg1 string `json:"address"` + Arg2 *string `json:"name"` + Arg3 *bool `json:"active"` + }{gasTankId, address, name, active} + out := struct { + Ret0 bool `json:"status"` + Ret1 *GasSponsor `json:"gasSponsor"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[20], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) UpdateGasSponsor(ctx context.Context, id uint64, name *string, active *bool) (bool, *GasSponsor, error) { + in := struct { + Arg0 uint64 `json:"id"` + Arg1 *string `json:"name"` + Arg2 *bool `json:"active"` + }{id, name, active} + out := struct { + Ret0 bool `json:"status"` + Ret1 *GasSponsor `json:"gasSponsor"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[21], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) RemoveGasSponsor(ctx context.Context, id uint64) (bool, error) { + in := struct { + Arg0 uint64 `json:"id"` + }{id} + out := struct { + Ret0 bool `json:"status"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[22], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) ReportGasSponsorUsage(ctx context.Context, gasTankId uint64, startTime *time.Time, endTime *time.Time) ([]*GasSponsorUsage, error) { + in := struct { + Arg0 uint64 `json:"gasTankId"` + Arg1 *time.Time `json:"startTime"` + Arg2 *time.Time `json:"endTime"` + }{gasTankId, startTime, endTime} + out := struct { + Ret0 []*GasSponsorUsage `json:"gasSponsorUsage"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[23], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) NextGasTankBalanceAdjustmentNonce(ctx context.Context, id uint64) (uint64, error) { + in := struct { + Arg0 uint64 `json:"id"` + }{id} + out := struct { + Ret0 uint64 `json:"nonce"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[24], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) AdjustGasTankBalance(ctx context.Context, id uint64, nonce uint64, amount float64) (bool, *GasTankBalanceAdjustment, error) { + in := struct { + Arg0 uint64 `json:"id"` + Arg1 uint64 `json:"nonce"` + Arg2 float64 `json:"amount"` + }{id, nonce, amount} + out := struct { + Ret0 bool `json:"status"` + Ret1 *GasTankBalanceAdjustment `json:"adjustment"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[25], in, &out) + return out.Ret0, out.Ret1, err +} + +func (c *relayerClient) GetGasTankBalanceAdjustment(ctx context.Context, id uint64, nonce uint64) (*GasTankBalanceAdjustment, error) { + in := struct { + Arg0 uint64 `json:"id"` + Arg1 uint64 `json:"nonce"` + }{id, nonce} + out := struct { + Ret0 *GasTankBalanceAdjustment `json:"adjustment"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[26], in, &out) + return out.Ret0, err +} + +func (c *relayerClient) ListGasTankBalanceAdjustments(ctx context.Context, id uint64, page *Page) (*Page, []*GasTankBalanceAdjustment, error) { + in := struct { + Arg0 uint64 `json:"id"` + Arg1 *Page `json:"page"` + }{id, page} + out := struct { + Ret0 *Page `json:"page"` + Ret1 []*GasTankBalanceAdjustment `json:"adjustments"` + }{} + + err := doJSONRequest(ctx, c.client, c.urls[27], in, &out) + return out.Ret0, out.Ret1, err +} + // HTTPClient is the interface used by generated clients to send HTTP requests. // It is fulfilled by *(net/http).Client, which is sufficient for most users. // Users can provide their own implementation for special retry policies. diff --git a/vendor/github.com/0xsequence/go-sequence/wallet.go b/vendor/github.com/0xsequence/go-sequence/wallet.go index 971ba056..42d61202 100644 --- a/vendor/github.com/0xsequence/go-sequence/wallet.go +++ b/vendor/github.com/0xsequence/go-sequence/wallet.go @@ -67,6 +67,7 @@ func GenericNewWallet[C core.WalletConfig](walletOptions WalletOptions[C], signe config: walletOptions.Config, context: seqContext, address: address, + estimator: NewEstimator(), skipSortSigners: walletOptions.SkipSortSigners, } w.signers = signers @@ -198,10 +199,11 @@ type Wallet[C core.WalletConfig] struct { config C signers []Signer - provider *ethrpc.Provider - relayer Relayer - sessions proto.Sessions - address common.Address + provider *ethrpc.Provider + estimator *Estimator + relayer Relayer + sessions proto.Sessions + address common.Address skipSortSigners bool @@ -575,15 +577,74 @@ func (w *Wallet[C]) SignTransactions(ctx context.Context, txns Transactions) (*S }, nil } -func (w *Wallet[C]) SendTransaction(ctx context.Context, signedTxns *SignedTransactions) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) { - return w.SendTransactions(ctx, signedTxns) +func (w *Wallet[C]) SendTransaction(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) { + return w.SendTransactions(ctx, signedTxns, feeQuote...) } -func (w *Wallet[C]) SendTransactions(ctx context.Context, signedTxns *SignedTransactions) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) { +func (w *Wallet[C]) SendTransactions(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) { if w.relayer == nil { return "", nil, nil, ErrRelayerNotSet } - return w.relayer.Relay(ctx, signedTxns) + + return w.relayer.Relay(ctx, signedTxns, feeQuote...) +} + +func (w *Wallet[C]) FeeOptions(ctx context.Context, txs Transactions) ([]*RelayerFeeOption, *RelayerFeeQuote, error) { + if w.relayer == nil { + return []*RelayerFeeOption{}, nil, ErrRelayerNotSet + } + + // prepare for signed txs + nonce, err := txs.Nonce() + if err != nil { + return nil, nil, fmt.Errorf("cannot load nonce from transactions: %w", err) + } + + if nonce == nil { + nonce, err = w.GetNonce() + if err != nil { + return nil, nil, err + } + } + + bundle := Transaction{ + Transactions: txs, + Nonce: nonce, + } + + // get transactions digest + digest, err := bundle.Digest() + if err != nil { + return nil, nil, fmt.Errorf("cannot get digest from transactions: %w", err) + } + + // prepare for fee estimation + areEOAs, err := w.estimator.AreEOAs(ctx, w.provider, w.config) + if err != nil { + return nil, nil, fmt.Errorf("estimator areEOAs error: %w", err) + } + + willSign, err := w.estimator.PickSigners(ctx, w.config, areEOAs) + if err != nil { + return nil, nil, fmt.Errorf("estimator pickSigners error: %w", err) + } + + sig := w.estimator.BuildStubSignature(w.config, willSign, areEOAs) + + // signed txs + signedTxs := &SignedTransactions{ + ChainID: w.chainID, + WalletAddress: w.address, + WalletConfig: w.config, + WalletContext: w.context, + Transactions: txs, + Nonce: nonce, + Digest: digest, + Signature: sig, + } + + // get fee options + return w.relayer.FeeOptions(ctx, signedTxs) } func (w *Wallet[C]) IsDeployed() (bool, error) { diff --git a/vendor/github.com/shopspring/decimal/.gitignore b/vendor/github.com/shopspring/decimal/.gitignore new file mode 100644 index 00000000..ff36b987 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/.gitignore @@ -0,0 +1,9 @@ +.git +*.swp + +# IntelliJ +.idea/ +*.iml + +# VS code +*.code-workspace diff --git a/vendor/github.com/shopspring/decimal/.travis.yml b/vendor/github.com/shopspring/decimal/.travis.yml new file mode 100644 index 00000000..6326d40f --- /dev/null +++ b/vendor/github.com/shopspring/decimal/.travis.yml @@ -0,0 +1,19 @@ +language: go + +arch: + - amd64 + - ppc64le + +go: + - 1.7.x + - 1.14.x + - 1.15.x + - 1.16.x + - 1.17.x + - tip + +install: + - go build . + +script: + - go test -v diff --git a/vendor/github.com/shopspring/decimal/CHANGELOG.md b/vendor/github.com/shopspring/decimal/CHANGELOG.md new file mode 100644 index 00000000..aea61154 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/CHANGELOG.md @@ -0,0 +1,49 @@ +## Decimal v1.3.1 + +#### ENHANCEMENTS +- Reduce memory allocation in case of initialization from big.Int [#252](https://github.com/shopspring/decimal/pull/252) + +#### BUGFIXES +- Fix binary marshalling of decimal zero value [#253](https://github.com/shopspring/decimal/pull/253) + +## Decimal v1.3.0 + +#### FEATURES +- Add NewFromFormattedString initializer [#184](https://github.com/shopspring/decimal/pull/184) +- Add NewNullDecimal initializer [#234](https://github.com/shopspring/decimal/pull/234) +- Add implementation of natural exponent function (Taylor, Hull-Abraham) [#229](https://github.com/shopspring/decimal/pull/229) +- Add RoundUp, RoundDown, RoundCeil, RoundFloor methods [#196](https://github.com/shopspring/decimal/pull/196) [#202](https://github.com/shopspring/decimal/pull/202) [#220](https://github.com/shopspring/decimal/pull/220) +- Add XML support for NullDecimal [#192](https://github.com/shopspring/decimal/pull/192) +- Add IsInteger method [#179](https://github.com/shopspring/decimal/pull/179) +- Add Copy helper method [#123](https://github.com/shopspring/decimal/pull/123) +- Add InexactFloat64 helper method [#205](https://github.com/shopspring/decimal/pull/205) +- Add CoefficientInt64 helper method [#244](https://github.com/shopspring/decimal/pull/244) + +#### ENHANCEMENTS +- Performance optimization of NewFromString init method [#198](https://github.com/shopspring/decimal/pull/198) +- Performance optimization of Abs and Round methods [#240](https://github.com/shopspring/decimal/pull/240) +- Additional tests (CI) for ppc64le architecture [#188](https://github.com/shopspring/decimal/pull/188) + +#### BUGFIXES +- Fix rounding in FormatFloat fallback path (roundShortest method, fix taken from Go main repository) [#161](https://github.com/shopspring/decimal/pull/161) +- Add slice range checks to UnmarshalBinary method [#232](https://github.com/shopspring/decimal/pull/232) + +## Decimal v1.2.0 + +#### BREAKING +- Drop support for Go version older than 1.7 [#172](https://github.com/shopspring/decimal/pull/172) + +#### FEATURES +- Add NewFromInt and NewFromInt32 initializers [#72](https://github.com/shopspring/decimal/pull/72) +- Add support for Go modules [#157](https://github.com/shopspring/decimal/pull/157) +- Add BigInt, BigFloat helper methods [#171](https://github.com/shopspring/decimal/pull/171) + +#### ENHANCEMENTS +- Memory usage optimization [#160](https://github.com/shopspring/decimal/pull/160) +- Updated travis CI golang versions [#156](https://github.com/shopspring/decimal/pull/156) +- Update documentation [#173](https://github.com/shopspring/decimal/pull/173) +- Improve code quality [#174](https://github.com/shopspring/decimal/pull/174) + +#### BUGFIXES +- Revert remove insignificant digits [#159](https://github.com/shopspring/decimal/pull/159) +- Remove 15 interval for RoundCash [#166](https://github.com/shopspring/decimal/pull/166) diff --git a/vendor/github.com/shopspring/decimal/LICENSE b/vendor/github.com/shopspring/decimal/LICENSE new file mode 100644 index 00000000..ad2148aa --- /dev/null +++ b/vendor/github.com/shopspring/decimal/LICENSE @@ -0,0 +1,45 @@ +The MIT License (MIT) + +Copyright (c) 2015 Spring, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +- Based on https://github.com/oguzbilgic/fpd, which has the following license: +""" +The MIT License (MIT) + +Copyright (c) 2013 Oguz Bilgic + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" diff --git a/vendor/github.com/shopspring/decimal/README.md b/vendor/github.com/shopspring/decimal/README.md new file mode 100644 index 00000000..2e35df06 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/README.md @@ -0,0 +1,130 @@ +# decimal + +[![Build Status](https://app.travis-ci.com/shopspring/decimal.svg?branch=master)](https://app.travis-ci.com/shopspring/decimal) [![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal) [![Go Report Card](https://goreportcard.com/badge/github.com/shopspring/decimal)](https://goreportcard.com/report/github.com/shopspring/decimal) + +Arbitrary-precision fixed-point decimal numbers in go. + +_Note:_ Decimal library can "only" represent numbers with a maximum of 2^31 digits after the decimal point. + +## Features + + * The zero-value is 0, and is safe to use without initialization + * Addition, subtraction, multiplication with no loss of precision + * Division with specified precision + * Database/sql serialization/deserialization + * JSON and XML serialization/deserialization + +## Install + +Run `go get github.com/shopspring/decimal` + +## Requirements + +Decimal library requires Go version `>=1.7` + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/shopspring/decimal" +) + +func main() { + price, err := decimal.NewFromString("136.02") + if err != nil { + panic(err) + } + + quantity := decimal.NewFromInt(3) + + fee, _ := decimal.NewFromString(".035") + taxRate, _ := decimal.NewFromString(".08875") + + subtotal := price.Mul(quantity) + + preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1))) + + total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1))) + + fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06 + fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421 + fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375 + fmt.Println("Total:", total) // Total: 459.824961375 + fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875 +} +``` + +## Documentation + +http://godoc.org/github.com/shopspring/decimal + +## Production Usage + +* [Spring](https://shopspring.com/), since August 14, 2014. +* If you are using this in production, please let us know! + +## FAQ + +#### Why don't you just use float64? + +Because float64 (or any binary floating point type, actually) can't represent +numbers such as `0.1` exactly. + +Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that +it prints out `10`, but it actually prints `9.999999999999831`. Over time, +these small errors can really add up! + +#### Why don't you just use big.Rat? + +big.Rat is fine for representing rational numbers, but Decimal is better for +representing money. Why? Here's a (contrived) example: + +Let's say you use big.Rat, and you have two numbers, x and y, both +representing 1/3, and you have `z = 1 - x - y = 1/3`. If you print each one +out, the string output has to stop somewhere (let's say it stops at 3 decimal +digits, for simplicity), so you'll get 0.333, 0.333, and 0.333. But where did +the other 0.001 go? + +Here's the above example as code: http://play.golang.org/p/lCZZs0w9KE + +With Decimal, the strings being printed out represent the number exactly. So, +if you have `x = y = 1/3` (with precision 3), they will actually be equal to +0.333, and when you do `z = 1 - x - y`, `z` will be equal to .334. No money is +unaccounted for! + +You still have to be careful. If you want to split a number `N` 3 ways, you +can't just send `N/3` to three different people. You have to pick one to send +`N - (2/3*N)` to. That person will receive the fraction of a penny remainder. + +But, it is much easier to be careful with Decimal than with big.Rat. + +#### Why isn't the API similar to big.Int's? + +big.Int's API is built to reduce the number of memory allocations for maximal +performance. This makes sense for its use-case, but the trade-off is that the +API is awkward and easy to misuse. + +For example, to add two big.Ints, you do: `z := new(big.Int).Add(x, y)`. A +developer unfamiliar with this API might try to do `z := a.Add(a, b)`. This +modifies `a` and sets `z` as an alias for `a`, which they might not expect. It +also modifies any other aliases to `a`. + +Here's an example of the subtle bugs you can introduce with big.Int's API: +https://play.golang.org/p/x2R_78pa8r + +In contrast, it's difficult to make such mistakes with decimal. Decimals +behave like other go numbers types: even though `a = b` will not deep copy +`b` into `a`, it is impossible to modify a Decimal, since all Decimal methods +return new Decimals and do not modify the originals. The downside is that +this causes extra allocations, so Decimal is less performant. My assumption +is that if you're using Decimals, you probably care more about correctness +than performance. + +## License + +The MIT License (MIT) + +This is a heavily modified fork of [fpd.Decimal](https://github.com/oguzbilgic/fpd), which was also released under the MIT License. diff --git a/vendor/github.com/shopspring/decimal/decimal-go.go b/vendor/github.com/shopspring/decimal/decimal-go.go new file mode 100644 index 00000000..9958d690 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/decimal-go.go @@ -0,0 +1,415 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package decimal + +type decimal struct { + d [800]byte // digits, big-endian representation + nd int // number of digits used + dp int // decimal point + neg bool // negative flag + trunc bool // discarded nonzero digits beyond d[:nd] +} + +func (a *decimal) String() string { + n := 10 + a.nd + if a.dp > 0 { + n += a.dp + } + if a.dp < 0 { + n += -a.dp + } + + buf := make([]byte, n) + w := 0 + switch { + case a.nd == 0: + return "0" + + case a.dp <= 0: + // zeros fill space between decimal point and digits + buf[w] = '0' + w++ + buf[w] = '.' + w++ + w += digitZero(buf[w : w+-a.dp]) + w += copy(buf[w:], a.d[0:a.nd]) + + case a.dp < a.nd: + // decimal point in middle of digits + w += copy(buf[w:], a.d[0:a.dp]) + buf[w] = '.' + w++ + w += copy(buf[w:], a.d[a.dp:a.nd]) + + default: + // zeros fill space between digits and decimal point + w += copy(buf[w:], a.d[0:a.nd]) + w += digitZero(buf[w : w+a.dp-a.nd]) + } + return string(buf[0:w]) +} + +func digitZero(dst []byte) int { + for i := range dst { + dst[i] = '0' + } + return len(dst) +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [24]byte + + // Write reversed decimal in buf. + n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0 + for n--; n >= 0; n-- { + a.d[a.nd] = buf[n] + a.nd++ + } + a.dp = a.nd + trim(a) +} + +// Maximum shift that we can do in one pass without overflow. +// A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63) +const maxShift = uintSize - 4 + +// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. +func rightShift(a *decimal, k uint) { + r := 0 // read pointer + w := 0 // write pointer + + // Pick up enough leading digits to cover first shift. + var n uint + for ; n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + return + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := uint(a.d[r]) + n = n*10 + c - '0' + } + a.dp -= r - 1 + + var mask uint = (1 << k) - 1 + + // Pick up a digit, put down a digit. + for ; r < a.nd; r++ { + c := uint(a.d[r]) + dig := n >> k + n &= mask + a.d[w] = byte(dig + '0') + w++ + n = n*10 + c - '0' + } + + // Put down extra digits. + for n > 0 { + dig := n >> k + n &= mask + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } + n = n * 10 + } + + a.nd = w + trim(a) +} + +// Cheat sheet for left shift: table indexed by shift count giving +// number of new digits that will be introduced by that shift. +// +// For example, leftcheats[4] = {2, "625"}. That means that +// if we are shifting by 4 (multiplying by 16), it will add 2 digits +// when the string prefix is "625" through "999", and one fewer digit +// if the string prefix is "000" through "624". +// +// Credit for this trick goes to Ken. + +type leftCheat struct { + delta int // number of new digits + cutoff string // minus one digit if original < a. +} + +var leftcheats = []leftCheat{ + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. + /* + seq 60 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\t{ 0, \"\" }," } + { + log2 = log(2)/log(10) + printf("\t{ %d, \"%s\" },\t// * %d\n", + int(log2*NR+1), $0, 2**NR) + }' + */ + {0, ""}, + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 + {9, "37252902984619140625"}, // * 268435456 + {9, "186264514923095703125"}, // * 536870912 + {10, "931322574615478515625"}, // * 1073741824 + {10, "4656612873077392578125"}, // * 2147483648 + {10, "23283064365386962890625"}, // * 4294967296 + {10, "116415321826934814453125"}, // * 8589934592 + {11, "582076609134674072265625"}, // * 17179869184 + {11, "2910383045673370361328125"}, // * 34359738368 + {11, "14551915228366851806640625"}, // * 68719476736 + {12, "72759576141834259033203125"}, // * 137438953472 + {12, "363797880709171295166015625"}, // * 274877906944 + {12, "1818989403545856475830078125"}, // * 549755813888 + {13, "9094947017729282379150390625"}, // * 1099511627776 + {13, "45474735088646411895751953125"}, // * 2199023255552 + {13, "227373675443232059478759765625"}, // * 4398046511104 + {13, "1136868377216160297393798828125"}, // * 8796093022208 + {14, "5684341886080801486968994140625"}, // * 17592186044416 + {14, "28421709430404007434844970703125"}, // * 35184372088832 + {14, "142108547152020037174224853515625"}, // * 70368744177664 + {15, "710542735760100185871124267578125"}, // * 140737488355328 + {15, "3552713678800500929355621337890625"}, // * 281474976710656 + {15, "17763568394002504646778106689453125"}, // * 562949953421312 + {16, "88817841970012523233890533447265625"}, // * 1125899906842624 + {16, "444089209850062616169452667236328125"}, // * 2251799813685248 + {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 + {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 + {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 + {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 + {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 + {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 + {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 + {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 + {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 +} + +// Is the leading prefix of b lexicographically less than s? +func prefixIsLessThan(b []byte, s string) bool { + for i := 0; i < len(s); i++ { + if i >= len(b) { + return true + } + if b[i] != s[i] { + return b[i] < s[i] + } + } + return false +} + +// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. +func leftShift(a *decimal, k uint) { + delta := leftcheats[k].delta + if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { + delta-- + } + + r := a.nd // read index + w := a.nd + delta // write index + + // Pick up a digit, put down a digit. + var n uint + for r--; r >= 0; r-- { + n += (uint(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } + a.dp += delta + trim(a) +} + +// Binary shift left (k > 0) or right (k < 0). +func (a *decimal) Shift(k int) { + switch { + case a.nd == 0: + // nothing to do: a == 0 + case k > 0: + for k > maxShift { + leftShift(a, maxShift) + k -= maxShift + } + leftShift(a, uint(k)) + case k < 0: + for k < -maxShift { + rightShift(a, maxShift) + k += maxShift + } + rightShift(a, uint(-k)) + } +} + +// If we chop a at nd digits, should we round up? +func shouldRoundUp(a *decimal, nd int) bool { + if nd < 0 || nd >= a.nd { + return false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + return true + } + return nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + return a.d[nd] >= '5' +} + +// Round a to nd digits (or fewer). +// If nd is zero, it means we're rounding +// just to the left of the digits, as in +// 0.09 -> 0.1. +func (a *decimal) Round(nd int) { + if nd < 0 || nd >= a.nd { + return + } + if shouldRoundUp(a, nd) { + a.RoundUp(nd) + } else { + a.RoundDown(nd) + } +} + +// Round a down to nd digits (or fewer). +func (a *decimal) RoundDown(nd int) { + if nd < 0 || nd >= a.nd { + return + } + a.nd = nd + trim(a) +} + +// Round a up to nd digits (or fewer). +func (a *decimal) RoundUp(nd int) { + if nd < 0 || nd >= a.nd { + return + } + + // round up + for i := nd - 1; i >= 0; i-- { + c := a.d[i] + if c < '9' { // can stop after this digit + a.d[i]++ + a.nd = i + 1 + return + } + } + + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + a.d[0] = '1' + a.nd = 1 + a.dp++ +} + +// Extract integer part, rounded appropriately. +// No guarantees about overflow. +func (a *decimal) RoundedInteger() uint64 { + if a.dp > 20 { + return 0xFFFFFFFFFFFFFFFF + } + var i int + n := uint64(0) + for i = 0; i < a.dp && i < a.nd; i++ { + n = n*10 + uint64(a.d[i]-'0') + } + for ; i < a.dp; i++ { + n *= 10 + } + if shouldRoundUp(a, a.dp) { + n++ + } + return n +} diff --git a/vendor/github.com/shopspring/decimal/decimal.go b/vendor/github.com/shopspring/decimal/decimal.go new file mode 100644 index 00000000..84405ec1 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/decimal.go @@ -0,0 +1,1904 @@ +// Package decimal implements an arbitrary precision fixed-point decimal. +// +// The zero-value of a Decimal is 0, as you would expect. +// +// The best way to create a new Decimal is to use decimal.NewFromString, ex: +// +// n, err := decimal.NewFromString("-123.4567") +// n.String() // output: "-123.4567" +// +// To use Decimal as part of a struct: +// +// type Struct struct { +// Number Decimal +// } +// +// Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point. +package decimal + +import ( + "database/sql/driver" + "encoding/binary" + "fmt" + "math" + "math/big" + "regexp" + "strconv" + "strings" +) + +// DivisionPrecision is the number of decimal places in the result when it +// doesn't divide exactly. +// +// Example: +// +// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d1.String() // output: "0.6666666666666667" +// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)) +// d2.String() // output: "0.0000666666666667" +// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)) +// d3.String() // output: "6666.6666666666666667" +// decimal.DivisionPrecision = 3 +// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d4.String() // output: "0.667" +// +var DivisionPrecision = 16 + +// MarshalJSONWithoutQuotes should be set to true if you want the decimal to +// be JSON marshaled as a number, instead of as a string. +// WARNING: this is dangerous for decimals with many digits, since many JSON +// unmarshallers (ex: Javascript's) will unmarshal JSON numbers to IEEE 754 +// double-precision floating point numbers, which means you can potentially +// silently lose precision. +var MarshalJSONWithoutQuotes = false + +// ExpMaxIterations specifies the maximum number of iterations needed to calculate +// precise natural exponent value using ExpHullAbrham method. +var ExpMaxIterations = 1000 + +// Zero constant, to make computations faster. +// Zero should never be compared with == or != directly, please use decimal.Equal or decimal.Cmp instead. +var Zero = New(0, 1) + +var zeroInt = big.NewInt(0) +var oneInt = big.NewInt(1) +var twoInt = big.NewInt(2) +var fourInt = big.NewInt(4) +var fiveInt = big.NewInt(5) +var tenInt = big.NewInt(10) +var twentyInt = big.NewInt(20) + +var factorials = []Decimal{New(1, 0)} + +// Decimal represents a fixed-point decimal. It is immutable. +// number = value * 10 ^ exp +type Decimal struct { + value *big.Int + + // NOTE(vadim): this must be an int32, because we cast it to float64 during + // calculations. If exp is 64 bit, we might lose precision. + // If we cared about being able to represent every possible decimal, we + // could make exp a *big.Int but it would hurt performance and numbers + // like that are unrealistic. + exp int32 +} + +// New returns a new fixed-point decimal, value * 10 ^ exp. +func New(value int64, exp int32) Decimal { + return Decimal{ + value: big.NewInt(value), + exp: exp, + } +} + +// NewFromInt converts a int64 to Decimal. +// +// Example: +// +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" +func NewFromInt(value int64) Decimal { + return Decimal{ + value: big.NewInt(value), + exp: 0, + } +} + +// NewFromInt32 converts a int32 to Decimal. +// +// Example: +// +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" +func NewFromInt32(value int32) Decimal { + return Decimal{ + value: big.NewInt(int64(value)), + exp: 0, + } +} + +// NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp +func NewFromBigInt(value *big.Int, exp int32) Decimal { + return Decimal{ + value: new(big.Int).Set(value), + exp: exp, + } +} + +// NewFromString returns a new Decimal from a string representation. +// Trailing zeroes are not trimmed. +// +// Example: +// +// d, err := NewFromString("-123.45") +// d2, err := NewFromString(".0001") +// d3, err := NewFromString("1.47000") +// +func NewFromString(value string) (Decimal, error) { + originalInput := value + var intString string + var exp int64 + + // Check if number is using scientific notation + eIndex := strings.IndexAny(value, "Ee") + if eIndex != -1 { + expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32) + if err != nil { + if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { + return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value) + } + return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value) + } + value = value[:eIndex] + exp = expInt + } + + pIndex := -1 + vLen := len(value) + for i := 0; i < vLen; i++ { + if value[i] == '.' { + if pIndex > -1 { + return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) + } + pIndex = i + } + } + + if pIndex == -1 { + // There is no decimal point, we can just parse the original string as + // an int + intString = value + } else { + if pIndex+1 < vLen { + intString = value[:pIndex] + value[pIndex+1:] + } else { + intString = value[:pIndex] + } + expInt := -len(value[pIndex+1:]) + exp += int64(expInt) + } + + var dValue *big.Int + // strconv.ParseInt is faster than new(big.Int).SetString so this is just a shortcut for strings we know won't overflow + if len(intString) <= 18 { + parsed64, err := strconv.ParseInt(intString, 10, 64) + if err != nil { + return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + } + dValue = big.NewInt(parsed64) + } else { + dValue = new(big.Int) + _, ok := dValue.SetString(intString, 10) + if !ok { + return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + } + } + + if exp < math.MinInt32 || exp > math.MaxInt32 { + // NOTE(vadim): I doubt a string could realistically be this long + return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput) + } + + return Decimal{ + value: dValue, + exp: int32(exp), + }, nil +} + +// NewFromFormattedString returns a new Decimal from a formatted string representation. +// The second argument - replRegexp, is a regular expression that is used to find characters that should be +// removed from given decimal string representation. All matched characters will be replaced with an empty string. +// +// Example: +// +// r := regexp.MustCompile("[$,]") +// d1, err := NewFromFormattedString("$5,125.99", r) +// +// r2 := regexp.MustCompile("[_]") +// d2, err := NewFromFormattedString("1_000_000", r2) +// +// r3 := regexp.MustCompile("[USD\\s]") +// d3, err := NewFromFormattedString("5000 USD", r3) +// +func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) { + parsedValue := replRegexp.ReplaceAllString(value, "") + d, err := NewFromString(parsedValue) + if err != nil { + return Decimal{}, err + } + return d, nil +} + +// RequireFromString returns a new Decimal from a string representation +// or panics if NewFromString would have returned an error. +// +// Example: +// +// d := RequireFromString("-123.45") +// d2 := RequireFromString(".0001") +// +func RequireFromString(value string) Decimal { + dec, err := NewFromString(value) + if err != nil { + panic(err) + } + return dec +} + +// NewFromFloat converts a float64 to Decimal. +// +// The converted number will contain the number of significant digits that can be +// represented in a float with reliable roundtrip. +// This is typically 15 digits, but may be more in some cases. +// See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. +// +// For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. +// +// NOTE: this will panic on NaN, +/-inf +func NewFromFloat(value float64) Decimal { + if value == 0 { + return New(0, 0) + } + return newFromFloat(value, math.Float64bits(value), &float64info) +} + +// NewFromFloat32 converts a float32 to Decimal. +// +// The converted number will contain the number of significant digits that can be +// represented in a float with reliable roundtrip. +// This is typically 6-8 digits depending on the input. +// See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. +// +// For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. +// +// NOTE: this will panic on NaN, +/-inf +func NewFromFloat32(value float32) Decimal { + if value == 0 { + return New(0, 0) + } + // XOR is workaround for https://github.com/golang/go/issues/26285 + a := math.Float32bits(value) ^ 0x80808080 + return newFromFloat(float64(value), uint64(a)^0x80808080, &float32info) +} + +func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal { + if math.IsNaN(val) || math.IsInf(val, 0) { + panic(fmt.Sprintf("Cannot create a Decimal from %v", val)) + } + exp := int(bits>>flt.mantbits) & (1<>(flt.expbits+flt.mantbits) != 0 + + roundShortest(&d, mant, exp, flt) + // If less than 19 digits, we can do calculation in an int64. + if d.nd < 19 { + tmp := int64(0) + m := int64(1) + for i := d.nd - 1; i >= 0; i-- { + tmp += m * int64(d.d[i]-'0') + m *= 10 + } + if d.neg { + tmp *= -1 + } + return Decimal{value: big.NewInt(tmp), exp: int32(d.dp) - int32(d.nd)} + } + dValue := new(big.Int) + dValue, ok := dValue.SetString(string(d.d[:d.nd]), 10) + if ok { + return Decimal{value: dValue, exp: int32(d.dp) - int32(d.nd)} + } + + return NewFromFloatWithExponent(val, int32(d.dp)-int32(d.nd)) +} + +// NewFromFloatWithExponent converts a float64 to Decimal, with an arbitrary +// number of fractional digits. +// +// Example: +// +// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" +// +func NewFromFloatWithExponent(value float64, exp int32) Decimal { + if math.IsNaN(value) || math.IsInf(value, 0) { + panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) + } + + bits := math.Float64bits(value) + mant := bits & (1<<52 - 1) + exp2 := int32((bits >> 52) & (1<<11 - 1)) + sign := bits >> 63 + + if exp2 == 0 { + // specials + if mant == 0 { + return Decimal{} + } + // subnormal + exp2++ + } else { + // normal + mant |= 1 << 52 + } + + exp2 -= 1023 + 52 + + // normalizing base-2 values + for mant&1 == 0 { + mant = mant >> 1 + exp2++ + } + + // maximum number of fractional base-10 digits to represent 2^N exactly cannot be more than -N if N<0 + if exp < 0 && exp < exp2 { + if exp2 < 0 { + exp = exp2 + } else { + exp = 0 + } + } + + // representing 10^M * 2^N as 5^M * 2^(M+N) + exp2 -= exp + + temp := big.NewInt(1) + dMant := big.NewInt(int64(mant)) + + // applying 5^M + if exp > 0 { + temp = temp.SetInt64(int64(exp)) + temp = temp.Exp(fiveInt, temp, nil) + } else if exp < 0 { + temp = temp.SetInt64(-int64(exp)) + temp = temp.Exp(fiveInt, temp, nil) + dMant = dMant.Mul(dMant, temp) + temp = temp.SetUint64(1) + } + + // applying 2^(M+N) + if exp2 > 0 { + dMant = dMant.Lsh(dMant, uint(exp2)) + } else if exp2 < 0 { + temp = temp.Lsh(temp, uint(-exp2)) + } + + // rounding and downscaling + if exp > 0 || exp2 < 0 { + halfDown := new(big.Int).Rsh(temp, 1) + dMant = dMant.Add(dMant, halfDown) + dMant = dMant.Quo(dMant, temp) + } + + if sign == 1 { + dMant = dMant.Neg(dMant) + } + + return Decimal{ + value: dMant, + exp: exp, + } +} + +// Copy returns a copy of decimal with the same value and exponent, but a different pointer to value. +func (d Decimal) Copy() Decimal { + d.ensureInitialized() + return Decimal{ + value: &(*d.value), + exp: d.exp, + } +} + +// rescale returns a rescaled version of the decimal. Returned +// decimal may be less precise if the given exponent is bigger +// than the initial exponent of the Decimal. +// NOTE: this will truncate, NOT round +// +// Example: +// +// d := New(12345, -4) +// d2 := d.rescale(-1) +// d3 := d2.rescale(-4) +// println(d1) +// println(d2) +// println(d3) +// +// Output: +// +// 1.2345 +// 1.2 +// 1.2000 +// +func (d Decimal) rescale(exp int32) Decimal { + d.ensureInitialized() + + if d.exp == exp { + return Decimal{ + new(big.Int).Set(d.value), + d.exp, + } + } + + // NOTE(vadim): must convert exps to float64 before - to prevent overflow + diff := math.Abs(float64(exp) - float64(d.exp)) + value := new(big.Int).Set(d.value) + + expScale := new(big.Int).Exp(tenInt, big.NewInt(int64(diff)), nil) + if exp > d.exp { + value = value.Quo(value, expScale) + } else if exp < d.exp { + value = value.Mul(value, expScale) + } + + return Decimal{ + value: value, + exp: exp, + } +} + +// Abs returns the absolute value of the decimal. +func (d Decimal) Abs() Decimal { + if !d.IsNegative() { + return d + } + d.ensureInitialized() + d2Value := new(big.Int).Abs(d.value) + return Decimal{ + value: d2Value, + exp: d.exp, + } +} + +// Add returns d + d2. +func (d Decimal) Add(d2 Decimal) Decimal { + rd, rd2 := RescalePair(d, d2) + + d3Value := new(big.Int).Add(rd.value, rd2.value) + return Decimal{ + value: d3Value, + exp: rd.exp, + } +} + +// Sub returns d - d2. +func (d Decimal) Sub(d2 Decimal) Decimal { + rd, rd2 := RescalePair(d, d2) + + d3Value := new(big.Int).Sub(rd.value, rd2.value) + return Decimal{ + value: d3Value, + exp: rd.exp, + } +} + +// Neg returns -d. +func (d Decimal) Neg() Decimal { + d.ensureInitialized() + val := new(big.Int).Neg(d.value) + return Decimal{ + value: val, + exp: d.exp, + } +} + +// Mul returns d * d2. +func (d Decimal) Mul(d2 Decimal) Decimal { + d.ensureInitialized() + d2.ensureInitialized() + + expInt64 := int64(d.exp) + int64(d2.exp) + if expInt64 > math.MaxInt32 || expInt64 < math.MinInt32 { + // NOTE(vadim): better to panic than give incorrect results, as + // Decimals are usually used for money + panic(fmt.Sprintf("exponent %v overflows an int32!", expInt64)) + } + + d3Value := new(big.Int).Mul(d.value, d2.value) + return Decimal{ + value: d3Value, + exp: int32(expInt64), + } +} + +// Shift shifts the decimal in base 10. +// It shifts left when shift is positive and right if shift is negative. +// In simpler terms, the given value for shift is added to the exponent +// of the decimal. +func (d Decimal) Shift(shift int32) Decimal { + d.ensureInitialized() + return Decimal{ + value: new(big.Int).Set(d.value), + exp: d.exp + shift, + } +} + +// Div returns d / d2. If it doesn't divide exactly, the result will have +// DivisionPrecision digits after the decimal point. +func (d Decimal) Div(d2 Decimal) Decimal { + return d.DivRound(d2, int32(DivisionPrecision)) +} + +// QuoRem does divsion with remainder +// d.QuoRem(d2,precision) returns quotient q and remainder r such that +// d = d2 * q + r, q an integer multiple of 10^(-precision) +// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 +// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 +// Note that precision<0 is allowed as input. +func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { + d.ensureInitialized() + d2.ensureInitialized() + if d2.value.Sign() == 0 { + panic("decimal division by 0") + } + scale := -precision + e := int64(d.exp - d2.exp - scale) + if e > math.MaxInt32 || e < math.MinInt32 { + panic("overflow in decimal QuoRem") + } + var aa, bb, expo big.Int + var scalerest int32 + // d = a 10^ea + // d2 = b 10^eb + if e < 0 { + aa = *d.value + expo.SetInt64(-e) + bb.Exp(tenInt, &expo, nil) + bb.Mul(d2.value, &bb) + scalerest = d.exp + // now aa = a + // bb = b 10^(scale + eb - ea) + } else { + expo.SetInt64(e) + aa.Exp(tenInt, &expo, nil) + aa.Mul(d.value, &aa) + bb = *d2.value + scalerest = scale + d2.exp + // now aa = a ^ (ea - eb - scale) + // bb = b + } + var q, r big.Int + q.QuoRem(&aa, &bb, &r) + dq := Decimal{value: &q, exp: scale} + dr := Decimal{value: &r, exp: scalerest} + return dq, dr +} + +// DivRound divides and rounds to a given precision +// i.e. to an integer multiple of 10^(-precision) +// for a positive quotient digit 5 is rounded up, away from 0 +// if the quotient is negative then digit 5 is rounded down, away from 0 +// Note that precision<0 is allowed as input. +func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { + // QuoRem already checks initialization + q, r := d.QuoRem(d2, precision) + // the actual rounding decision is based on comparing r*10^precision and d2/2 + // instead compare 2 r 10 ^precision and d2 + var rv2 big.Int + rv2.Abs(r.value) + rv2.Lsh(&rv2, 1) + // now rv2 = abs(r.value) * 2 + r2 := Decimal{value: &rv2, exp: r.exp + precision} + // r2 is now 2 * r * 10 ^ precision + var c = r2.Cmp(d2.Abs()) + + if c < 0 { + return q + } + + if d.value.Sign()*d2.value.Sign() < 0 { + return q.Sub(New(1, -precision)) + } + + return q.Add(New(1, -precision)) +} + +// Mod returns d % d2. +func (d Decimal) Mod(d2 Decimal) Decimal { + quo := d.Div(d2).Truncate(0) + return d.Sub(d2.Mul(quo)) +} + +// Pow returns d to the power d2 +func (d Decimal) Pow(d2 Decimal) Decimal { + var temp Decimal + if d2.IntPart() == 0 { + return NewFromFloat(1) + } + temp = d.Pow(d2.Div(NewFromFloat(2))) + if d2.IntPart()%2 == 0 { + return temp.Mul(temp) + } + if d2.IntPart() > 0 { + return temp.Mul(temp).Mul(d) + } + return temp.Mul(temp).Div(d) +} + +// ExpHullAbrham calculates the natural exponent of decimal (e to the power of d) using Hull-Abraham algorithm. +// OverallPrecision argument specifies the overall precision of the result (integer part + decimal part). +// +// ExpHullAbrham is faster than ExpTaylor for small precision values, but it is much slower for large precision values. +// +// Example: +// +// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000" +// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284" +// +func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) { + // Algorithm based on Variable precision exponential function. + // ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham. + if d.IsZero() { + return Decimal{oneInt, 0}, nil + } + + currentPrecision := overallPrecision + + // Algorithm does not work if currentPrecision * 23 < |x|. + // Precision is automatically increased in such cases, so the value can be calculated precisely. + // If newly calculated precision is higher than ExpMaxIterations the currentPrecision will not be changed. + f := d.Abs().InexactFloat64() + if ncp := f / 23; ncp > float64(currentPrecision) && ncp < float64(ExpMaxIterations) { + currentPrecision = uint32(math.Ceil(ncp)) + } + + // fail if abs(d) beyond an over/underflow threshold + overflowThreshold := New(23*int64(currentPrecision), 0) + if d.Abs().Cmp(overflowThreshold) > 0 { + return Decimal{}, fmt.Errorf("over/underflow threshold, exp(x) cannot be calculated precisely") + } + + // Return 1 if abs(d) small enough; this also avoids later over/underflow + overflowThreshold2 := New(9, -int32(currentPrecision)-1) + if d.Abs().Cmp(overflowThreshold2) <= 0 { + return Decimal{oneInt, d.exp}, nil + } + + // t is the smallest integer >= 0 such that the corresponding abs(d/k) < 1 + t := d.exp + int32(d.NumDigits()) // Add d.NumDigits because the paper assumes that d.value [0.1, 1) + + if t < 0 { + t = 0 + } + + k := New(1, t) // reduction factor + r := Decimal{new(big.Int).Set(d.value), d.exp - t} // reduced argument + p := int32(currentPrecision) + t + 2 // precision for calculating the sum + + // Determine n, the number of therms for calculating sum + // use first Newton step (1.435p - 1.182) / log10(p/abs(r)) + // for solving appropriate equation, along with directed + // roundings and simple rational bound for log10(p/abs(r)) + rf := r.Abs().InexactFloat64() + pf := float64(p) + nf := math.Ceil((1.453*pf - 1.182) / math.Log10(pf/rf)) + if nf > float64(ExpMaxIterations) || math.IsNaN(nf) { + return Decimal{}, fmt.Errorf("exact value cannot be calculated in <=ExpMaxIterations iterations") + } + n := int64(nf) + + tmp := New(0, 0) + sum := New(1, 0) + one := New(1, 0) + for i := n - 1; i > 0; i-- { + tmp.value.SetInt64(i) + sum = sum.Mul(r.DivRound(tmp, p)) + sum = sum.Add(one) + } + + ki := k.IntPart() + res := New(1, 0) + for i := ki; i > 0; i-- { + res = res.Mul(sum) + } + + resNumDigits := int32(res.NumDigits()) + + var roundDigits int32 + if resNumDigits > abs(res.exp) { + roundDigits = int32(currentPrecision) - resNumDigits - res.exp + } else { + roundDigits = int32(currentPrecision) + } + + res = res.Round(roundDigits) + + return res, nil +} + +// ExpTaylor calculates the natural exponent of decimal (e to the power of d) using Taylor series expansion. +// Precision argument specifies how precise the result must be (number of digits after decimal point). +// Negative precision is allowed. +// +// ExpTaylor is much faster for large precision values than ExpHullAbrham. +// +// Example: +// +// d, err := NewFromFloat(26.1).ExpTaylor(2).String() +// d.String() // output: "216314672147.06" +// +// NewFromFloat(26.1).ExpTaylor(20).String() +// d.String() // output: "216314672147.05767284062928674083" +// +// NewFromFloat(26.1).ExpTaylor(-10).String() +// d.String() // output: "220000000000" +// +func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { + // Note(mwoss): Implementation can be optimized by exclusively using big.Int API only + if d.IsZero() { + return Decimal{oneInt, 0}.Round(precision), nil + } + + var epsilon Decimal + var divPrecision int32 + if precision < 0 { + epsilon = New(1, -1) + divPrecision = 8 + } else { + epsilon = New(1, -precision-1) + divPrecision = precision + 1 + } + + decAbs := d.Abs() + pow := d.Abs() + factorial := New(1, 0) + + result := New(1, 0) + + for i := int64(1); ; { + step := pow.DivRound(factorial, divPrecision) + result = result.Add(step) + + // Stop Taylor series when current step is smaller than epsilon + if step.Cmp(epsilon) < 0 { + break + } + + pow = pow.Mul(decAbs) + + i++ + + // Calculate next factorial number or retrieve cached value + if len(factorials) >= int(i) && !factorials[i-1].IsZero() { + factorial = factorials[i-1] + } else { + // To avoid any race conditions, firstly the zero value is appended to a slice to create + // a spot for newly calculated factorial. After that, the zero value is replaced by calculated + // factorial using the index notation. + factorial = factorials[i-2].Mul(New(i, 0)) + factorials = append(factorials, Zero) + factorials[i-1] = factorial + } + } + + if d.Sign() < 0 { + result = New(1, 0).DivRound(result, precision+1) + } + + result = result.Round(precision) + return result, nil +} + +// NumDigits returns the number of digits of the decimal coefficient (d.Value) +// Note: Current implementation is extremely slow for large decimals and/or decimals with large fractional part +func (d Decimal) NumDigits() int { + // Note(mwoss): It can be optimized, unnecessary cast of big.Int to string + if d.IsNegative() { + return len(d.value.String()) - 1 + } + return len(d.value.String()) +} + +// IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false. +func (d Decimal) IsInteger() bool { + // The most typical case, all decimal with exponent higher or equal 0 can be represented as integer + if d.exp >= 0 { + return true + } + // When the exponent is negative we have to check every number after the decimal place + // If all of them are zeroes, we are sure that given decimal can be represented as an integer + var r big.Int + q := new(big.Int).Set(d.value) + for z := abs(d.exp); z > 0; z-- { + q.QuoRem(q, tenInt, &r) + if r.Cmp(zeroInt) != 0 { + return false + } + } + return true +} + +// Abs calculates absolute value of any int32. Used for calculating absolute value of decimal's exponent. +func abs(n int32) int32 { + if n < 0 { + return -n + } + return n +} + +// Cmp compares the numbers represented by d and d2 and returns: +// +// -1 if d < d2 +// 0 if d == d2 +// +1 if d > d2 +// +func (d Decimal) Cmp(d2 Decimal) int { + d.ensureInitialized() + d2.ensureInitialized() + + if d.exp == d2.exp { + return d.value.Cmp(d2.value) + } + + rd, rd2 := RescalePair(d, d2) + + return rd.value.Cmp(rd2.value) +} + +// Equal returns whether the numbers represented by d and d2 are equal. +func (d Decimal) Equal(d2 Decimal) bool { + return d.Cmp(d2) == 0 +} + +// Equals is deprecated, please use Equal method instead +func (d Decimal) Equals(d2 Decimal) bool { + return d.Equal(d2) +} + +// GreaterThan (GT) returns true when d is greater than d2. +func (d Decimal) GreaterThan(d2 Decimal) bool { + return d.Cmp(d2) == 1 +} + +// GreaterThanOrEqual (GTE) returns true when d is greater than or equal to d2. +func (d Decimal) GreaterThanOrEqual(d2 Decimal) bool { + cmp := d.Cmp(d2) + return cmp == 1 || cmp == 0 +} + +// LessThan (LT) returns true when d is less than d2. +func (d Decimal) LessThan(d2 Decimal) bool { + return d.Cmp(d2) == -1 +} + +// LessThanOrEqual (LTE) returns true when d is less than or equal to d2. +func (d Decimal) LessThanOrEqual(d2 Decimal) bool { + cmp := d.Cmp(d2) + return cmp == -1 || cmp == 0 +} + +// Sign returns: +// +// -1 if d < 0 +// 0 if d == 0 +// +1 if d > 0 +// +func (d Decimal) Sign() int { + if d.value == nil { + return 0 + } + return d.value.Sign() +} + +// IsPositive return +// +// true if d > 0 +// false if d == 0 +// false if d < 0 +func (d Decimal) IsPositive() bool { + return d.Sign() == 1 +} + +// IsNegative return +// +// true if d < 0 +// false if d == 0 +// false if d > 0 +func (d Decimal) IsNegative() bool { + return d.Sign() == -1 +} + +// IsZero return +// +// true if d == 0 +// false if d > 0 +// false if d < 0 +func (d Decimal) IsZero() bool { + return d.Sign() == 0 +} + +// Exponent returns the exponent, or scale component of the decimal. +func (d Decimal) Exponent() int32 { + return d.exp +} + +// Coefficient returns the coefficient of the decimal. It is scaled by 10^Exponent() +func (d Decimal) Coefficient() *big.Int { + d.ensureInitialized() + // we copy the coefficient so that mutating the result does not mutate the Decimal. + return new(big.Int).Set(d.value) +} + +// CoefficientInt64 returns the coefficient of the decimal as int64. It is scaled by 10^Exponent() +// If coefficient cannot be represented in an int64, the result will be undefined. +func (d Decimal) CoefficientInt64() int64 { + d.ensureInitialized() + return d.value.Int64() +} + +// IntPart returns the integer component of the decimal. +func (d Decimal) IntPart() int64 { + scaledD := d.rescale(0) + return scaledD.value.Int64() +} + +// BigInt returns integer component of the decimal as a BigInt. +func (d Decimal) BigInt() *big.Int { + scaledD := d.rescale(0) + i := &big.Int{} + i.SetString(scaledD.String(), 10) + return i +} + +// BigFloat returns decimal as BigFloat. +// Be aware that casting decimal to BigFloat might cause a loss of precision. +func (d Decimal) BigFloat() *big.Float { + f := &big.Float{} + f.SetString(d.String()) + return f +} + +// Rat returns a rational number representation of the decimal. +func (d Decimal) Rat() *big.Rat { + d.ensureInitialized() + if d.exp <= 0 { + // NOTE(vadim): must negate after casting to prevent int32 overflow + denom := new(big.Int).Exp(tenInt, big.NewInt(-int64(d.exp)), nil) + return new(big.Rat).SetFrac(d.value, denom) + } + + mul := new(big.Int).Exp(tenInt, big.NewInt(int64(d.exp)), nil) + num := new(big.Int).Mul(d.value, mul) + return new(big.Rat).SetFrac(num, oneInt) +} + +// Float64 returns the nearest float64 value for d and a bool indicating +// whether f represents d exactly. +// For more details, see the documentation for big.Rat.Float64 +func (d Decimal) Float64() (f float64, exact bool) { + return d.Rat().Float64() +} + +// InexactFloat64 returns the nearest float64 value for d. +// It doesn't indicate if the returned value represents d exactly. +func (d Decimal) InexactFloat64() float64 { + f, _ := d.Float64() + return f +} + +// String returns the string representation of the decimal +// with the fixed point. +// +// Example: +// +// d := New(-12345, -3) +// println(d.String()) +// +// Output: +// +// -12.345 +// +func (d Decimal) String() string { + return d.string(true) +} + +// StringFixed returns a rounded fixed-point string with places digits after +// the decimal point. +// +// Example: +// +// NewFromFloat(0).StringFixed(2) // output: "0.00" +// NewFromFloat(0).StringFixed(0) // output: "0" +// NewFromFloat(5.45).StringFixed(0) // output: "5" +// NewFromFloat(5.45).StringFixed(1) // output: "5.5" +// NewFromFloat(5.45).StringFixed(2) // output: "5.45" +// NewFromFloat(5.45).StringFixed(3) // output: "5.450" +// NewFromFloat(545).StringFixed(-1) // output: "550" +// +func (d Decimal) StringFixed(places int32) string { + rounded := d.Round(places) + return rounded.string(false) +} + +// StringFixedBank returns a banker rounded fixed-point string with places digits +// after the decimal point. +// +// Example: +// +// NewFromFloat(0).StringFixedBank(2) // output: "0.00" +// NewFromFloat(0).StringFixedBank(0) // output: "0" +// NewFromFloat(5.45).StringFixedBank(0) // output: "5" +// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4" +// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" +// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" +// NewFromFloat(545).StringFixedBank(-1) // output: "540" +// +func (d Decimal) StringFixedBank(places int32) string { + rounded := d.RoundBank(places) + return rounded.string(false) +} + +// StringFixedCash returns a Swedish/Cash rounded fixed-point string. For +// more details see the documentation at function RoundCash. +func (d Decimal) StringFixedCash(interval uint8) string { + rounded := d.RoundCash(interval) + return rounded.string(false) +} + +// Round rounds the decimal to places decimal places. +// If places < 0, it will round the integer part to the nearest 10^(-places). +// +// Example: +// +// NewFromFloat(5.45).Round(1).String() // output: "5.5" +// NewFromFloat(545).Round(-1).String() // output: "550" +// +func (d Decimal) Round(places int32) Decimal { + if d.exp == -places { + return d + } + // truncate to places + 1 + ret := d.rescale(-places - 1) + + // add sign(d) * 0.5 + if ret.value.Sign() < 0 { + ret.value.Sub(ret.value, fiveInt) + } else { + ret.value.Add(ret.value, fiveInt) + } + + // floor for positive numbers, ceil for negative numbers + _, m := ret.value.DivMod(ret.value, tenInt, new(big.Int)) + ret.exp++ + if ret.value.Sign() < 0 && m.Cmp(zeroInt) != 0 { + ret.value.Add(ret.value, oneInt) + } + + return ret +} + +// RoundCeil rounds the decimal towards +infinity. +// +// Example: +// +// NewFromFloat(545).RoundCeil(-2).String() // output: "600" +// NewFromFloat(500).RoundCeil(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5" +// +func (d Decimal) RoundCeil(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() > 0 { + rescaled.value.Add(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundFloor rounds the decimal towards -infinity. +// +// Example: +// +// NewFromFloat(545).RoundFloor(-2).String() // output: "500" +// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4" +// +func (d Decimal) RoundFloor(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() < 0 { + rescaled.value.Sub(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundUp rounds the decimal away from zero. +// +// Example: +// +// NewFromFloat(545).RoundUp(-2).String() // output: "600" +// NewFromFloat(500).RoundUp(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4" +// +func (d Decimal) RoundUp(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() > 0 { + rescaled.value.Add(rescaled.value, oneInt) + } else if d.value.Sign() < 0 { + rescaled.value.Sub(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundDown rounds the decimal towards zero. +// +// Example: +// +// NewFromFloat(545).RoundDown(-2).String() // output: "500" +// NewFromFloat(-500).RoundDown(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5" +// +func (d Decimal) RoundDown(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + return rescaled +} + +// RoundBank rounds the decimal to places decimal places. +// If the final digit to round is equidistant from the nearest two integers the +// rounded value is taken as the even number +// +// If places < 0, it will round the integer part to the nearest 10^(-places). +// +// Examples: +// +// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4" +// NewFromFloat(545).RoundBank(-1).String() // output: "540" +// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5" +// NewFromFloat(546).RoundBank(-1).String() // output: "550" +// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6" +// NewFromFloat(555).RoundBank(-1).String() // output: "560" +// +func (d Decimal) RoundBank(places int32) Decimal { + + round := d.Round(places) + remainder := d.Sub(round).Abs() + + half := New(5, -places-1) + if remainder.Cmp(half) == 0 && round.value.Bit(0) != 0 { + if round.value.Sign() < 0 { + round.value.Add(round.value, oneInt) + } else { + round.value.Sub(round.value, oneInt) + } + } + + return round +} + +// RoundCash aka Cash/Penny/öre rounding rounds decimal to a specific +// interval. The amount payable for a cash transaction is rounded to the nearest +// multiple of the minimum currency unit available. The following intervals are +// available: 5, 10, 25, 50 and 100; any other number throws a panic. +// 5: 5 cent rounding 3.43 => 3.45 +// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) +// 25: 25 cent rounding 3.41 => 3.50 +// 50: 50 cent rounding 3.75 => 4.00 +// 100: 100 cent rounding 3.50 => 4.00 +// For more details: https://en.wikipedia.org/wiki/Cash_rounding +func (d Decimal) RoundCash(interval uint8) Decimal { + var iVal *big.Int + switch interval { + case 5: + iVal = twentyInt + case 10: + iVal = tenInt + case 25: + iVal = fourInt + case 50: + iVal = twoInt + case 100: + iVal = oneInt + default: + panic(fmt.Sprintf("Decimal does not support this Cash rounding interval `%d`. Supported: 5, 10, 25, 50, 100", interval)) + } + dVal := Decimal{ + value: iVal, + } + + // TODO: optimize those calculations to reduce the high allocations (~29 allocs). + return d.Mul(dVal).Round(0).Div(dVal).Truncate(2) +} + +// Floor returns the nearest integer value less than or equal to d. +func (d Decimal) Floor() Decimal { + d.ensureInitialized() + + if d.exp >= 0 { + return d + } + + exp := big.NewInt(10) + + // NOTE(vadim): must negate after casting to prevent int32 overflow + exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) + + z := new(big.Int).Div(d.value, exp) + return Decimal{value: z, exp: 0} +} + +// Ceil returns the nearest integer value greater than or equal to d. +func (d Decimal) Ceil() Decimal { + d.ensureInitialized() + + if d.exp >= 0 { + return d + } + + exp := big.NewInt(10) + + // NOTE(vadim): must negate after casting to prevent int32 overflow + exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) + + z, m := new(big.Int).DivMod(d.value, exp, new(big.Int)) + if m.Cmp(zeroInt) != 0 { + z.Add(z, oneInt) + } + return Decimal{value: z, exp: 0} +} + +// Truncate truncates off digits from the number, without rounding. +// +// NOTE: precision is the last digit that will not be truncated (must be >= 0). +// +// Example: +// +// decimal.NewFromString("123.456").Truncate(2).String() // "123.45" +// +func (d Decimal) Truncate(precision int32) Decimal { + d.ensureInitialized() + if precision >= 0 && -precision > d.exp { + return d.rescale(-precision) + } + return d +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error { + if string(decimalBytes) == "null" { + return nil + } + + str, err := unquoteIfQuoted(decimalBytes) + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", decimalBytes, err) + } + + decimal, err := NewFromString(str) + *d = decimal + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", str, err) + } + return nil +} + +// MarshalJSON implements the json.Marshaler interface. +func (d Decimal) MarshalJSON() ([]byte, error) { + var str string + if MarshalJSONWithoutQuotes { + str = d.String() + } else { + str = "\"" + d.String() + "\"" + } + return []byte(str), nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. As a string representation +// is already used when encoding to text, this method stores that string as []byte +func (d *Decimal) UnmarshalBinary(data []byte) error { + // Verify we have at least 4 bytes for the exponent. The GOB encoded value + // may be empty. + if len(data) < 4 { + return fmt.Errorf("error decoding binary %v: expected at least 4 bytes, got %d", data, len(data)) + } + + // Extract the exponent + d.exp = int32(binary.BigEndian.Uint32(data[:4])) + + // Extract the value + d.value = new(big.Int) + if err := d.value.GobDecode(data[4:]); err != nil { + return fmt.Errorf("error decoding binary %v: %s", data, err) + } + + return nil +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (d Decimal) MarshalBinary() (data []byte, err error) { + // Write the exponent first since it's a fixed size + v1 := make([]byte, 4) + binary.BigEndian.PutUint32(v1, uint32(d.exp)) + + // Add the value + var v2 []byte + if v2, err = d.value.GobEncode(); err != nil { + return + } + + // Return the byte array + data = append(v1, v2...) + return +} + +// Scan implements the sql.Scanner interface for database deserialization. +func (d *Decimal) Scan(value interface{}) error { + // first try to see if the data is stored in database as a Numeric datatype + switch v := value.(type) { + + case float32: + *d = NewFromFloat(float64(v)) + return nil + + case float64: + // numeric in sqlite3 sends us float64 + *d = NewFromFloat(v) + return nil + + case int64: + // at least in sqlite3 when the value is 0 in db, the data is sent + // to us as an int64 instead of a float64 ... + *d = New(v, 0) + return nil + + default: + // default is trying to interpret value stored as string + str, err := unquoteIfQuoted(v) + if err != nil { + return err + } + *d, err = NewFromString(str) + return err + } +} + +// Value implements the driver.Valuer interface for database serialization. +func (d Decimal) Value() (driver.Value, error) { + return d.String(), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for XML +// deserialization. +func (d *Decimal) UnmarshalText(text []byte) error { + str := string(text) + + dec, err := NewFromString(str) + *d = dec + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", str, err) + } + + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface for XML +// serialization. +func (d Decimal) MarshalText() (text []byte, err error) { + return []byte(d.String()), nil +} + +// GobEncode implements the gob.GobEncoder interface for gob serialization. +func (d Decimal) GobEncode() ([]byte, error) { + return d.MarshalBinary() +} + +// GobDecode implements the gob.GobDecoder interface for gob serialization. +func (d *Decimal) GobDecode(data []byte) error { + return d.UnmarshalBinary(data) +} + +// StringScaled first scales the decimal then calls .String() on it. +// NOTE: buggy, unintuitive, and DEPRECATED! Use StringFixed instead. +func (d Decimal) StringScaled(exp int32) string { + return d.rescale(exp).String() +} + +func (d Decimal) string(trimTrailingZeros bool) string { + if d.exp >= 0 { + return d.rescale(0).value.String() + } + + abs := new(big.Int).Abs(d.value) + str := abs.String() + + var intPart, fractionalPart string + + // NOTE(vadim): this cast to int will cause bugs if d.exp == INT_MIN + // and you are on a 32-bit machine. Won't fix this super-edge case. + dExpInt := int(d.exp) + if len(str) > -dExpInt { + intPart = str[:len(str)+dExpInt] + fractionalPart = str[len(str)+dExpInt:] + } else { + intPart = "0" + + num0s := -dExpInt - len(str) + fractionalPart = strings.Repeat("0", num0s) + str + } + + if trimTrailingZeros { + i := len(fractionalPart) - 1 + for ; i >= 0; i-- { + if fractionalPart[i] != '0' { + break + } + } + fractionalPart = fractionalPart[:i+1] + } + + number := intPart + if len(fractionalPart) > 0 { + number += "." + fractionalPart + } + + if d.value.Sign() < 0 { + return "-" + number + } + + return number +} + +func (d *Decimal) ensureInitialized() { + if d.value == nil { + d.value = new(big.Int) + } +} + +// Min returns the smallest Decimal that was passed in the arguments. +// +// To call this function with an array, you must do: +// +// Min(arr[0], arr[1:]...) +// +// This makes it harder to accidentally call Min with 0 arguments. +func Min(first Decimal, rest ...Decimal) Decimal { + ans := first + for _, item := range rest { + if item.Cmp(ans) < 0 { + ans = item + } + } + return ans +} + +// Max returns the largest Decimal that was passed in the arguments. +// +// To call this function with an array, you must do: +// +// Max(arr[0], arr[1:]...) +// +// This makes it harder to accidentally call Max with 0 arguments. +func Max(first Decimal, rest ...Decimal) Decimal { + ans := first + for _, item := range rest { + if item.Cmp(ans) > 0 { + ans = item + } + } + return ans +} + +// Sum returns the combined total of the provided first and rest Decimals +func Sum(first Decimal, rest ...Decimal) Decimal { + total := first + for _, item := range rest { + total = total.Add(item) + } + + return total +} + +// Avg returns the average value of the provided first and rest Decimals +func Avg(first Decimal, rest ...Decimal) Decimal { + count := New(int64(len(rest)+1), 0) + sum := Sum(first, rest...) + return sum.Div(count) +} + +// RescalePair rescales two decimals to common exponential value (minimal exp of both decimals) +func RescalePair(d1 Decimal, d2 Decimal) (Decimal, Decimal) { + d1.ensureInitialized() + d2.ensureInitialized() + + if d1.exp == d2.exp { + return d1, d2 + } + + baseScale := min(d1.exp, d2.exp) + if baseScale != d1.exp { + return d1.rescale(baseScale), d2 + } + return d1, d2.rescale(baseScale) +} + +func min(x, y int32) int32 { + if x >= y { + return y + } + return x +} + +func unquoteIfQuoted(value interface{}) (string, error) { + var bytes []byte + + switch v := value.(type) { + case string: + bytes = []byte(v) + case []byte: + bytes = v + default: + return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", + value, value) + } + + // If the amount is quoted, strip the quotes + if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' { + bytes = bytes[1 : len(bytes)-1] + } + return string(bytes), nil +} + +// NullDecimal represents a nullable decimal with compatibility for +// scanning null values from the database. +type NullDecimal struct { + Decimal Decimal + Valid bool +} + +func NewNullDecimal(d Decimal) NullDecimal { + return NullDecimal{ + Decimal: d, + Valid: true, + } +} + +// Scan implements the sql.Scanner interface for database deserialization. +func (d *NullDecimal) Scan(value interface{}) error { + if value == nil { + d.Valid = false + return nil + } + d.Valid = true + return d.Decimal.Scan(value) +} + +// Value implements the driver.Valuer interface for database serialization. +func (d NullDecimal) Value() (driver.Value, error) { + if !d.Valid { + return nil, nil + } + return d.Decimal.Value() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (d *NullDecimal) UnmarshalJSON(decimalBytes []byte) error { + if string(decimalBytes) == "null" { + d.Valid = false + return nil + } + d.Valid = true + return d.Decimal.UnmarshalJSON(decimalBytes) +} + +// MarshalJSON implements the json.Marshaler interface. +func (d NullDecimal) MarshalJSON() ([]byte, error) { + if !d.Valid { + return []byte("null"), nil + } + return d.Decimal.MarshalJSON() +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for XML +// deserialization +func (d *NullDecimal) UnmarshalText(text []byte) error { + str := string(text) + + // check for empty XML or XML without body e.g., + if str == "" { + d.Valid = false + return nil + } + if err := d.Decimal.UnmarshalText(text); err != nil { + d.Valid = false + return err + } + d.Valid = true + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface for XML +// serialization. +func (d NullDecimal) MarshalText() (text []byte, err error) { + if !d.Valid { + return []byte{}, nil + } + return d.Decimal.MarshalText() +} + +// Trig functions + +// Atan returns the arctangent, in radians, of x. +func (d Decimal) Atan() Decimal { + if d.Equal(NewFromFloat(0.0)) { + return d + } + if d.GreaterThan(NewFromFloat(0.0)) { + return d.satan() + } + return d.Neg().satan().Neg() +} + +func (d Decimal) xatan() Decimal { + P0 := NewFromFloat(-8.750608600031904122785e-01) + P1 := NewFromFloat(-1.615753718733365076637e+01) + P2 := NewFromFloat(-7.500855792314704667340e+01) + P3 := NewFromFloat(-1.228866684490136173410e+02) + P4 := NewFromFloat(-6.485021904942025371773e+01) + Q0 := NewFromFloat(2.485846490142306297962e+01) + Q1 := NewFromFloat(1.650270098316988542046e+02) + Q2 := NewFromFloat(4.328810604912902668951e+02) + Q3 := NewFromFloat(4.853903996359136964868e+02) + Q4 := NewFromFloat(1.945506571482613964425e+02) + z := d.Mul(d) + b1 := P0.Mul(z).Add(P1).Mul(z).Add(P2).Mul(z).Add(P3).Mul(z).Add(P4).Mul(z) + b2 := z.Add(Q0).Mul(z).Add(Q1).Mul(z).Add(Q2).Mul(z).Add(Q3).Mul(z).Add(Q4) + z = b1.Div(b2) + z = d.Mul(z).Add(d) + return z +} + +// satan reduces its argument (known to be positive) +// to the range [0, 0.66] and calls xatan. +func (d Decimal) satan() Decimal { + Morebits := NewFromFloat(6.123233995736765886130e-17) // pi/2 = PIO2 + Morebits + Tan3pio8 := NewFromFloat(2.41421356237309504880) // tan(3*pi/8) + pi := NewFromFloat(3.14159265358979323846264338327950288419716939937510582097494459) + + if d.LessThanOrEqual(NewFromFloat(0.66)) { + return d.xatan() + } + if d.GreaterThan(Tan3pio8) { + return pi.Div(NewFromFloat(2.0)).Sub(NewFromFloat(1.0).Div(d).xatan()).Add(Morebits) + } + return pi.Div(NewFromFloat(4.0)).Add((d.Sub(NewFromFloat(1.0)).Div(d.Add(NewFromFloat(1.0)))).xatan()).Add(NewFromFloat(0.5).Mul(Morebits)) +} + +// sin coefficients +var _sin = [...]Decimal{ + NewFromFloat(1.58962301576546568060e-10), // 0x3de5d8fd1fd19ccd + NewFromFloat(-2.50507477628578072866e-8), // 0xbe5ae5e5a9291f5d + NewFromFloat(2.75573136213857245213e-6), // 0x3ec71de3567d48a1 + NewFromFloat(-1.98412698295895385996e-4), // 0xbf2a01a019bfdf03 + NewFromFloat(8.33333333332211858878e-3), // 0x3f8111111110f7d0 + NewFromFloat(-1.66666666666666307295e-1), // 0xbfc5555555555548 +} + +// Sin returns the sine of the radian argument x. +func (d Decimal) Sin() Decimal { + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + if d.Equal(NewFromFloat(0.0)) { + return d + } + // make argument positive but save the sign + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + sign = true + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + // reflect in x axis + if j > 3 { + sign = !sign + j -= 4 + } + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if j == 1 || j == 2 { + w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) + y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) + } else { + y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) + } + if sign { + y = y.Neg() + } + return y +} + +// cos coefficients +var _cos = [...]Decimal{ + NewFromFloat(-1.13585365213876817300e-11), // 0xbda8fa49a0861a9b + NewFromFloat(2.08757008419747316778e-9), // 0x3e21ee9d7b4e3f05 + NewFromFloat(-2.75573141792967388112e-7), // 0xbe927e4f7eac4bc6 + NewFromFloat(2.48015872888517045348e-5), // 0x3efa01a019c844f5 + NewFromFloat(-1.38888888888730564116e-3), // 0xbf56c16c16c14f91 + NewFromFloat(4.16666666666665929218e-2), // 0x3fa555555555554b +} + +// Cos returns the cosine of the radian argument x. +func (d Decimal) Cos() Decimal { + + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + // make argument positive + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + // reflect in x axis + if j > 3 { + sign = !sign + j -= 4 + } + if j > 1 { + sign = !sign + } + + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if j == 1 || j == 2 { + y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) + } else { + w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) + y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) + } + if sign { + y = y.Neg() + } + return y +} + +var _tanP = [...]Decimal{ + NewFromFloat(-1.30936939181383777646e+4), // 0xc0c992d8d24f3f38 + NewFromFloat(1.15351664838587416140e+6), // 0x413199eca5fc9ddd + NewFromFloat(-1.79565251976484877988e+7), // 0xc1711fead3299176 +} +var _tanQ = [...]Decimal{ + NewFromFloat(1.00000000000000000000e+0), + NewFromFloat(1.36812963470692954678e+4), //0x40cab8a5eeb36572 + NewFromFloat(-1.32089234440210967447e+6), //0xc13427bc582abc96 + NewFromFloat(2.50083801823357915839e+7), //0x4177d98fc2ead8ef + NewFromFloat(-5.38695755929454629881e+7), //0xc189afe03cbe5a31 +} + +// Tan returns the tangent of the radian argument x. +func (d Decimal) Tan() Decimal { + + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + if d.Equal(NewFromFloat(0.0)) { + return d + } + + // make argument positive but save the sign + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + sign = true + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if zz.GreaterThan(NewFromFloat(1e-14)) { + w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2])) + x := zz.Add(_tanQ[1]).Mul(zz).Add(_tanQ[2]).Mul(zz).Add(_tanQ[3]).Mul(zz).Add(_tanQ[4]) + y = z.Add(z.Mul(w.Div(x))) + } else { + y = z + } + if j&2 == 2 { + y = NewFromFloat(-1.0).Div(y) + } + if sign { + y = y.Neg() + } + return y +} diff --git a/vendor/github.com/shopspring/decimal/rounding.go b/vendor/github.com/shopspring/decimal/rounding.go new file mode 100644 index 00000000..d4b0cd00 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/rounding.go @@ -0,0 +1,160 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package decimal + +type floatInfo struct { + mantbits uint + expbits uint + bias int +} + +var float32info = floatInfo{23, 8, -127} +var float64info = floatInfo{52, 11, -1023} + +// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely reconstructed. +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + return + } + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // We may see at once that the number is already shortest. + // + // Suppose d is not denormal, so that 2^exp <= d < 10^dp. + // The closest shorter number is at least 10^(dp-nd) away. + // The lower/upper bounds computed below are at distance + // at most 2^(exp-mantbits). + // + // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), + // or equivalently log2(10)*(dp-nd) > exp-mantbits. + // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). + minexp := flt.bias + 1 // minimum possible exponent + if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { + // The number is already shortest. + return + } + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. + upper := new(decimal) + upper.Assign(mant*2 + 1) + upper.Shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. + var mantlo uint64 + var explo int + if mant > 1<= d.nd { + break + } + li := ui - upper.dp + lower.dp + l := byte('0') // lower digit + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] + } + u := byte('0') // upper digit + if ui < upper.nd { + u = upper.d[ui] + } + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding + // down (i.e., and we have reached the final digit of lower). + okdown := l != m || inclusive && li+1 == lower.nd + + switch { + case upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + case upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + case upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } + // Okay to round up if upper has a different digit and either upper + // is inclusive or upper is bigger than the result of rounding up. + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + switch { + case okdown && okup: + d.Round(mi + 1) + return + case okdown: + d.RoundDown(mi + 1) + return + case okup: + d.RoundUp(mi + 1) + return + } + } +} diff --git a/vendor/github.com/webrpc/webrpc/gen/funcmap.go b/vendor/github.com/webrpc/webrpc/gen/funcmap.go index 9a4a690d..dfa35267 100644 --- a/vendor/github.com/webrpc/webrpc/gen/funcmap.go +++ b/vendor/github.com/webrpc/webrpc/gen/funcmap.go @@ -71,5 +71,6 @@ func templateFuncMap(opts map[string]interface{}) map[string]interface{} { "pascalCase": applyStringFunction("pascalCase", textcase.PascalCase), // v0.7.0 "snakeCase": applyStringFunction("snakeCase", textcase.SnakeCase), // v0.7.0 "kebabCase": applyStringFunction("kebabCase", textcase.KebabCase), // v0.7.0 + "replaceAll": strings.ReplaceAll, } } diff --git a/vendor/github.com/webrpc/webrpc/gen/funcmap_types.go b/vendor/github.com/webrpc/webrpc/gen/funcmap_types.go index 7b9b1d64..526edd89 100644 --- a/vendor/github.com/webrpc/webrpc/gen/funcmap_types.go +++ b/vendor/github.com/webrpc/webrpc/gen/funcmap_types.go @@ -14,40 +14,40 @@ func isCoreType(v interface{}) bool { } // Returns true if given type is struct. -func isStructType(v interface{}) (bool, error) { +func isStructType(v interface{}) bool { switch t := v.(type) { case schema.Type: - return t.Kind == "struct", nil + return t.Kind == "struct" case *schema.Type: - return t.Kind == "struct", nil + return t.Kind == "struct" case schema.VarType: - return t.Type == schema.T_Struct, nil + return t.Type == schema.T_Struct case *schema.VarType: if t != nil { - return t.Type == schema.T_Struct, nil + return t.Type == schema.T_Struct } - return false, nil + return false default: - return false, fmt.Errorf("isStructType(): unexpected type %T: %+v", v, v) + return false } } // Returns true if given type is enum. -func isEnumType(v interface{}) (bool, error) { +func isEnumType(v interface{}) bool { switch t := v.(type) { case schema.Type: - return t.Kind == "enum", nil + return t.Kind == "enum" case *schema.Type: - return t.Kind == "enum", nil + return t.Kind == "enum" case schema.VarType: - return t.Struct.Type.Kind == "enum", nil + return t.Struct.Type.Kind == "enum" case *schema.VarType: if t != nil { - return t.Struct.Type.Kind == "enum", nil + return t.Struct.Type.Kind == "enum" } - return false, nil + return false default: - return false, fmt.Errorf("isEnumType(): unexpected type %T: %+v", v, v) + return false } } diff --git a/vendor/github.com/webrpc/webrpc/gen/template_source.go b/vendor/github.com/webrpc/webrpc/gen/template_source.go index 15d213d2..24d36810 100644 --- a/vendor/github.com/webrpc/webrpc/gen/template_source.go +++ b/vendor/github.com/webrpc/webrpc/gen/template_source.go @@ -105,7 +105,7 @@ func (s *TemplateSource) loadRemote() (*template.Template, error) { } } else { // cache remote git - if err := s.cacheTemplates(s.target, sourceFS, cacheFS, cacheDir); err != nil { + if err := s.cacheTemplates(s.target, sourceFS, cacheDir); err != nil { s.CacheRefreshErr = err } } @@ -130,22 +130,27 @@ func (s *TemplateSource) loadRemote() (*template.Template, error) { return tmpl, nil } -func (s *TemplateSource) cacheTemplates(target string, remoteFS, cacheFS http.FileSystem, cacheDir string) error { +func (s *TemplateSource) cacheTemplates(target string, remoteFS http.FileSystem, cacheDir string) error { // create empty cache directory if _, err := os.Stat(cacheDir); os.IsExist(err) { if err := os.RemoveAll(cacheDir); err != nil { return err } } - if err := os.MkdirAll(cacheDir, 0755); err != nil { - return fmt.Errorf("unable to create directory for template cache at %s: %w", cacheDir, err) - } filenames, err := vfspath.Glob(remoteFS, "/*.go.tmpl") if err != nil { return err } + if len(filenames) == 0 { + return fmt.Errorf("no template files were found in target %s", target) + } + + if err := os.MkdirAll(cacheDir, 0755); err != nil { + return fmt.Errorf("unable to create directory for template cache at %s: %w", cacheDir, err) + } + for _, filename := range filenames { data, err := vfsutil.ReadFile(remoteFS, filename) if err != nil { diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/definition_parser.go b/vendor/github.com/webrpc/webrpc/schema/ridl/definition_parser.go index 89dc6301..34bc0e4d 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/definition_parser.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/definition_parser.go @@ -24,5 +24,6 @@ func parserStateDefinition(p *parser) parserState { return parserStateDefinitionValue(&DefinitionNode{ leftNode: newTokenNode(tokens[0]), + comment: parseComments(p.comments, tokens[0].line), }) } diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/enum_parser.go b/vendor/github.com/webrpc/webrpc/schema/ridl/enum_parser.go index 80ab53c9..df532d9e 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/enum_parser.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/enum_parser.go @@ -11,6 +11,7 @@ func parserStateEnumExplicitValue(en *EnumNode, dn *DefinitionNode) parserState return p.stateError(err) } dn.rightNode = newTokenNode(explicitValue) + en.comment = parseComments(p.comments, explicitValue.line) } en.values = append(en.values, dn) @@ -35,6 +36,7 @@ func parserStateEnumDefinition(et *EnumNode) parserState { return parserStateEnumExplicitValue(et, &DefinitionNode{ leftNode: newTokenNode(matches[2]), + comment: parseComments(p.comments, matches[0].line), }) case tokenNewLine, tokenWhitespace: @@ -68,5 +70,6 @@ func parserStateEnum(p *parser) parserState { name: newTokenNode(matches[2]), enumType: newTokenNode(matches[5]), values: []*DefinitionNode{}, + comment: parseComments(p.comments, matches[0].line), }) } diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/parser.go b/vendor/github.com/webrpc/webrpc/schema/ridl/parser.go index 30aadf84..cc4632b5 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/parser.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/parser.go @@ -38,21 +38,23 @@ type parser struct { length int pos int - words chan interface{} + words chan interface{} + comments map[int]string root RootNode } func newParser(src []byte) (*parser, error) { - tokens, err := tokenize(src) + tokens, comments, err := tokenize(src) if err != nil { return nil, err } p := &parser{ - words: make(chan interface{}), - tokens: tokens, - length: len(tokens), + words: make(chan interface{}), + tokens: tokens, + length: len(tokens), + comments: comments, } return p, nil } @@ -104,12 +106,16 @@ func (p *parser) run() error { } func (p *parser) continueUntilEOL() error { + words := []string{} + for { tok := p.cursor() switch tok.tt { case tokenNewLine, tokenEOF: return nil + case tokenWord: + words = append(words, tok.String()) } p.next() @@ -505,3 +511,46 @@ func composedValue(tokens []*token) (*token, error) { col: baseToken.col, }, nil } + +func parseComments(comments map[int]string, currentLine int) string { + iteration := 0 + c := []string{} + + if len(comments) == 0 { + return "" + } + + for ; currentLine >= 0; currentLine-- { + comment, ok := comments[currentLine] + if ok { + c = append(c, comment) + delete(comments, currentLine) + iteration = 0 + + if len(comments) == 0 { + break + } + } + + // if we already found a comment and there is one empty line we don't read more lines + if !ok && len(c) > 0 { + break + } + + // if there are 2 lines of empty space => no comment we don't read more lines + if iteration > 1 { + break + } + + iteration++ + } + + if len(c) > 0 { + // slices.Reverse is introduced with go 1.22 + for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 { + c[i], c[j] = c[j], c[i] + } + } + + return strings.Join(c, "\n") +} diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/parser_node.go b/vendor/github.com/webrpc/webrpc/schema/ridl/parser_node.go index fa554b49..a1f2498e 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/parser_node.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/parser_node.go @@ -138,7 +138,8 @@ type DefinitionNode struct { optional bool - meta []*DefinitionNode + meta []*DefinitionNode + comment string } func (dn DefinitionNode) Meta() []*DefinitionNode { @@ -167,6 +168,8 @@ func (dn DefinitionNode) Optional() bool { return dn.optional } +func (dn DefinitionNode) Comment() string { return dn.comment } + type TokenNode struct { node @@ -226,6 +229,7 @@ type EnumNode struct { name *TokenNode enumType *TokenNode values []*DefinitionNode + comment string } func (en EnumNode) Type() NodeType { @@ -244,11 +248,14 @@ func (en EnumNode) Values() []*DefinitionNode { return en.values } +func (en EnumNode) Comments() string { return en.comment } + type StructNode struct { node - name *TokenNode - fields []*DefinitionNode + name *TokenNode + fields []*DefinitionNode + comment string } func (mn StructNode) Name() *TokenNode { @@ -263,6 +270,8 @@ func (mn *StructNode) Fields() []*DefinitionNode { return mn.fields } +func (mn *StructNode) Comment() string { return mn.comment } + type ErrorNode struct { node @@ -317,6 +326,7 @@ type MethodNode struct { proxy bool + comment string inputs argumentList outputs argumentList } @@ -345,12 +355,14 @@ func (mn *MethodNode) Outputs() []*ArgumentNode { return mn.outputs.arguments } +func (mn *MethodNode) Comment() string { return mn.comment } + type ServiceNode struct { node - name *TokenNode - + name *TokenNode methods []*MethodNode + comment string } func (sn ServiceNode) Type() NodeType { @@ -365,6 +377,8 @@ func (sn ServiceNode) Methods() []*MethodNode { return sn.methods } +func (sn ServiceNode) Comment() string { return sn.comment } + type argumentList struct { stream bool diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/ridl.go b/vendor/github.com/webrpc/webrpc/schema/ridl/ridl.go index 0d964663..57440ea8 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/ridl.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/ridl.go @@ -6,6 +6,7 @@ import ( "io/fs" "path" "strconv" + "strings" "github.com/webrpc/webrpc/schema" ) @@ -128,12 +129,12 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { } for i := range imported.Types { - if isImportAllowed(string(imported.Types[i].Name), members) { + if isImportAllowed(imported.Types[i].Name, members) { s.Types = append(s.Types, imported.Types[i]) } } for i := range imported.Services { - if isImportAllowed(string(imported.Services[i].Name), members) { + if isImportAllowed(imported.Services[i].Name, members) { s.Services = append(s.Services, imported.Services[i]) } } @@ -151,23 +152,26 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { // pushing types (1st pass) for _, line := range q.root.Structs() { s.Types = append(s.Types, &schema.Type{ - Kind: schemaTypeKindStruct, - Name: line.Name().String(), + Kind: schemaTypeKindStruct, + Name: line.Name().String(), + Comments: parseComment(line.Comment()), }) } // pushing services (1st pass) for _, service := range q.root.Services() { - // push service - s.Services = append(s.Services, &schema.Service{ - Name: service.Name().String(), - }) + srv := &schema.Service{ + Name: service.Name().String(), + Comments: parseComment(service.Comment()), + } + + s.Services = append(s.Services, srv) } // enum fields for _, line := range q.root.Enums() { name := line.Name().String() - enumDef := s.GetTypeByName(string(name)) + enumDef := s.GetTypeByName(name) if enumDef == nil { return nil, fmt.Errorf("unexpected error, could not find definition for: %v", name) @@ -186,12 +190,15 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { val = strconv.Itoa(i) } - enumDef.Fields = append(enumDef.Fields, &schema.TypeField{ + elems := &schema.TypeField{ Name: key, TypeExtra: schema.TypeExtra{ Value: val, }, - }) + Comments: parseComment(def.Comment()), + } + + enumDef.Fields = append(enumDef.Fields, elems) } } @@ -235,6 +242,7 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { TypeExtra: schema.TypeExtra{ Optional: def.Optional(), }, + Comments: parseComment(def.Comment()), } for _, meta := range def.Meta() { key, val := meta.Left().String(), meta.Right().String() @@ -251,7 +259,6 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { methods := []*schema.Method{} for _, method := range service.Methods() { - inputs, err := buildArgumentsList(s, method.Inputs()) if err != nil { return nil, err @@ -262,14 +269,17 @@ func (p *Parser) parse() (*schema.WebRPCSchema, error) { return nil, err } - // push method - methods = append(methods, &schema.Method{ + // push m + m := &schema.Method{ Name: method.Name().String(), StreamInput: method.StreamInput(), StreamOutput: method.StreamOutput(), Inputs: inputs, Outputs: outputs, - }) + Comments: strings.FieldsFunc(method.Comment(), func(r rune) bool { return r == '\n' }), + } + + methods = append(methods, m) } serviceDef := s.GetServiceByName(service.Name().String()) @@ -346,3 +356,7 @@ func buildArgumentsList(s *schema.WebRPCSchema, args []*ArgumentNode) ([]*schema return output, nil } + +func parseComment(comment string) []string { + return strings.FieldsFunc(comment, func(r rune) bool { return r == '\n' }) +} diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/service_parser.go b/vendor/github.com/webrpc/webrpc/schema/ridl/service_parser.go index a6b37766..d2e7b14d 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/service_parser.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/service_parser.go @@ -35,8 +35,9 @@ func parseStateServiceMethodDefinition(sn *ServiceNode) parserState { } mn := &MethodNode{ - name: newTokenNode(methodName), - proxy: proxy, + name: newTokenNode(methodName), + proxy: proxy, + comment: parseComments(p.comments, matches[0].line), inputs: argumentList{ stream: streamInput, arguments: []*ArgumentNode{}, @@ -112,7 +113,6 @@ func parserStateServiceMethod(s *ServiceNode) parserState { } func parserStateService(p *parser) parserState { - matches, err := p.match(tokenWord, tokenWhitespace, tokenWord, tokenEOL) if err != nil { return p.stateError(err) @@ -125,5 +125,6 @@ func parserStateService(p *parser) parserState { return parserStateServiceMethod(&ServiceNode{ name: newTokenNode(matches[2]), methods: []*MethodNode{}, + comment: parseComments(p.comments, matches[0].line), }) } diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/struct_parser.go b/vendor/github.com/webrpc/webrpc/schema/ridl/struct_parser.go index 2c48a08e..561703a7 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/struct_parser.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/struct_parser.go @@ -73,6 +73,7 @@ func parserStateStructFieldDefinition(mn *StructNode) parserState { field := &DefinitionNode{ leftNode: newTokenNode(matches[2]), + comment: parseComments(p.comments, matches[0].line), } // ? @@ -137,7 +138,8 @@ func parserStateStruct(p *parser) parserState { } return parserStateStructField(&StructNode{ - name: newTokenNode(matches[2]), - fields: []*DefinitionNode{}, + name: newTokenNode(matches[2]), + fields: []*DefinitionNode{}, + comment: parseComments(p.comments, matches[0].line), }) } diff --git a/vendor/github.com/webrpc/webrpc/schema/ridl/tokenizer.go b/vendor/github.com/webrpc/webrpc/schema/ridl/tokenizer.go index b528eea6..7253cdcf 100644 --- a/vendor/github.com/webrpc/webrpc/schema/ridl/tokenizer.go +++ b/vendor/github.com/webrpc/webrpc/schema/ridl/tokenizer.go @@ -1,15 +1,46 @@ package ridl -func tokenize(src []byte) ([]token, error) { - lx := newLexer(string(src)) +import "strings" +// tokenize +// Returns: +// - []token: A slice containing all the tokens parsed from the source. +// - map[int]string: A map where the key is the line number and the value is the comment present in that line. +// +// This function extracts tokens from it. The comments are associated with the line +// numbers where they occur, providing a convenient map for comment retrieval +func tokenize(src []byte) ([]token, map[int]string, error) { + lx := newLexer(string(src)) tokens := []token{} + lineComments := make(map[int]string) + + commentLine := false + commentTokens := []string{} for tok := range lx.tokens { if tok.tt == tokenEOF { break } + + if commentLine { + if tok.tt != tokenNewLine && tok.tt != tokenWhitespace { + commentTokens = append(commentTokens, tok.String()) + } + } + + if tok.tt == tokenHash { + commentLine = true + } + + if tok.tt == tokenNewLine { + if commentLine { + lineComments[tok.line] = strings.Join(commentTokens, " ") + commentTokens = []string{} + } + commentLine = false + } + tokens = append(tokens, tok) } - return tokens, nil + return tokens, lineComments, nil } diff --git a/vendor/github.com/webrpc/webrpc/schema/schema.go b/vendor/github.com/webrpc/webrpc/schema/schema.go index 6df79a56..1b4deeac 100644 --- a/vendor/github.com/webrpc/webrpc/schema/schema.go +++ b/vendor/github.com/webrpc/webrpc/schema/schema.go @@ -94,7 +94,7 @@ func (s *WebRPCSchema) ToJSON() (string, error) { func (s *WebRPCSchema) GetTypeByName(name string) *Type { name = strings.ToLower(name) for _, message := range s.Types { - if strings.ToLower(string(message.Name)) == name { + if strings.ToLower(message.Name) == name { return message } } @@ -104,7 +104,7 @@ func (s *WebRPCSchema) GetTypeByName(name string) *Type { func (s *WebRPCSchema) GetServiceByName(name string) *Service { name = strings.ToLower(name) for _, service := range s.Services { - if strings.ToLower(string(service.Name)) == name { + if strings.ToLower(service.Name) == name { return service } } diff --git a/vendor/github.com/webrpc/webrpc/schema/service.go b/vendor/github.com/webrpc/webrpc/schema/service.go index e048c366..1e3336f9 100644 --- a/vendor/github.com/webrpc/webrpc/schema/service.go +++ b/vendor/github.com/webrpc/webrpc/schema/service.go @@ -6,14 +6,16 @@ import ( ) type Service struct { - Name string `json:"name"` - Methods []*Method `json:"methods"` + Name string `json:"name"` + Methods []*Method `json:"methods"` + Comments []string `json:"comments"` Schema *WebRPCSchema `json:"-"` // denormalize/back-reference } type Method struct { - Name string `json:"name"` + Name string `json:"name"` + Comments []string `json:"comments"` StreamInput bool `json:"streamInput,omitempty"` StreamOutput bool `json:"streamOutput,omitempty"` diff --git a/vendor/github.com/webrpc/webrpc/schema/type.go b/vendor/github.com/webrpc/webrpc/schema/type.go index 6da01147..484fd268 100644 --- a/vendor/github.com/webrpc/webrpc/schema/type.go +++ b/vendor/github.com/webrpc/webrpc/schema/type.go @@ -17,10 +17,13 @@ type Type struct { Type *VarType `json:"type,omitempty"` Fields []*TypeField `json:"fields,omitempty"` TypeExtra `json:",omitempty"` + Comments []string `json:"comments,omitempty"` } type TypeField struct { - Name string `json:"name"` + Comments []string `json:"comments,omitempty"` + Name string `json:"name"` + Type *VarType `json:"type,omitempty"` TypeExtra `json:",omitempty"` } @@ -126,8 +129,9 @@ func (t *Type) Parse(schema *WebRPCSchema) error { // ensure enum type is one of the allowed types.. aka integer fieldType := t.Type - if !isValidVarType(fieldType.String(), VarIntegerCoreTypes) { - return fmt.Errorf("schema error: enum '%s' field '%s' is invalid. must be an integer type.", t.Name, fieldType.String()) + validCoreTypes := append(VarIntegerCoreTypes, T_String) + if !isValidVarType(fieldType.String(), validCoreTypes) { + return fmt.Errorf("schema error: enum '%s' field '%s' is invalid. must be an integer type", t.Name, fieldType.String()) } } @@ -151,6 +155,17 @@ func (t *Type) Parse(schema *WebRPCSchema) error { return nil } +func (t *Type) RequiredFields() []*TypeField { + requiredFields := make([]*TypeField, 0) + for _, field := range t.Fields { + if !field.Optional { + requiredFields = append(requiredFields, field) + } + } + + return requiredFields +} + func startsWithUpper(s string) bool { if len(s) == 0 { return false diff --git a/vendor/github.com/webrpc/webrpc/schema/var_type.go b/vendor/github.com/webrpc/webrpc/schema/var_type.go index fa116b12..7e6645c3 100644 --- a/vendor/github.com/webrpc/webrpc/schema/var_type.go +++ b/vendor/github.com/webrpc/webrpc/schema/var_type.go @@ -6,8 +6,9 @@ import ( ) type VarType struct { - Expr string // Type, ie. map> or []User - Type CoreType // Kind, ie. int, map or struct + Expr string // Type, ie. map> or []User + Type CoreType // Kind, ie. int, map or struct + Comments []string `json:"comments,omitempty"` List *VarListType Map *VarMapType diff --git a/vendor/github.com/webrpc/webrpc/version.go b/vendor/github.com/webrpc/webrpc/version.go index 7cf151b1..544869dc 100644 --- a/vendor/github.com/webrpc/webrpc/version.go +++ b/vendor/github.com/webrpc/webrpc/version.go @@ -7,4 +7,4 @@ package webrpc // The patch value is automatically updated with the latest git tag in CI. // // Version is available as {{.WebrpcGenVersion}} in generator templates. -var VERSION = "v0.14.0-dev" +var VERSION = "v0.15.2-dev" diff --git a/vendor/modules.txt b/vendor/modules.txt index e2f4b2c2..0b441476 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -36,7 +36,7 @@ github.com/0xsequence/ethkit/util # github.com/0xsequence/go-ethauth v0.13.0 ## explicit; go 1.17 github.com/0xsequence/go-ethauth -# github.com/0xsequence/go-sequence v0.29.0 +# github.com/0xsequence/go-sequence v0.29.2 ## explicit; go 1.21 github.com/0xsequence/go-sequence github.com/0xsequence/go-sequence/contracts @@ -478,6 +478,9 @@ github.com/segmentio/asm/internal/unsafebytes # github.com/sergi/go-diff v1.3.1 ## explicit; go 1.12 github.com/sergi/go-diff/diffmatchpatch +# github.com/shopspring/decimal v1.3.1 +## explicit; go 1.13 +github.com/shopspring/decimal # github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c ## explicit; go 1.19 github.com/shurcooL/httpfs/path/vfspath @@ -511,7 +514,7 @@ github.com/tyler-smith/go-bip39/wordlists github.com/uber-go/tally/v4 github.com/uber-go/tally/v4/internal/identity github.com/uber-go/tally/v4/prometheus -# github.com/webrpc/webrpc v0.14.0 +# github.com/webrpc/webrpc v0.15.2 ## explicit; go 1.16 github.com/webrpc/webrpc github.com/webrpc/webrpc/cmd/webrpc-gen