solace-zar-trustless-escrow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. checksums.yaml +7 -0
  2. data/lib/solace/zar_trustless_escrow/codecs_extensions.rb +101 -0
  3. data/lib/solace/zar_trustless_escrow/composers/claim_composer.rb +136 -0
  4. data/lib/solace/zar_trustless_escrow/composers/deposit_composer.rb +145 -0
  5. data/lib/solace/zar_trustless_escrow/composers/mediated_deposit_composer.rb +173 -0
  6. data/lib/solace/zar_trustless_escrow/composers/mediated_reclaim_composer.rb +137 -0
  7. data/lib/solace/zar_trustless_escrow/composers/mediated_release_composer.rb +157 -0
  8. data/lib/solace/zar_trustless_escrow/composers/reclaim_composer.rb +135 -0
  9. data/lib/solace/zar_trustless_escrow/composers/token_account_init_composer.rb +88 -0
  10. data/lib/solace/zar_trustless_escrow/constants.rb +47 -0
  11. data/lib/solace/zar_trustless_escrow/errors/program_error.rb +30 -0
  12. data/lib/solace/zar_trustless_escrow/errors.rb +104 -0
  13. data/lib/solace/zar_trustless_escrow/instructions/claim_instruction.rb +60 -0
  14. data/lib/solace/zar_trustless_escrow/instructions/deposit_instruction.rb +65 -0
  15. data/lib/solace/zar_trustless_escrow/instructions/mediated_deposit_instruction.rb +74 -0
  16. data/lib/solace/zar_trustless_escrow/instructions/mediated_reclaim_instruction.rb +60 -0
  17. data/lib/solace/zar_trustless_escrow/instructions/mediated_release_instruction.rb +65 -0
  18. data/lib/solace/zar_trustless_escrow/instructions/reclaim_instruction.rb +60 -0
  19. data/lib/solace/zar_trustless_escrow/instructions/token_account_init_instruction.rb +48 -0
  20. data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow/escrow_deposit_operations.rb +243 -0
  21. data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow/mediated_escrow_deposit_operations.rb +259 -0
  22. data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow.rb +148 -0
  23. data/lib/solace/zar_trustless_escrow/types/escrow_deposit.rb +44 -0
  24. data/lib/solace/zar_trustless_escrow/types/mediated_escrow_deposit.rb +50 -0
  25. data/lib/solace/zar_trustless_escrow/version.rb +7 -0
  26. data/lib/solace/zar_trustless_escrow.rb +38 -0
  27. metadata +171 -0
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Programs
5
+ class ZarTrustlessEscrow < Base
6
+ # Three-party mediated escrow operations for
7
+ # {Solace::Programs::ZarTrustlessEscrow}: deposit, release, and reclaim
8
+ # against the MediatedEscrowDeposit account. Mixed into the program client;
9
+ # methods run in the client's instance context (connection, program_id, and
10
+ # the get_*_address derivations are available). The per-mint vault setup
11
+ # (token_account_init) is shared across escrow types and lives on the client
12
+ # itself, not here.
13
+ module MediatedEscrowDepositOperations
14
+ # Fetches and deserializes the MediatedEscrowDeposit account at the given
15
+ # address. Derive the address first with {#get_mediated_escrow_deposit_address}.
16
+ #
17
+ # @param address [#to_s] Base58 address of the MediatedEscrowDeposit account.
18
+ # @return [Solace::ZarTrustlessEscrow::MediatedEscrowDeposit] The deserialized deposit.
19
+ # @raise [RuntimeError] If no account exists at the address.
20
+ def fetch_mediated_escrow_deposit(address:)
21
+ account = connection.get_account_info(address.to_s)
22
+ raise "MediatedEscrowDeposit account not found at #{address}" unless account
23
+
24
+ Solace::ZarTrustlessEscrow::MediatedEscrowDeposit.deserialize(
25
+ Solace::Utils::Codecs.base64_to_bytestream(account['data'][0])
26
+ )
27
+ end
28
+
29
+ # Returns whether a MediatedEscrowDeposit account exists at the given
30
+ # address. Derive the address first with {#get_mediated_escrow_deposit_address}.
31
+ #
32
+ # @param address [#to_s] Base58 address of the MediatedEscrowDeposit account.
33
+ # @return [Boolean] True if an account exists at the address.
34
+ def mediated_escrow_deposit_exists?(address:)
35
+ !connection.get_account_info(address.to_s).nil?
36
+ end
37
+
38
+ # Deposits funds into a three-party mediated escrow, signs, and
39
+ # (optionally) sends it. The depositor and fee payer sign.
40
+ #
41
+ # @param payer [Solace::Keypair] The fee payer (signs).
42
+ # @param depositor [Solace::Keypair] The depositor (signs).
43
+ # @param sign [Boolean] Whether to sign the transaction.
44
+ # @param execute [Boolean] Whether to send the transaction.
45
+ # @param composer_opts [Hash] Options for {#compose_mediated_deposit}.
46
+ # @return [Solace::Transaction] The created or sent transaction.
47
+ def mediated_deposit(payer:, depositor:, sign: true, execute: true, **composer_opts)
48
+ composer = compose_mediated_deposit(fee_payer: payer, depositor:, **composer_opts)
49
+
50
+ yield composer if block_given?
51
+
52
+ tx = composer
53
+ .set_fee_payer(payer)
54
+ .compose_transaction
55
+
56
+ if sign
57
+ tx.sign(payer, depositor)
58
+
59
+ connection.send_transaction(tx.serialize) if execute
60
+ end
61
+
62
+ tx
63
+ end
64
+
65
+ # Prepares a mediated-deposit transaction. Derives the MediatedEscrowDeposit
66
+ # PDA, the program vault, and the depositor's associated token account.
67
+ #
68
+ # @param mint [#to_s] Mint of the escrowed tokens.
69
+ # @param depositor [#to_s, Keypair] The depositor.
70
+ # @param id [#to_s] Unique id used to derive the escrow PDA.
71
+ # @param mediator [#to_s] Mediator who decides the outcome.
72
+ # @param beneficiary [#to_s] Beneficiary the mediator may release to.
73
+ # @param amount [Integer] u64 amount to deposit.
74
+ # @param fee_payer [#to_s, Keypair] The fee payer (writable signer).
75
+ # @param rent_collector [#to_s] (Optional) Rent collector on close (default: nil).
76
+ # @param expires_at [Integer] (Optional) Unix timestamp for depositor reclaim (default: nil).
77
+ # @param token_program_id [String] Token program that owns the mint (default: legacy SPL Token).
78
+ # @return [Solace::TransactionComposer] A composer with the mediated-deposit instruction.
79
+ def compose_mediated_deposit(
80
+ mint:,
81
+ depositor:,
82
+ id:,
83
+ mediator:,
84
+ beneficiary:,
85
+ amount:,
86
+ fee_payer:,
87
+ rent_collector: nil,
88
+ expires_at: nil,
89
+ token_program_id: Solace::Constants::TOKEN_PROGRAM_ID
90
+ )
91
+ mediated_escrow_deposit, = get_mediated_escrow_deposit_address(id:)
92
+ program_token_account, = get_vault_address(mint:)
93
+ depositor_token_account, = Solace::Programs::AssociatedTokenAccount.get_address(
94
+ owner: depositor,
95
+ mint:,
96
+ token_program_id:
97
+ )
98
+
99
+ ix = Composers::ZarTrustlessEscrowMediatedDepositComposer.new(
100
+ mint:,
101
+ depositor:,
102
+ depositor_token_account:,
103
+ mediated_escrow_deposit:,
104
+ program_token_account:,
105
+ fee_payer:,
106
+ amount:,
107
+ id:,
108
+ mediator:,
109
+ beneficiary:,
110
+ rent_collector:,
111
+ expires_at:,
112
+ program_id:,
113
+ token_program_id:
114
+ )
115
+
116
+ TransactionComposer.new(connection:).add_instruction(ix)
117
+ end
118
+
119
+ # Releases a mediated escrow on behalf of the mediator, signs, and
120
+ # (optionally) sends it. The mediator and fee payer sign.
121
+ #
122
+ # @param payer [Solace::Keypair] The fee payer (signs).
123
+ # @param mediator [Solace::Keypair] The mediator (signs).
124
+ # @param sign [Boolean] Whether to sign the transaction.
125
+ # @param execute [Boolean] Whether to send the transaction.
126
+ # @param composer_opts [Hash] Options for {#compose_mediated_release}.
127
+ # @return [Solace::Transaction] The created or sent transaction.
128
+ def mediated_release(payer:, mediator:, sign: true, execute: true, **composer_opts)
129
+ composer = compose_mediated_release(fee_payer: payer, mediator:, **composer_opts)
130
+
131
+ yield composer if block_given?
132
+
133
+ tx = composer
134
+ .set_fee_payer(payer)
135
+ .compose_transaction
136
+
137
+ if sign
138
+ tx.sign(payer, mediator)
139
+
140
+ connection.send_transaction(tx.serialize) if execute
141
+ end
142
+
143
+ tx
144
+ end
145
+
146
+ # Prepares a mediated-release transaction. Derives the MediatedEscrowDeposit
147
+ # PDA, the program vault, and the recipient's associated token account.
148
+ #
149
+ # @param mint [#to_s] Mint of the escrowed tokens.
150
+ # @param mediator [#to_s, Keypair] The mediator releasing the funds.
151
+ # @param recipient [#to_s] Depositor or beneficiary receiving the tokens.
152
+ # @param rent_collector [#to_s] Account that receives the closed-account rent.
153
+ # @param id [#to_s] Unique id used to derive the escrow PDA.
154
+ # @param fee_payer [#to_s, Keypair] The fee payer (writable signer).
155
+ # @param token_program_id [String] Token program that owns the mint (default: legacy SPL Token).
156
+ # @return [Solace::TransactionComposer] A composer with the mediated-release instruction.
157
+ def compose_mediated_release(
158
+ mint:,
159
+ mediator:,
160
+ recipient:,
161
+ rent_collector:,
162
+ id:,
163
+ fee_payer:,
164
+ token_program_id: Solace::Constants::TOKEN_PROGRAM_ID
165
+ )
166
+ mediated_escrow_deposit, = get_mediated_escrow_deposit_address(id:)
167
+ program_token_account, = get_vault_address(mint:)
168
+ recipient_token_account, = Solace::Programs::AssociatedTokenAccount.get_address(
169
+ owner: recipient,
170
+ mint:,
171
+ token_program_id:
172
+ )
173
+
174
+ ix = Composers::ZarTrustlessEscrowMediatedReleaseComposer.new(
175
+ mint:,
176
+ mediator:,
177
+ recipient:,
178
+ recipient_token_account:,
179
+ mediated_escrow_deposit:,
180
+ program_token_account:,
181
+ rent_collector:,
182
+ fee_payer:,
183
+ id:,
184
+ program_id:,
185
+ token_program_id:
186
+ )
187
+
188
+ TransactionComposer.new(connection:).add_instruction(ix)
189
+ end
190
+
191
+ # Reclaims an expired mediated escrow as the depositor, signs, and
192
+ # (optionally) sends it. The depositor and fee payer sign.
193
+ #
194
+ # @param payer [Solace::Keypair] The fee payer (signs).
195
+ # @param depositor [Solace::Keypair] The depositor (signs, receives tokens and rent).
196
+ # @param sign [Boolean] Whether to sign the transaction.
197
+ # @param execute [Boolean] Whether to send the transaction.
198
+ # @param composer_opts [Hash] Options for {#compose_mediated_reclaim}.
199
+ # @return [Solace::Transaction] The created or sent transaction.
200
+ def mediated_reclaim(payer:, depositor:, sign: true, execute: true, **composer_opts)
201
+ composer = compose_mediated_reclaim(fee_payer: payer, depositor:, **composer_opts)
202
+
203
+ yield composer if block_given?
204
+
205
+ tx = composer
206
+ .set_fee_payer(payer)
207
+ .compose_transaction
208
+
209
+ if sign
210
+ tx.sign(payer, depositor)
211
+
212
+ connection.send_transaction(tx.serialize) if execute
213
+ end
214
+
215
+ tx
216
+ end
217
+
218
+ # Prepares a mediated-reclaim transaction. Derives the MediatedEscrowDeposit
219
+ # PDA, the program vault, and the depositor's associated token account.
220
+ #
221
+ # @param mint [#to_s] Mint of the escrowed tokens.
222
+ # @param depositor [#to_s, Keypair] The depositor (receives the tokens and rent).
223
+ # @param id [#to_s] Unique id used to derive the escrow PDA.
224
+ # @param fee_payer [#to_s, Keypair] The fee payer (writable signer).
225
+ # @param token_program_id [String] Token program that owns the mint (default: legacy SPL Token).
226
+ # @return [Solace::TransactionComposer] A composer with the mediated-reclaim instruction.
227
+ def compose_mediated_reclaim(
228
+ mint:,
229
+ depositor:,
230
+ id:,
231
+ fee_payer:,
232
+ token_program_id: Solace::Constants::TOKEN_PROGRAM_ID
233
+ )
234
+ mediated_escrow_deposit, = get_mediated_escrow_deposit_address(id:)
235
+ program_token_account, = get_vault_address(mint:)
236
+ depositor_token_account, = Solace::Programs::AssociatedTokenAccount.get_address(
237
+ owner: depositor,
238
+ mint:,
239
+ token_program_id:
240
+ )
241
+
242
+ ix = Composers::ZarTrustlessEscrowMediatedReclaimComposer.new(
243
+ mint:,
244
+ depositor:,
245
+ depositor_token_account:,
246
+ mediated_escrow_deposit:,
247
+ program_token_account:,
248
+ fee_payer:,
249
+ id:,
250
+ program_id:,
251
+ token_program_id:
252
+ )
253
+
254
+ TransactionComposer.new(connection:).add_instruction(ix)
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'zar_trustless_escrow/escrow_deposit_operations'
4
+ require_relative 'zar_trustless_escrow/mediated_escrow_deposit_operations'
5
+
6
+ module Solace
7
+ module Programs
8
+ # High-level client for the ZAR Trustless Escrow program.
9
+ #
10
+ # Provides PDA derivation (class methods), account fetching, the shared vault
11
+ # setup, and a compose/send pair per instruction. The instruction operations
12
+ # live in two mixins included below, split by escrow type:
13
+ # - {EscrowDepositOperations} — two-party escrow (deposit/claim/reclaim).
14
+ # - {MediatedEscrowDepositOperations} — three-party mediated escrow.
15
+ #
16
+ # @example
17
+ # program = Solace::Programs::ZarTrustlessEscrow.new(connection:)
18
+ # vault, = program.get_vault_address(mint: mint_address)
19
+ class ZarTrustlessEscrow < Base
20
+ include EscrowDepositOperations
21
+ include MediatedEscrowDepositOperations
22
+
23
+ class << self
24
+ # Derives the EscrowDeposit PDA for a claim authority, from the on-chain
25
+ # seeds ["escrow_deposit", claim_authority].
26
+ #
27
+ # @param claim_authority [#to_s] Base58 authority that can claim the deposit.
28
+ # @param program_id [#to_s] The escrow program id (default: mainnet PROGRAM_ID).
29
+ # @return [Array<String, Integer>] The escrow deposit address and bump seed.
30
+ def get_escrow_deposit_address(claim_authority:, program_id: Solace::ZarTrustlessEscrow::PROGRAM_ID)
31
+ Solace::Utils::PDA.find_program_address(
32
+ [Solace::ZarTrustlessEscrow::ESCROW_DEPOSIT_SEED, claim_authority.to_s],
33
+ program_id.to_s
34
+ )
35
+ end
36
+
37
+ # Derives the MediatedEscrowDeposit PDA for an id, from the on-chain seeds
38
+ # ["mediated_escrow_deposit", id].
39
+ #
40
+ # @param id [#to_s] Base58 unique id the escrow was created with.
41
+ # @param program_id [#to_s] The escrow program id (default: mainnet PROGRAM_ID).
42
+ # @return [Array<String, Integer>] The mediated escrow deposit address and bump seed.
43
+ def get_mediated_escrow_deposit_address(id:, program_id: Solace::ZarTrustlessEscrow::PROGRAM_ID)
44
+ Solace::Utils::PDA.find_program_address(
45
+ [Solace::ZarTrustlessEscrow::MEDIATED_ESCROW_DEPOSIT_SEED, id.to_s],
46
+ program_id.to_s
47
+ )
48
+ end
49
+
50
+ # Derives the per-mint program vault PDA, from the on-chain seeds
51
+ # ["vault", mint]. A single vault is shared across all deposits for a mint.
52
+ #
53
+ # @param mint [#to_s] Base58 mint the vault holds.
54
+ # @param program_id [#to_s] The escrow program id (default: mainnet PROGRAM_ID).
55
+ # @return [Array<String, Integer>] The vault address and bump seed.
56
+ def get_vault_address(mint:, program_id: Solace::ZarTrustlessEscrow::PROGRAM_ID)
57
+ Solace::Utils::PDA.find_program_address(
58
+ [Solace::ZarTrustlessEscrow::VAULT_SEED, mint.to_s],
59
+ program_id.to_s
60
+ )
61
+ end
62
+ end
63
+
64
+ # Initializes a new ZAR Trustless Escrow client.
65
+ #
66
+ # @param connection [Solace::Connection] The connection to the Solana cluster.
67
+ # @param program_id [String] The escrow program id (default: mainnet PROGRAM_ID).
68
+ def initialize(connection:, program_id: Solace::ZarTrustlessEscrow::PROGRAM_ID)
69
+ super
70
+ end
71
+
72
+ # Alias for the class method, defaulting to this client's program id.
73
+ #
74
+ # @param options [Hash] Options for the get_escrow_deposit_address class method.
75
+ # @return [Array<String, Integer>] The escrow deposit address and bump seed.
76
+ def get_escrow_deposit_address(**options)
77
+ self.class.get_escrow_deposit_address(program_id:, **options)
78
+ end
79
+
80
+ # Alias for the class method, defaulting to this client's program id.
81
+ #
82
+ # @param options [Hash] Options for the get_mediated_escrow_deposit_address class method.
83
+ # @return [Array<String, Integer>] The mediated escrow deposit address and bump seed.
84
+ def get_mediated_escrow_deposit_address(**options)
85
+ self.class.get_mediated_escrow_deposit_address(program_id:, **options)
86
+ end
87
+
88
+ # Alias for the class method, defaulting to this client's program id.
89
+ #
90
+ # @param options [Hash] Options for the get_vault_address class method.
91
+ # @return [Array<String, Integer>] The vault address and bump seed.
92
+ def get_vault_address(**options)
93
+ self.class.get_vault_address(program_id:, **options)
94
+ end
95
+
96
+ # Initializes the per-mint program vault, signs, and (optionally) sends it.
97
+ # The vault is shared across both escrow types, so this lives on the client
98
+ # itself rather than in an escrow-type mixin. The fee payer is the only signer.
99
+ #
100
+ # @param payer [Solace::Keypair] The fee payer (pays fees and rent, signs).
101
+ # @param sign [Boolean] Whether to sign the transaction.
102
+ # @param execute [Boolean] Whether to send the transaction.
103
+ # @param composer_opts [Hash] Options for {#compose_token_account_init}.
104
+ # @return [Solace::Transaction] The created or sent transaction.
105
+ def token_account_init(payer:, sign: true, execute: true, **composer_opts)
106
+ composer = compose_token_account_init(fee_payer: payer, **composer_opts)
107
+
108
+ yield composer if block_given?
109
+
110
+ tx = composer
111
+ .set_fee_payer(payer)
112
+ .compose_transaction
113
+
114
+ if sign
115
+ tx.sign(payer)
116
+
117
+ connection.send_transaction(tx.serialize) if execute
118
+ end
119
+
120
+ tx
121
+ end
122
+
123
+ # Prepares a token-account-init transaction. Derives the program vault PDA.
124
+ #
125
+ # @param mint [#to_s] Mint the vault holds.
126
+ # @param fee_payer [#to_s, Keypair] The fee payer (writable signer).
127
+ # @param token_program_id [String] Token program that owns the mint (default: legacy SPL Token).
128
+ # @return [Solace::TransactionComposer] A composer with the token-account-init instruction.
129
+ def compose_token_account_init(
130
+ mint:,
131
+ fee_payer:,
132
+ token_program_id: Solace::Constants::TOKEN_PROGRAM_ID
133
+ )
134
+ program_token_account, = get_vault_address(mint:)
135
+
136
+ ix = Composers::ZarTrustlessEscrowTokenAccountInitComposer.new(
137
+ mint:,
138
+ program_token_account:,
139
+ fee_payer:,
140
+ program_id:,
141
+ token_program_id:
142
+ )
143
+
144
+ TransactionComposer.new(connection:).add_instruction(ix)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module ZarTrustlessEscrow
5
+ # Immutable value object representing the deserialized EscrowDeposit account —
6
+ # the two-party escrow created by the `deposit` instruction and consumed by
7
+ # `claim` / `re_claim`. Fetching from the chain is the Program layer's
8
+ # responsibility — see Solace::Programs::ZarTrustlessEscrow#get_escrow_deposit.
9
+ #
10
+ # On-chain layout (state/escrow_deposit.rs, matches the IDL):
11
+ # discriminator(8), version(u8), mint(32), depositor(32), claim_pubkey(32),
12
+ # amount(u64), sponsor(Option<Pubkey>).
13
+ #
14
+ # @example
15
+ # deposit = program.get_escrow_deposit(claim_authority: claim_authority)
16
+ # deposit.amount # => 1_000_000
17
+ # deposit.claim_pubkey # => "9xQ..."
18
+ EscrowDeposit = Data.define(
19
+ :version, # Integer — escrow deposit version
20
+ :mint, # String — base58 mint of the escrowed tokens
21
+ :depositor, # String — base58 original depositor
22
+ :claim_pubkey, # String — base58 authority that can claim the deposit
23
+ :amount, # Integer — escrowed amount (u64)
24
+ :sponsor # String, nil — base58 optional fee sponsor
25
+ ) do
26
+ # Deserializes an EscrowDeposit from a stream of Borsh-encoded account data.
27
+ #
28
+ # @param io [IO, StringIO] Stream positioned at the start of the account data.
29
+ # @return [EscrowDeposit] The deserialized, frozen value.
30
+ def self.deserialize(io)
31
+ io.read(8) # skip the 8-byte Anchor discriminator
32
+
33
+ new(
34
+ version: Solace::Utils::Codecs.decode_u8(io),
35
+ mint: Solace::Utils::Codecs.decode_pubkey(io),
36
+ depositor: Solace::Utils::Codecs.decode_pubkey(io),
37
+ claim_pubkey: Solace::Utils::Codecs.decode_pubkey(io),
38
+ amount: Solace::Utils::Codecs.decode_le_u64(io),
39
+ sponsor: Solace::Utils::Codecs.decode_option_pubkey(io)
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module ZarTrustlessEscrow
5
+ # Immutable value object representing the deserialized MediatedEscrowDeposit
6
+ # account — the three-party escrow created by `mediated_deposit` and consumed
7
+ # by `mediated_release` / `mediated_reclaim`. Fetching from the chain is the
8
+ # Program layer's responsibility — see
9
+ # Solace::Programs::ZarTrustlessEscrow#get_mediated_escrow_deposit.
10
+ #
11
+ # On-chain layout (state/mediated_escrow_deposit.rs, matches the IDL):
12
+ # discriminator(8), version(u8), mint(32), depositor(32), mediator(32),
13
+ # beneficiary(32), amount(u64), rent_collector(Option<Pubkey>),
14
+ # expires_at(Option<i64>).
15
+ #
16
+ # @example
17
+ # escrow = program.get_mediated_escrow_deposit(id: id)
18
+ # escrow.mediator # => "9xQ..."
19
+ # escrow.expires_at # => 1_780_000_000 or nil
20
+ MediatedEscrowDeposit = Data.define(
21
+ :version, # Integer — mediated escrow deposit version
22
+ :mint, # String — base58 mint of the escrowed tokens
23
+ :depositor, # String — base58 original depositor
24
+ :mediator, # String — base58 mediator who decides the outcome
25
+ :beneficiary, # String — base58 beneficiary the mediator may release to
26
+ :amount, # Integer — escrowed amount (u64)
27
+ :rent_collector, # String, nil — base58 optional rent collector on close
28
+ :expires_at # Integer, nil — unix timestamp after which depositor may reclaim
29
+ ) do
30
+ # Deserializes a MediatedEscrowDeposit from a stream of Borsh-encoded data.
31
+ #
32
+ # @param io [IO, StringIO] Stream positioned at the start of the account data.
33
+ # @return [MediatedEscrowDeposit] The deserialized, frozen value.
34
+ def self.deserialize(io)
35
+ io.read(8) # skip the 8-byte Anchor discriminator
36
+
37
+ new(
38
+ version: Solace::Utils::Codecs.decode_u8(io),
39
+ mint: Solace::Utils::Codecs.decode_pubkey(io),
40
+ depositor: Solace::Utils::Codecs.decode_pubkey(io),
41
+ mediator: Solace::Utils::Codecs.decode_pubkey(io),
42
+ beneficiary: Solace::Utils::Codecs.decode_pubkey(io),
43
+ amount: Solace::Utils::Codecs.decode_le_u64(io),
44
+ rent_collector: Solace::Utils::Codecs.decode_option_pubkey(io),
45
+ expires_at: Solace::Utils::Codecs.decode_option_i64(io)
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module ZarTrustlessEscrow
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solace'
4
+ require 'solace/zar_trustless_escrow/version'
5
+
6
+ module Solace
7
+ # ZAR Trustless Escrow — a Solace extension for the on-chain escrow program.
8
+ #
9
+ # The program supports two escrow shapes:
10
+ # - Two-party escrow: a depositor locks funds claimable by a claim authority,
11
+ # reclaimable by the depositor (deposit / claim / re_claim).
12
+ # - Three-party mediated escrow: a depositor locks funds that a mediator
13
+ # releases to the depositor or a beneficiary, with an optional expiry that
14
+ # lets the depositor reclaim (mediated_deposit / mediated_release /
15
+ # mediated_reclaim).
16
+ module ZarTrustlessEscrow
17
+ # Base class for all errors raised by this gem.
18
+ class Error < StandardError; end
19
+ end
20
+ end
21
+
22
+ require 'solace/zar_trustless_escrow/constants'
23
+ require 'solace/zar_trustless_escrow/codecs_extensions'
24
+ require 'solace/zar_trustless_escrow/errors'
25
+
26
+ def req_glob(path)
27
+ Dir[File.join(__dir__, path)].each { |f| require f }
28
+ end
29
+
30
+ # Load account types
31
+ req_glob('zar_trustless_escrow/types/*.rb')
32
+
33
+ # Load instructions and composers
34
+ req_glob('zar_trustless_escrow/instructions/*.rb')
35
+ req_glob('zar_trustless_escrow/composers/*.rb')
36
+
37
+ # Load programs (the program client depends on the layers above)
38
+ req_glob('zar_trustless_escrow/programs/*.rb')