Skip to content

Fix: pass session key instead of full authority data in Ed25519SessionAuthority methods - #117

Open
wirewallet-jeremy wants to merge 5 commits into
anagrambuild:mainfrom
wirewallet-jeremy:jeremy/bugfix/invalid-public-key-byte-length
Open

Fix: pass session key instead of full authority data in Ed25519SessionAuthority methods#117
wirewallet-jeremy wants to merge 5 commits into
anagrambuild:mainfrom
wirewallet-jeremy:jeremy/bugfix/invalid-public-key-byte-length

Conversation

@wirewallet-jeremy

Copy link
Copy Markdown

I hit this trying to use the SDK to create sub-accounts under a Swig smart wallet.

Stacktrace

Error: Invalid PublicKey byte length. Lenght is 80, not 32 bytes
    at new _class (@swig-wallet/lib/dist/index.cjs:37:13)
    at Object.subAccountCreateV1Instruction (@swig-wallet/lib/dist/index.cjs:2405:23)
    at _Ed25519SessionAuthority.subAccountCreate (@swig-wallet/lib/dist/index.cjs:4080:31)
    at async getCreateSubAccountInstructions (@swig-wallet/classic/dist/index.cjs:164:19)

This attempts to fix the issue where the SDK's _Ed25519SessionAuthority.subAccountCreate passes the full 80-byte authority data to new PublicKey(), which expects 32 bytes and crashes with 'Invalid PublicKey byte length. Length is 80, not 32 bytes.'

Instead of passing the entire 80-byte serialized authority struct, just pass the 32 byte session key.

Script which should reproduce the issue:

import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import {
  fetchSwig,
  getCreateSubAccountInstructions,
  getCreateSwigInstructionBuilder,
  createEd25519AuthorityInfo,
  createEd25519SessionAuthorityInfo,
  ActionsBuilder,
  findSwigPda,
} from "@swig-wallet/classic";

// Create a Swig with root (Ed25519) + session (Ed25519Session) authorities
const rootActions = ActionsBuilder.new().all().manageAuthority().subAccount().get();
const sessionActions = ActionsBuilder.new().solLimit({ amount: 100000000n }).subAccount().get();

const swigId = new Uint8Array(32);
crypto.getRandomValues(swigId);

const rootAuthInfo = createEd25519AuthorityInfo(rootKeypair.publicKey.toBase58());
const sessionAuthInfo = createEd25519SessionAuthorityInfo(
  sessionKeypair.publicKey.toBase58(),
  1512000n, // ~7 days in slots
);

const builder = getCreateSwigInstructionBuilder({
  payer: rootKeypair.publicKey,
  swigAddress: findSwigPda(swigId),
  id: swigId,
  actions: rootActions,
  authorityInfo: rootAuthInfo,
  options: { signingFn },
});
builder.addAuthority(sessionAuthInfo, sessionActions);
// ... submit transaction, Swig created successfully with 2 roles ...

// Now try to create a sub-account for role 1 (Ed25519Session):
const swig = await fetchSwig(connection, swigAddress);
const instructions = await getCreateSubAccountInstructions(swig, 1, {
  payer: sessionKeypair.publicKey,
  signingFn: sessionSigningFn,
});
// ^ THROWS: Invalid PublicKey byte length. Length is 80, not 32 bytes

@wirewallet-jeremy wirewallet-jeremy changed the title Pass session key instead of full authority data in Ed25519SessionAuthority methods Fix: pass session key instead of full authority data in Ed25519SessionAuthority methods Mar 9, 2026

@tracy-codes tracy-codes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

overall this LGTM. can you please add some regression tests just to ensure this never pops up again in the future?

{
roleId: args.roleId,
authorityData: this.data,
authorityData: this.sessionKey.toBytes(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we add a regression test for this exact path?

please cover Ed25519 session authority + getCreateSubAccountInstructionContext(...) (or classic getCreateSubAccountInstructions(...)) and assert it no longer throws Invalid PublicKey byte length and successfully creates the sub-account PDA.

actingRoleId: args.actingRoleId,
actions: args.actions.bytes(),
authorityData: this.data,
authorityData: this.sessionKey.toBytes(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

since this PR updates multiple Ed25519 session methods from this.data (80-byte struct) to this.sessionKey.toBytes() (32-byte key), can we add one manage-authority regression test as well (e.g. add-authority via session role) to lock this behavior in?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Absolutely, I will add some tests soon!

{
roleId: args.roleId,
authorityData: this.data,
authorityData: this.sessionKey.toBytes(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Oh yes. Thanks for this! Although, these should be .id() or address() with the new methods. not .sessionKey.toBytes(). Nice catch

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@thewuhxyz - Let me know if I'm wrong, but I'm seeing this.id -> this.info.publicKey. this.address -> this.ed25519PublicKey, and this.signer -> this.sessionKey.toBytes(). Should we be using this.signer here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this.signer is just for instructions that sign, like subAccountSign and sign, this.id/address should be used for other instruction, mostly.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ok switched 'em all over to this.id. Let me know how it looks.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@thewuhxyz - any other changes you'd like to see in this PR? Thanks for looking!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good to me. Just wondering the cause of the hiccup in CI

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'm not sure, do you think it's related to my changes?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I reverted the last commit to see if it would address the failing tests. Can add back if necessary, lmk

@wirewallet-jeremy
wirewallet-jeremy force-pushed the jeremy/bugfix/invalid-public-key-byte-length branch 2 times, most recently from 1c6295f to d6bf6c2 Compare March 20, 2026 20:23
@edo-chan
edo-chan requested a review from tracy-codes April 20, 2026 16:42
@tracy-codes

Copy link
Copy Markdown
Contributor

@wirewallet-jeremy please rebase your fork against latest main here and push up, some changes to CI were made to support solana v3.x.x. that should trigger the action to run again and pass

@wirewallet-jeremy

Copy link
Copy Markdown
Author

@wirewallet-jeremy please rebase your fork against latest main here and push up, some changes to CI were made to support solana v3.x.x. that should trigger the action to run again and pass

Will do @tracy-codes. Thanks for looking!

… passes the full 80-byte authority data to `new PublicKey()`, which expects 32 bytes and crashes with 'Invalid PublicKey byte length. Length is 80, not 32 bytes.'

Instead of passing the entire 80-byte serialized authority struct, just pass the 32 byte session key.
* session authority can create sub-account after session activation
* session authority builds addAuthority instruction without byte-length error
@wirewallet-jeremy
wirewallet-jeremy force-pushed the jeremy/bugfix/invalid-public-key-byte-length branch from d6bf6c2 to 07e6313 Compare April 20, 2026 19:06
@wirewallet-jeremy
wirewallet-jeremy force-pushed the jeremy/bugfix/invalid-public-key-byte-length branch from 2282f11 to 5e15268 Compare April 20, 2026 21:06
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.

3 participants