Module: Solace::Utils::PDA

Included in:
PublicKey
Defined in:
lib/solace/utils/pda.rb

Overview

Module for generating program addresses

This module provides methods for generating program addresses from seeds and program IDs. It interfaces with the Curve25519 Dalek library to check if a point is on the curve. It also provides a method for converting seeds to bytes and a method for checking if a string looks like a base58 address.

See Also:

Since:

  • 0.0.1

Defined Under Namespace

Classes: InvalidPDAError

Constant Summary collapse

PDA_MARKER =

!@attribute PDA_MARKER PDA_MARKER is the marker used in PDA calculations

Since:

  • 0.0.1

'ProgramDerivedAddress'
MAX_BUMP_SEED =

!@attribute MAX_BUMP_SEED The maximum seed value for PDA calculations

Since:

  • 0.0.1

255

Class Method Summary collapse

Class Method Details

.create_program_address(seeds, program_id) ⇒ String

Creates a program address from seeds and program ID

Parameters:

  • seeds (Array)

    The seeds to use in the calculation

  • program_id (String)

    The program ID to use in the calculation

Returns:

  • (String)

    The program address

Raises:

Since:

  • 0.0.1



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/solace/utils/pda.rb', line 57

def self.create_program_address(seeds, program_id)
  seed_bytes = seeds.map { |seed| seed_to_bytes(seed) }.flatten

  program_id_bytes = Solace::Utils::Codecs.base58_to_bytes(program_id)

  combined = seed_bytes + program_id_bytes + PDA_MARKER.bytes

  hash_bin = Digest::SHA256.digest(combined.pack('C*'))

  raise InvalidPDAError if Solace::Utils::Curve25519Dalek.on_curve?(hash_bin)

  Solace::Utils::Codecs.bytes_to_base58(hash_bin.bytes)
end

.find_program_address(seeds, program_id) ⇒ Array

Finds a valid program address by trying different seeds

Examples:

Find a PDA with bump seed

seeds = ['metadata', mint_address, 'edition']
program_id = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'

address, bump = Solace::Utils::PDA.find_program_address(seeds, program_id)

Parameters:

  • seeds (Array)

    The seeds to use in the calculation

  • program_id (String)

    The program ID to use in the calculation

Returns:

  • (Array)

    The program address and bump seed

Raises:

Since:

  • 0.0.1



40
41
42
43
44
45
46
47
48
49
# File 'lib/solace/utils/pda.rb', line 40

def self.find_program_address(seeds, program_id)
  MAX_BUMP_SEED.downto(0) do |bump|
    address = create_program_address(seeds + [bump], program_id)
    return [address, bump]
  rescue InvalidPDAError
    next
  end

  raise 'Unable to find a valid program address'
end

.looks_like_base58_address?(string) ⇒ Boolean

Checks if a string looks like a base58 address

Parameters:

  • string (String)

    The string to check

Returns:

  • (Boolean)

    True if the string looks like a base58 address, false otherwise

Since:

  • 0.0.1



92
93
94
95
# File 'lib/solace/utils/pda.rb', line 92

def self.looks_like_base58_address?(string)
  string.length.between?(32, 44) &&
    Solace::Utils::Codecs.valid_base58?(string)
end

.seed_to_bytes(seed) ⇒ Array

Prepares a list of seeds for creating a program address

Parameters:

  • seed (String, Integer, Array)

    The seed to prepare

Returns:

  • (Array)

    The prepared seeds

Since:

  • 0.0.1



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/solace/utils/pda.rb', line 75

def self.seed_to_bytes(seed)
  case seed
  when String
    looks_like_base58_address?(seed) ? Solace::Utils::Codecs.base58_to_bytes(seed) : seed.bytes
  when Integer
    seed.between?(0, 255) ? [seed] : seed.digits(256)
  when Array
    seed
  else
    seed.to_s.bytes
  end
end