Skip to content

Commit 2ae55ab

Browse files
committed
Merge branch 'main' into init-solana-tests
2 parents 5fa115c + 306ee69 commit 2ae55ab

100 files changed

Lines changed: 2683 additions & 1750 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/brown-icons-push.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@layerzerolabs/hyperliquid-composer": patch
3+
"@layerzerolabs/oft-hyperliquid-example": patch
4+
---
5+
6+
rename FeeAbstraction to PreFundedFeeAbstraction in docs

.github/dependabot.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "npm"
4+
directories:
5+
- "/"
6+
- "/packages/*"
7+
- "/examples/*"
8+
9+
schedule:
10+
interval: "daily"
11+
12+
# Keep at most one open Dependabot PR at a time
13+
open-pull-requests-limit: 1
14+
15+
# Only update this single public package
16+
allow:
17+
- dependency-name: "@layerzerolabs/lz-definitions"
18+
dependency-type: "direct"
19+
20+
# Grouping is redundant with the allow-list, but harmless and keeps naming consistent
21+
groups:
22+
lz-definitions:
23+
patterns:
24+
- "@layerzerolabs/lz-definitions"

.github/workflows/reusable-test.yaml

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,6 @@ jobs:
162162
- name: Setup build cache
163163
uses: ./.github/workflows/actions/setup-build-cache
164164

165-
- name: E2E Test Notice
166-
run: |
167-
echo "::notice::🧪 E2E tests are non-blocking and run against live networks"
168-
echo "::notice::These tests validate real blockchain interactions but may fail due to:"
169-
echo "::notice:: - Network connectivity issues"
170-
echo "::notice:: - RPC rate limiting"
171-
echo "::notice:: - External service downtime"
172-
echo "::notice:: - Gas price fluctuations"
173-
echo "::notice::E2E test failures do NOT block the main CI pipeline"
174-
175165
# There is a small bug in docker compose that will cause 401 if we don't pull the base image manually
176166
#
177167
# See more here https://github.com/docker/compose-cli/issues/1545
@@ -217,34 +207,74 @@ jobs:
217207
with:
218208
path: ./logs
219209

220-
# Post comment on E2E test failure
221-
- name: Comment on E2E failure
222-
if: steps.test-e2e.outcome == 'failure'
210+
# Post comment on E2E test completion (success or failure)
211+
- name: Comment on E2E results
212+
if: always() && steps.test-e2e.outcome != 'skipped' && steps.test-e2e.outcome != 'cancelled'
223213
uses: actions/github-script@v7
224214
with:
225215
script: |
216+
const outcome = '${{ steps.test-e2e.outcome }}';
217+
const emoji = outcome === 'success' ? '✅' : '❌';
218+
const status = outcome === 'success' ? 'Passed' : 'Failed';
219+
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 16) + ' (UTC)';
220+
const runNumber = context.runNumber;
226221
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
227222
const prNumber = context.payload.pull_request?.number;
223+
const header = "## 🧪 E2E Test Status";
224+
225+
const newEntry = `- ${emoji} [Run #${runNumber}](${runUrl}) - ${status} - ${timestamp}`;
228226
229227
if (prNumber) {
230-
const comment = "## 🚨 E2E Tests Failed\n\n" +
231-
"The E2E tests failed during CI. These tests validate real blockchain interactions and may fail due to:\n" +
232-
"- Network connectivity issues\n" +
233-
"- RPC rate limiting\n" +
234-
"- External service downtime\n" +
235-
"**Action Run:** " + runUrl + "\n\n" +
236-
"This is **non-blocking** and does not prevent merging. Check the action logs above for detailed failure information.";
237-
238228
try {
239-
await github.rest.issues.createComment({
240-
issue_number: prNumber,
229+
const { data: comments } = await github.rest.issues.listComments({
241230
owner: context.repo.owner,
242231
repo: context.repo.repo,
243-
body: comment
232+
issue_number: prNumber,
244233
});
234+
235+
const botComment = comments.find(comment =>
236+
comment.user.type === 'Bot' &&
237+
comment.body.includes(header)
238+
);
239+
240+
if (botComment) {
241+
// Extract existing entries
242+
const bodyLines = botComment.body.split('\n');
243+
const runsStartIndex = bodyLines.findIndex(line => line.trim() === '**Test Runs (Newest First):**');
244+
245+
let newBody;
246+
if (runsStartIndex !== -1) {
247+
// Prepend new entry to existing runs (newest first)
248+
const beforeRuns = bodyLines.slice(0, runsStartIndex + 1).join('\n');
249+
const existingRuns = bodyLines.slice(runsStartIndex + 1).join('\n');
250+
newBody = beforeRuns + '\n' + newEntry + '\n' + existingRuns;
251+
} else {
252+
// Shouldn't happen, but handle gracefully
253+
newBody = botComment.body + '\n\n**Test Runs (Newest First):**\n' + newEntry;
254+
}
255+
256+
await github.rest.issues.updateComment({
257+
owner: context.repo.owner,
258+
repo: context.repo.repo,
259+
comment_id: botComment.id,
260+
body: newBody
261+
});
262+
} else {
263+
// Create new comment
264+
const comment = header + "\n\n" +
265+
"E2E tests are non-blocking and validate real blockchain interactions. Failures may occur due to network issues, RPC rate limits, or external service downtime.\n\n" +
266+
"**Test Runs (Newest First):**\n" +
267+
newEntry;
268+
269+
await github.rest.issues.createComment({
270+
issue_number: prNumber,
271+
owner: context.repo.owner,
272+
repo: context.repo.repo,
273+
body: comment
274+
});
275+
}
245276
} catch (error) {
246-
// Silently fail if we don't have permission to comment (e.g., on forks)
247-
console.log('Could not post comment to PR:', error.message);
277+
console.log('Error managing PR comments:', error.message);
248278
}
249279
}
250280

examples/oapp-solana/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @layerzerolabs/oapp-solana-example
22

3+
## 0.2.0
4+
5+
### Minor Changes
6+
7+
- 6c95cd3: migrate oapp-solana to LzReceiveTypesV2
8+
39
## 0.1.5
410

511
### Patch Changes

examples/oapp-solana/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,26 @@ npx hardhat --network arbitrum-sepolia lz:oapp:send --from-eid 40231 --dst-eid 4
299299

300300
Congratulations, you have now successfully set up an EVM <> Solana OApp.
301301

302+
### Viewing Sent Strings
303+
304+
After sending cross-chain messages you can inspect the stored string on either side directly from the terminal:
305+
306+
- Solana store account:
307+
308+
```bash
309+
npx hardhat lz:oapp:solana:debug --eid 40168 --action store
310+
```
311+
312+
Use the Solana endpoint ID that matches your environment (e.g., `40168` for Devnet, `30168` for Mainnet) and optionally pass `--store <STORE_PUBKEY>` if you need to override the derived PDA.
313+
314+
- EVM contract storage:
315+
316+
```bash
317+
npx hardhat lz:oapp:evm:debug --network arbitrum-sepolia --contract-name MyOApp
318+
```
319+
320+
Switch `--network` to the EVM chain you deployed to and supply a different `--contract-name` if your deployment artifact uses another name. The task performs a read-only call to the `data()` getter and prints the latest received message.
321+
302322
### Running tests
303323

304324
The `test` command will execute the hardhat and forge tests:

examples/oapp-solana/layerzero.config.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ const SOLANA_ENFORCED_OPTIONS: OAppEnforcedOption[] = [
3838
// Arbitrum <-> Solana
3939

4040
// With the config generator, pathways declared are automatically bidirectional
41-
// i.e. if you declare A,B there's no need to declare B,A
41+
// i.e. if you declare Arbitrum,Solana there's no need to declare Solana,Arbitrum
4242
const pathways: TwoWayConfig[] = [
4343
[
44-
arbitrumContract, // Chain A contract
45-
solanaContract, // Chain B contract
44+
arbitrumContract, // Arbitrum contract
45+
solanaContract, // Solana contract
4646
[['LayerZero Labs'], []], // [ requiredDVN[], [ optionalDVN[], threshold ] ]
47-
[1, 32], // [A to B confirmations, B to A confirmations]
48-
[SOLANA_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Chain B enforcedOptions, Chain A enforcedOptions
47+
[20, 32], // [Arbitrum to Solana outbound confirmations, Solana to Arbitrum outbound confirmations]
48+
[SOLANA_ENFORCED_OPTIONS, EVM_ENFORCED_OPTIONS], // Arbitrum to Solana enforcedOptions, Solana to Arbitrum enforcedOptions
4949
],
5050
]
5151

examples/oapp-solana/lib/client/generated/my_oapp/accounts/endpointSettings.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ export function getEndpointSettingsAccountDataSerializer(): Serializer<
6464
],
6565
{ description: 'EndpointSettingsAccountData' }
6666
),
67-
(value) => ({
68-
...value,
69-
discriminator: new Uint8Array([221, 232, 73, 56, 10, 66, 72, 14]),
70-
})
67+
(value) => ({ ...value, discriminator: new Uint8Array([221, 232, 73, 56, 10, 66, 72, 14]) })
7168
) as Serializer<EndpointSettingsAccountDataArgs, EndpointSettingsAccountData>
7269
}
7370

@@ -124,7 +121,7 @@ export async function safeFetchAllEndpointSettings(
124121
}
125122

126123
export function getEndpointSettingsGpaBuilder(context: Pick<Context, 'rpc' | 'programs'>) {
127-
const programId = context.programs.getPublicKey('myOapp', 'HFyiETGKEUS9tr87K1HXmVJHkqQRtw8wShRNTMkKKxay')
124+
const programId = context.programs.getPublicKey('myOapp', '')
128125
return gpaBuilder(context, programId)
129126
.registerFields<{
130127
discriminator: Uint8Array

examples/oapp-solana/lib/client/generated/my_oapp/accounts/lzReceiveTypesAccounts.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ import {
2525
mapSerializer,
2626
publicKey as publicKeySerializer,
2727
struct,
28+
u8,
2829
} from '@metaplex-foundation/umi/serializers'
2930

30-
/** LzReceiveTypesAccounts includes accounts that are used in the LzReceiveTypes instruction. */
3131
export type LzReceiveTypesAccounts = Account<LzReceiveTypesAccountsAccountData>
3232

3333
export type LzReceiveTypesAccountsAccountData = {
3434
discriminator: Uint8Array
3535
store: PublicKey
36+
alt: PublicKey
37+
bump: number
3638
}
3739

38-
export type LzReceiveTypesAccountsAccountDataArgs = { store: PublicKey }
40+
export type LzReceiveTypesAccountsAccountDataArgs = { store: PublicKey; alt: PublicKey; bump: number }
3941

4042
export function getLzReceiveTypesAccountsAccountDataSerializer(): Serializer<
4143
LzReceiveTypesAccountsAccountDataArgs,
@@ -46,13 +48,12 @@ export function getLzReceiveTypesAccountsAccountDataSerializer(): Serializer<
4648
[
4749
['discriminator', bytes({ size: 8 })],
4850
['store', publicKeySerializer()],
51+
['alt', publicKeySerializer()],
52+
['bump', u8()],
4953
],
5054
{ description: 'LzReceiveTypesAccountsAccountData' }
5155
),
52-
(value) => ({
53-
...value,
54-
discriminator: new Uint8Array([248, 87, 167, 117, 5, 251, 21, 126]),
55-
})
56+
(value) => ({ ...value, discriminator: new Uint8Array([248, 87, 167, 117, 5, 251, 21, 126]) })
5657
) as Serializer<LzReceiveTypesAccountsAccountDataArgs, LzReceiveTypesAccountsAccountData>
5758
}
5859

@@ -109,16 +110,18 @@ export async function safeFetchAllLzReceiveTypesAccounts(
109110
}
110111

111112
export function getLzReceiveTypesAccountsGpaBuilder(context: Pick<Context, 'rpc' | 'programs'>) {
112-
const programId = context.programs.getPublicKey('myOapp', 'HFyiETGKEUS9tr87K1HXmVJHkqQRtw8wShRNTMkKKxay')
113+
const programId = context.programs.getPublicKey('myOapp', '')
113114
return gpaBuilder(context, programId)
114-
.registerFields<{ discriminator: Uint8Array; store: PublicKey }>({
115+
.registerFields<{ discriminator: Uint8Array; store: PublicKey; alt: PublicKey; bump: number }>({
115116
discriminator: [0, bytes({ size: 8 })],
116117
store: [8, publicKeySerializer()],
118+
alt: [40, publicKeySerializer()],
119+
bump: [72, u8()],
117120
})
118121
.deserializeUsing<LzReceiveTypesAccounts>((account) => deserializeLzReceiveTypesAccounts(account))
119122
.whereField('discriminator', new Uint8Array([248, 87, 167, 117, 5, 251, 21, 126]))
120123
}
121124

122125
export function getLzReceiveTypesAccountsSize(): number {
123-
return 40
126+
return 73
124127
}

examples/oapp-solana/lib/client/generated/my_oapp/accounts/peerConfig.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,7 @@ export type PeerConfigAccountData = {
3131
bump: number
3232
}
3333

34-
export type PeerConfigAccountDataArgs = {
35-
peerAddress: Uint8Array
36-
enforcedOptions: EnforcedOptionsArgs
37-
bump: number
38-
}
34+
export type PeerConfigAccountDataArgs = { peerAddress: Uint8Array; enforcedOptions: EnforcedOptionsArgs; bump: number }
3935

4036
export function getPeerConfigAccountDataSerializer(): Serializer<PeerConfigAccountDataArgs, PeerConfigAccountData> {
4137
return mapSerializer<PeerConfigAccountDataArgs, any, PeerConfigAccountData>(
@@ -48,10 +44,7 @@ export function getPeerConfigAccountDataSerializer(): Serializer<PeerConfigAccou
4844
],
4945
{ description: 'PeerConfigAccountData' }
5046
),
51-
(value) => ({
52-
...value,
53-
discriminator: new Uint8Array([181, 157, 86, 198, 33, 193, 94, 203]),
54-
})
47+
(value) => ({ ...value, discriminator: new Uint8Array([181, 157, 86, 198, 33, 193, 94, 203]) })
5548
) as Serializer<PeerConfigAccountDataArgs, PeerConfigAccountData>
5649
}
5750

@@ -108,7 +101,7 @@ export async function safeFetchAllPeerConfig(
108101
}
109102

110103
export function getPeerConfigGpaBuilder(context: Pick<Context, 'rpc' | 'programs'>) {
111-
const programId = context.programs.getPublicKey('myOapp', 'HFyiETGKEUS9tr87K1HXmVJHkqQRtw8wShRNTMkKKxay')
104+
const programId = context.programs.getPublicKey('myOapp', '')
112105
return gpaBuilder(context, programId)
113106
.registerFields<{
114107
discriminator: Uint8Array

examples/oapp-solana/lib/client/generated/my_oapp/accounts/store.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,7 @@ export type StoreAccountData = {
3939
string: string
4040
}
4141

42-
export type StoreAccountDataArgs = {
43-
admin: PublicKey
44-
bump: number
45-
endpointProgram: PublicKey
46-
string: string
47-
}
42+
export type StoreAccountDataArgs = { admin: PublicKey; bump: number; endpointProgram: PublicKey; string: string }
4843

4944
export function getStoreAccountDataSerializer(): Serializer<StoreAccountDataArgs, StoreAccountData> {
5045
return mapSerializer<StoreAccountDataArgs, any, StoreAccountData>(
@@ -58,10 +53,7 @@ export function getStoreAccountDataSerializer(): Serializer<StoreAccountDataArgs
5853
],
5954
{ description: 'StoreAccountData' }
6055
),
61-
(value) => ({
62-
...value,
63-
discriminator: new Uint8Array([130, 48, 247, 244, 182, 191, 30, 26]),
64-
})
56+
(value) => ({ ...value, discriminator: new Uint8Array([130, 48, 247, 244, 182, 191, 30, 26]) })
6557
) as Serializer<StoreAccountDataArgs, StoreAccountData>
6658
}
6759

@@ -118,7 +110,7 @@ export async function safeFetchAllStore(
118110
}
119111

120112
export function getStoreGpaBuilder(context: Pick<Context, 'rpc' | 'programs'>) {
121-
const programId = context.programs.getPublicKey('myOapp', 'HFyiETGKEUS9tr87K1HXmVJHkqQRtw8wShRNTMkKKxay')
113+
const programId = context.programs.getPublicKey('myOapp', '')
122114
return gpaBuilder(context, programId)
123115
.registerFields<{
124116
discriminator: Uint8Array

0 commit comments

Comments
 (0)