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.
- checksums.yaml +7 -0
- data/lib/solace/zar_trustless_escrow/codecs_extensions.rb +101 -0
- data/lib/solace/zar_trustless_escrow/composers/claim_composer.rb +136 -0
- data/lib/solace/zar_trustless_escrow/composers/deposit_composer.rb +145 -0
- data/lib/solace/zar_trustless_escrow/composers/mediated_deposit_composer.rb +173 -0
- data/lib/solace/zar_trustless_escrow/composers/mediated_reclaim_composer.rb +137 -0
- data/lib/solace/zar_trustless_escrow/composers/mediated_release_composer.rb +157 -0
- data/lib/solace/zar_trustless_escrow/composers/reclaim_composer.rb +135 -0
- data/lib/solace/zar_trustless_escrow/composers/token_account_init_composer.rb +88 -0
- data/lib/solace/zar_trustless_escrow/constants.rb +47 -0
- data/lib/solace/zar_trustless_escrow/errors/program_error.rb +30 -0
- data/lib/solace/zar_trustless_escrow/errors.rb +104 -0
- data/lib/solace/zar_trustless_escrow/instructions/claim_instruction.rb +60 -0
- data/lib/solace/zar_trustless_escrow/instructions/deposit_instruction.rb +65 -0
- data/lib/solace/zar_trustless_escrow/instructions/mediated_deposit_instruction.rb +74 -0
- data/lib/solace/zar_trustless_escrow/instructions/mediated_reclaim_instruction.rb +60 -0
- data/lib/solace/zar_trustless_escrow/instructions/mediated_release_instruction.rb +65 -0
- data/lib/solace/zar_trustless_escrow/instructions/reclaim_instruction.rb +60 -0
- data/lib/solace/zar_trustless_escrow/instructions/token_account_init_instruction.rb +48 -0
- data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow/escrow_deposit_operations.rb +243 -0
- data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow/mediated_escrow_deposit_operations.rb +259 -0
- data/lib/solace/zar_trustless_escrow/programs/zar_trustless_escrow.rb +148 -0
- data/lib/solace/zar_trustless_escrow/types/escrow_deposit.rb +44 -0
- data/lib/solace/zar_trustless_escrow/types/mediated_escrow_deposit.rb +50 -0
- data/lib/solace/zar_trustless_escrow/version.rb +7 -0
- data/lib/solace/zar_trustless_escrow.rb +38 -0
- 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,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')
|