Skip to content
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

Handle events without contract IDs correctly #172

Merged
merged 5 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/npm_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ jobs:
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 16
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
always-auth: true

- name: Install Depencencies
run: yarn install
Expand All @@ -23,6 +24,9 @@ jobs:
run: yarn preversion

- name: Publish npm package
run: yarn publish
run: |
yarn publish
npm deprecate soroban-client@latest \
"⚠️ This package is now deprecated: transition to `stellar-sdk@beta`, instead! 🚚 All future updates and bug fixes will happen there. Please refer to the migration guide for details on porting your codebase: https://github.com/stellar/js-soroban-client/tree/main/docs/migration.md"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
fail-fast: false
max-parallel: 4
matrix:
node-version: [16, 18, 20]
node-version: [18, 20]

steps:
- name: Checkout
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
A breaking change should be clearly marked in this log.


## Unreleased

### Fixed
* The `Server.getEvents` method now correctly parses responses without a `contractId` field set: the `events[i].contractId` field on an event will be omitted if there was no ID in the event (e.g. for system events; ([#172](https://github.com/stellar/js-soroban-client/pull/172))).
* The `Server.getEvents()` method will correctly parse the event value as an `xdr.ScVal` rather than an `xdr.DiagnosticEvent` ([#172](https://github.com/stellar/js-soroban-client/pull/172)).


## v1.0.0-beta.4

### Fixed
Expand Down
118 changes: 118 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
**This library is deprecated in favor of `stellar-sdk`.**

## Migrating to `stellar-sdk`

This migration guide is focused towards former users of `soroban-client`, but you can refer to the [full migration guide](https://gist.github.com/Shaptic/5ce4f16d9cce7118f391fbde398c2f30/) for more details.

### Why?

Many applications built on Stellar need to utilize both [Horizon](https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-stack#horizon-api) (in order to support Stellar's existing, native functionality and do things like query transaction history, manage DEX offers, etc.) as well as [Soroban RPC](https://soroban.stellar.org/docs/reference/rpc) (in order to interact with smart contracts, retrieve event streams, etc.). By separating support for these two APIs across two SDKs, the applications have unnecessary bloat and code duplication. They both have a unified interface: the protocol XDR (which is abstracted by [`stellar-base`](https://www.npmjs.com/package/stellar-base)), and so it makes sense for a single package to have modules for communicating with either of the interfaces.

If you *just* need Soroban RPC (which is likely the case given that you're in this repository), you can continue to just use those pieces. The only adaptation necessary is updating module references.

### Module Philosophy

All of the abstractions related to Soroban RPC live under the `SorobanRpc` namespace, and the API definitions live under `SorobanRpc.Api`:

```js
// before:
import * as SorobanClient from 'soroban-client';

const s = SorobanClient.Server("...");
const r: SorobanClient.SorobanRpc.GetTransactionResponse = s.getTransaction("...");

// after:
import { SorobanRpc } from 'soroban-client';

const s = SorobanRpc.Server("...");
const r: SorobanRpc.Api.GetTransactionResponse = s.getTransaction("...");
```

All of the _shared_ interfaces, such as those for building operations, dealing with accounts, or touch the XDR in any way (i.e. the fundamental building blocks of the Stellar protocol) still live at the top level. For example,

```js
import {
Account,
TransactionBuilder,
SorobanDataBuilder
} from 'stellar-sdk';
```

(If you've ever imported and used `stellar-base` directly, then this distinction should be clear: anything found in `stellar-base` lives in the top-level module.)

### Migration Details

To migrate, you will need to identify where you are interacting with the RPC server vs. just interacting with the Stellar protocol. Namely,

* `Server` now lives under the `SorobanRpc` submodule
* Soroban helpers such as `assembleTransaction` also live under this submodule
* The API definitions now live in the `SorobanRpc.Api` submodule
* Helpers that are "shared" and have nothing to do with the RPC (like `TransactionBuilder` and `ContractSpec`) are still in the top level

Here's an example before-and-after set of scripts:

Before:

```typescript
import * as SorobanClient from 'soroban-client';

const s = SorobanClient.Server('https://rpc-futurenet.stellar.org');
const kp = SorobanClient.Keypair.random();
const c = new Contract("C...");

async function main() {
return s.getAccount(kp.publicKey()).then(account => {
const tx = new SorobanClient.TransactionBuilder(account, {
fee: BASE_FEE
})
.addOperation(c.call("hello", SorobanClient.scValToNative("world")))
.setNetworkPassphrase(StellarSdk.Networks.FUTURENET)
.setTimeout(30)
.build();

let sim: SorobanClient.SorobanRpc.SimulateTransactionResult;
sim = await s.simulateTransaction(tx);
const readyTx = SorobanClient.assembleTransaction(
tx,
StellarSdk.Networks.FUTURENET,
sim);

readyTx.sign(kp);
return s.submitTransaction(readyTx);
});
}
```

After:

```typescript
import {
Keypair,
Networks,
TransactionBuilder,
Operation,
scValToNative,
SorobanRpc
} from 'stellar-sdk';
const { Api, assembleTransaction } = SorobanRpc;

const s = SorobanRpc.Server('https://horizon-testnet.stellar.org');
const kp = Keypair.random();

async function main() {
return s.getAccount(kp.publicKey()).then(account => {
const tx = new TransactionBuilder(account, { fee: BASE_FEE })
.addOperation(c.call("hello", scValToNative("world")))
.setNetworkPassphrase(Networks.FUTURENET)
.setTimeout(30)
.build();

let sim: Api.SimulateTransactionResult;
sim = await s.simulateTransaction(tx);
const readyTx = assembleTransaction(tx, Networks.FUTURENET, sim);
readyTx.sign(kp);

return s.submitTransaction(readyTx);
});
}
```
12 changes: 9 additions & 3 deletions src/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ export function parseRawEvents(
return {
latestLedger: r.latestLedger,
events: (r.events ?? []).map((evt) => {
const clone: Omit<SorobanRpc.RawEventResponse, 'contractId'> = { ...evt };
delete (clone as any).contractId; // `as any` hack because contractId field isn't optional

// the contractId may be empty so we omit the field in that case
return {
...evt,
contractId: new Contract(evt.contractId),
...clone,
...(evt.contractId !== '' && {
contractId: new Contract(evt.contractId)
}),
topic: evt.topic.map((topic) => xdr.ScVal.fromXDR(topic, 'base64')),
value: xdr.DiagnosticEvent.fromXDR(evt.value.xdr, 'base64')
value: xdr.ScVal.fromXDR(evt.value.xdr, 'base64')
};
})
};
Expand Down
6 changes: 3 additions & 3 deletions src/soroban_rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ export namespace SorobanRpc {
}

interface EventResponse extends BaseEventResponse {
contractId: Contract;
contractId?: Contract;
topic: xdr.ScVal[];
value: xdr.DiagnosticEvent;
value: xdr.ScVal;
}

export interface RawGetEventsResponse {
Expand All @@ -165,7 +165,7 @@ export namespace SorobanRpc {
inSuccessfulContractCall: boolean;
}

interface RawEventResponse extends BaseEventResponse {
export interface RawEventResponse extends BaseEventResponse {
contractId: string;
topic: string[];
value: {
Expand Down
Loading