Skip to content

feat(contracts): accept pending lock transfers in LRTP - #1199

Merged
stackman27 merged 8 commits into
mainfrom
sish/accept-pending-transfer-lrtp
Nov 4, 2026
Merged

stackman27 merged 8 commits into
mainfrom
sish/accept-pending-transfer-lrtp

Conversation

@stackman27

Copy link
Copy Markdown
Collaborator

No description provided.

@stackman27
stackman27 marked this pull request as ready for review November 3, 2026 15:04
@stackman27
stackman27 requested a review from a team as a code owner November 3, 2026 15:04
@stackman27 stackman27 changed the title Feat: Accept pending transfer in LRTP feat(contracts): accept pending lock transfers in LRTP Nov 3, 2026
Comment on lines +167 to +196
factoryID, choiceContext, disclosedContracts, err := f.getTransferFactory(ctx, instrumentId, inputHoldingCids, sender, f.poolOwner, poolReceiveMeta)
if err != nil {
return "", splice_api_token_metadata_v1.ChoiceContext{}, nil, err
}

// A named receiver label switches the backend to two-step ("offer") mode,
// which omits the direct-mode context entries and disclosures the offer path
// still requires — merge the direct-mode response in.
if len(poolReceiveMeta) > 0 {
_, directContext, directDisclosures, err := f.getTransferFactory(ctx, instrumentId, inputHoldingCids, sender, f.poolOwner, nil)
if err != nil {
return "", splice_api_token_metadata_v1.ChoiceContext{}, nil, fmt.Errorf("failed to fetch direct-mode context for merge: %w", err)
}
for k, v := range directContext.Values {
if _, ok := choiceContext.Values[k]; !ok {
choiceContext.Values[k] = v
}
}
seen := make(map[string]bool, len(disclosedContracts))
for _, d := range disclosedContracts {
seen[d.ContractId] = true
}
for _, d := range directDisclosures {
if !seen[d.ContractId] {
disclosedContracts = append(disclosedContracts, d)
}
}
}

return factoryID, choiceContext, disclosedContracts, nil

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

2 calls here, The first call asks DA for the context of the actual (labeled) transfer "ccip-public" that's the one we submit.

But DA's offer-mode response only covers the offer step and leaves out pieces the accept step needs (transfer rule, receiver credentials, preapproval), and since we accept in the same transaction, the second call grabs the direct-mode response just to fill those gaps.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, correct me if I'm wrong:

First call, with Metadata -> returns the disclosures for a two-step transfer, but only the disclosures for the offer, not the acceptance
Second call, we intentionally omit the Metadata -> returns the direct mode disclosures (which contain the necessary disclosures for acceptance), but only if the receiver has a Preapproval created?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

that's my understanding as well.

First call (with the label) returns only what creating the offer needs.

Second call (no metadata) returns the direct-transfer response, which includes what the accept needs but DA only serves that if the receiver has a preapproval. Bit of a hack, but it lets us do it in one transaction until their updated endpoint lands.

@stackman27

Copy link
Copy Markdown
Collaborator Author

/auto-fix

@app-token-issuer-integrations

Copy link
Copy Markdown
Contributor

@stackman27
stackman27 merged commit fa58b01 into main Nov 4, 2026
46 checks passed
@stackman27
stackman27 deleted the sish/accept-pending-transfer-lrtp branch November 4, 2026 16:31
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