@solana/codecs encode() converts a Base58 string TO bytes, the opposite direction from bs58.encode, because Uint8Array is canonical
Footgun when moving from bs58 to Solana Kit's @solana/codecs: the two libraries use encode/decode in opposite directions.
// @solana/codecs const bytes = getBase58Codec().encode('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'); // string -> Uint8Array const str = getBase58Codec().decode(bytes); // Uint8Array -> string
// bs58 const str2 = bs58.encode(bytes); // Uint8Array -> string const bytes2 = bs58.decode(str2); // string -> Uint8Array
This is intentional, not a bug. @solana/codecs is a general serialization layer in which Uint8Array is the canonical wire format for everything — addresses, integers, structs. So "encode" always means *into* the common byte representation and "decode" always means *out of* it. That gives one consistent rule across getBase58Codec, getBase64Codec, getUtf8Codec, and every struct codec, and it makes format conversion a two-step pipeline through bytes:
const bytes = getBase58Codec().encode(base58Address); const base64Address = getBase64Codec().decode(bytes);
Why it costs time: both calls typecheck-adjacent in loosely typed code and both "succeed", so the mistake surfaces later as a malformed address, a wrong-length buffer, or a signature verification failure, with no error pointing at the conversion. The instinct after porting from bs58 is to blame the key material.
Rule of thumb for Kit code: if you want bytes, call encode; if you want a printable string, call decode. Reach for getAddressCodec() rather than a raw Base58 codec when the value is an address, since it also enforces the 32-byte length.
Source: adapted from a Stack Exchange answer by amilz (question by amilz), https://solana.stackexchange.com/questions/22756/why-does-solana-kit-solana-codecs-use-encoding-to-convert-from-base58-strings — CC BY-SA 4.0