-
Notifications
You must be signed in to change notification settings - Fork 233
Add OZ Relayer docs #2071 #2176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
1 similar comment
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
1 similar comment
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
|
Preview is available here: |
ElliotFriend
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lookin' really good!
left a couple small notes, but i think it's very close!
|
|
||
| ### Prerequisites | ||
|
|
||
| This guide assumes you have deployed the Increment smart contract example code found [here](https://github.com/stellar/soroban-examples/tree/v22.0.1/increment). See the [Getting Started](https://developers.stellar.org/docs/build/smart-contracts/getting-started) tutorial section 3 and 4 for more information about building and deploying the Increment contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's make the Getting Started link a relative one (the kind that's like ../../path/to/file.mdx)
| ```js | ||
| // Poll for transaction result | ||
| let txResponse = await rpc.getTransaction(response.hash!); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think there's something like rpc.pollTransaction() that you could use that takes away the need for the while loop
Co-authored-by: Elliot Voris <elliot@stellar.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive documentation for the OpenZeppelin Relayer (also known as Stellar Channels Service) to the Stellar developer documentation. The documentation replaces the discontinued Launchtube service and provides developers with a managed infrastructure solution for submitting Stellar Soroban transactions with automatic parallel processing and fee management.
Changes:
- Added new documentation page with detailed guides for smart contract invocation and account transfers using OpenZeppelin Relayer
- Integrated OpenZeppelin Relayer into navigation menus, routes, and internationalization files
- Updated tools overview page to include the new relayer service
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/tools/openzeppelin-relayer.mdx | New comprehensive documentation page with code examples for using OpenZeppelin Relayer for contract invocations and token transfers |
| docs/tools/README.mdx | Added OpenZeppelin Relayer section to the tools overview page |
| config/theme/navbar.ts | Added OpenZeppelin Relayer navigation item in the Tools dropdown menu |
| i18n/en/docusaurus-theme-classic/navbar.json | Added internationalization entry for OpenZeppelin Relayer navbar label |
| static/llms.txt | Added OpenZeppelin Relayer link to the developer tools list |
| routes.txt | Added route for the new OpenZeppelin Relayer documentation page |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <label | ||
| htmlFor="amount" | ||
| className="block mb-2.5 text-sm font-medium text-heading" | ||
| >Amount (XML)</label |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The label incorrectly refers to "XML" when it should be "XLM" (the native Stellar token). XML is a markup language, while XLM is the Stellar Lumens cryptocurrency.
| >Amount (XML)</label | |
| >Amount (XLM)</label |
| <input type="text" id="toAddress" name="toAddress" className="bg-neutral-secondary-medium border border-default-medium text-heading text-sm rounded-base focus:ring-brand focus:border-brand block w-full px-3 py-2.5 shadow-xs placeholder:text-body" placeholder="G.........." required /> | ||
| </div> | ||
| <div className="mb-5"> | ||
| <label htmlFor="amount" className="block mb-2.5 text-sm font-medium text-heading">Amount (XML)</label> |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The label incorrectly refers to "XML" when it should be "XLM" (the native Stellar token). XML is a markup language, while XLM is the Stellar Lumens cryptocurrency.
| <label htmlFor="amount" className="block mb-2.5 text-sm font-medium text-heading">Amount (XML)</label> | |
| <label htmlFor="amount" className="block mb-2.5 text-sm font-medium text-heading">Amount (XLM)</label> |
| // Poll for transaction result | ||
| let txResponse = await rpc.getTransaction(response.hash!); | ||
| while (txResponse.status === "NOT_FOUND") { | ||
| await new Promise((r) => setTimeout(r, 2000)); | ||
| txResponse = await rpc.getTransaction(response.hash!); | ||
| } |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The polling loop lacks a timeout mechanism. If the transaction never gets confirmed or fails, this will poll indefinitely. Consider adding a maximum number of retries or a timeout to prevent infinite loops.
| // Poll for transaction result | |
| let txResponse = await rpc.getTransaction(response.hash!); | |
| while (txResponse.status === "NOT_FOUND") { | |
| await new Promise((r) => setTimeout(r, 2000)); | |
| txResponse = await rpc.getTransaction(response.hash!); | |
| } | |
| // Poll for transaction result with a maximum number of attempts to avoid infinite loops | |
| const maxAttempts = 30; // e.g., ~60 seconds total with 2s delay | |
| let attempts = 0; | |
| let txResponse = await rpc.getTransaction(response.hash!); | |
| while (txResponse.status === "NOT_FOUND" && attempts < maxAttempts) { | |
| await new Promise((r) => setTimeout(r, 2000)); | |
| txResponse = await rpc.getTransaction(response.hash!); | |
| attempts++; | |
| } | |
| if (txResponse.status === "NOT_FOUND") { | |
| throw new Error("Transaction could not be confirmed within the expected time."); | |
| } |
| }); | ||
|
|
||
| return response.hash; | ||
| } catch (error) { |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch block simply re-throws the error without adding context or handling. While this may be intentional for demonstration purposes, consider either removing the try-catch entirely or adding meaningful error handling/logging.
| } catch (error) { | |
| } catch (error) { | |
| console.error('Failed to submit Stellar transaction via OpenZeppelin Relayer:', error); |
| // Return the result | ||
| return txResponse.returnValue._value; |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing _value (a private/internal property indicated by the underscore prefix) directly may be fragile and could break with SDK updates. Consider using the proper public API method to extract the return value if available.
| // Return the result | |
| return txResponse.returnValue._value; | |
| // Return the result using the public SDK helper | |
| return StellarSDK.scValToNative(txResponse.returnValue); |
| </div> | ||
| ``` | ||
| 3. The complete code This is the complete code for the client side (frontend): |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This heading should be formatted as a markdown heading (#### 3. The complete code) to maintain consistency with other numbered sections like "#### 1. Call server side function" and "#### 2. Markup code".
| 3. The complete code This is the complete code for the client side (frontend): | |
| #### 3. The complete code | |
| This is the complete code for the client side (frontend): |
| const simulation = await rpc.simulateTransaction(tx); | ||
| const assembled = StellarSDK.rpc.assembleTransaction(tx, simulation).build(); | ||
| // Extract function and auth XDRs | ||
| const op = await assembled.operations[0]; |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The await keyword is unnecessary here since accessing an array element is a synchronous operation. Remove the await keyword as it has no effect and may cause confusion.
| const op = await assembled.operations[0]; | |
| const op = assembled.operations[0]; |
| while (txResponse.status === "NOT_FOUND") { | ||
| await new Promise((r) => setTimeout(r, 2000)); | ||
| txResponse = await rpc.getTransaction(response.hash!); | ||
| } | ||
| // Return the result |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The polling loop only checks for "NOT_FOUND" status but doesn't handle other possible transaction statuses like "FAILED". If the transaction fails, this could result in returning an undefined or incorrect value. Consider adding proper status checking and error handling.
| while (txResponse.status === "NOT_FOUND") { | |
| await new Promise((r) => setTimeout(r, 2000)); | |
| txResponse = await rpc.getTransaction(response.hash!); | |
| } | |
| // Return the result | |
| let attempts = 0; | |
| const maxAttempts = 30; | |
| while (txResponse.status === "NOT_FOUND" && attempts < maxAttempts) { | |
| await new Promise((r) => setTimeout(r, 2000)); | |
| txResponse = await rpc.getTransaction(response.hash!); | |
| attempts += 1; | |
| } | |
| if (txResponse.status !== "SUCCESS") { | |
| throw new Error(`Transaction did not complete successfully. Status: ${txResponse.status}`); | |
| } | |
| // Return the result | |
| if (!txResponse.returnValue || typeof txResponse.returnValue._value === "undefined") { | |
| throw new Error("Transaction completed but no return value was found."); | |
| } |
| const args: [] = []; | ||
| const response = await SendContractTransaction( | ||
| 'GAZQUIHE242WV4CK7LLM5ZV4SM6SLV4CEY4LLAKEYD2O000000000000', | ||
| 'CDAZOG4V2KAPVBBKCAMHUT367AUGYWYEHD652UOJVER5ERNYGSOROBAN', | ||
| "increment", | ||
| [], | ||
| ); |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable args is declared but then an empty array is passed directly to SendContractTransaction instead. This makes the args variable declaration redundant. Consider either using the args variable or removing its declaration.
| } | ||
| ``` | ||
| ### OpenZeppelin Relayer documentation |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section is titled "OpenZeppelin Relayer documentation" at the end of a page already about OpenZeppelin Relayer documentation. The title is redundant and should be more specific, such as "Additional Resources" or "Further Reading".
| ### OpenZeppelin Relayer documentation | |
| ### Additional resources |
|
Preview is available here: |
Adding OpenZeppelin Relayer documentation to the Tools dropdown.