Module: Solace::Utils::PDA

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

Defined Under Namespace

Classes: InvalidPDAError

Constant Summary collapse

PDA_MARKER =

!@const PDA_MARKER

The marker used in PDA calculations
'ProgramDerivedAddress'
MAX_BUMP_SEED =

!@const MAX_BUMP_SEED

The maximum seed value for PDA calculations
255

Class Method Summary collapse

Class Method Details

.create_program_address(seeds, program_id) ⇒ String

Creates a program address from seeds and program ID

Raises:



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/solace/utils/pda.rb', line 50

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

Raises:



33
34
35
36
37
38
39
40
41
42
# File 'lib/solace/utils/pda.rb', line 33

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



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

def self.looks_like_base58_address?(string)
  string.length >= 32 &&
    string.length <= 44 &&
    Solace::Utils::Codecs.valid_base58?(string)
end

.seed_to_bytes(seed) ⇒ Array

Prepares a list of seeds for creating a program address



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/solace/utils/pda.rb', line 68

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