Skip to content

Fix isolated margin ntli encoding#150

Open
boyi wants to merge 4 commits into
sonirico:masterfrom
boyi:fix-update-isolated-margin-ntli-int
Open

Fix isolated margin ntli encoding#150
boyi wants to merge 4 commits into
sonirico:masterfrom
boyi:fix-update-isolated-margin-ntli-int

Conversation

@boyi

@boyi boyi commented May 30, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Description

Brief description of the changes in this PR.

Type of Change

  • [*] Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement

Testing

  • [ *] I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have run make test and all checks pass

Code Quality

  • [* ] My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Generated Code

  • [* ] I have run make generate and committed any generated files
  • Generated files are up to date with struct changes

Breaking Changes

If this is a breaking change, please describe the impact and migration path for existing users:

Screenshots (if applicable)

Add screenshots to help explain your changes.

Additional Notes

Any additional information that would be helpful for reviewers.

Comment thread exchange.go Outdated
return nil
}

func isAPIResponseTarget(result any) bool {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it would change the default behavior.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have to be sure about changes submitted in PRs, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right to push back — it shouldn't exist. I've removed it in 01584b9.

The problem it was papering over: executeAction has seven call sites, and only two of them (UpdateLeverage, UpdateIsolatedMargin) pass a result type that doesn't decode the status envelope. UserState is a plain struct, so {"status":"err","response":"Cannot switch leverage type with open position."} unmarshals into a zero value with err == nil — the caller sees a silent success. The other five call sites pass APIResponse[T], whose UnmarshalJSON already populates Ok/Err and whose callers check it.

So the envelope check is needed for two statically-known call sites, and isAPIResponseTarget was inferring that at runtime. Worse, matching on a type-name prefix isn't a contract: renaming APIResponse would compile fine and silently disable the guard for every caller, and any future APIResponseFoo would match by accident.

Replaced with an explicit split:

  • signAndPost — sign + POST, returns the raw body
  • executeAction — unchanged behavior, for targets that decode the envelope themselves
  • executeActionChecked — runs exchangeActionError first; used only by the two UserState call sites

No behavior change for the five APIResponse[T] call sites, which answers the "would it change the default behavior" question by construction rather than by argument.

I also gave exchangeActionError an exported ExchangeActionError type so callers can errors.As an exchange rejection apart from a transport or decode failure.

Happy to split the refactor into its own PR if you'd rather keep this one scoped to the ntli encoding fix.

boyi and others added 2 commits July 10, 2026 09:06
…iant

executeAction used reflect + a type-name prefix to decide at runtime whether
the caller's result type decodes the {"status":"err"} envelope itself. All
seven call sites are statically known, so split the method instead:

  - signAndPost: sign + POST, returns the raw body
  - executeAction: for APIResponse[T] targets, which decode the envelope
  - executeActionChecked: for targets that don't (UserState)

Matching on a type name is not a contract — renaming APIResponse would have
silently disabled the guard for every caller with no compile error.

Also give exchangeActionError a typed ExchangeActionError so library users can
errors.As a rejected action apart from a transport or decode failure.

No behavior change for the five APIResponse[T] call sites.
Comment thread exchange.go
// exchangeActionError reports the exchange's rejection of an action, or nil if
// the response is not a rejection. A body that does not parse as the envelope
// is left for the caller's json.Unmarshal to reject.
func exchangeActionError(resp []byte) error {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename to parseExchangeActionError

Comment thread exchange.go
if len(envelope.Response) > 0 {
return &ExchangeActionError{Message: string(envelope.Response)}
}
return &ExchangeActionError{Message: "exchange action failed"}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not create structs for errors; Instead, let's use error sentinels

var (
  ErrExchangeAction = errors.New("exchange action failed")
)
// and then in some other place

if len(envelope.Response) > 0 {
		return fmt.Errorf("%w, %s", ErrExchangeAction, envelope.Response)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants