Skip to content

Commit 89abdb1

Browse files
fix parse err of TLV of new compress_and_close ixn. add regression tests for block 443787702 (#330)
rev inline doc
1 parent 8ef3c05 commit 89abdb1

File tree

7 files changed

+385
-8
lines changed

7 files changed

+385
-8
lines changed

src/common/typedefs/account/v1.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::common::typedefs::unsigned_integer::UnsignedInteger;
88
use crate::dao::generated::accounts::Model;
99
use crate::ingester::error::IngesterError;
1010
use crate::ingester::persist::COMPRESSED_TOKEN_PROGRAM;
11-
use borsh::BorshDeserialize;
1211
use jsonrpsee_core::Serialize;
1312
use utoipa::ToSchema;
1413

@@ -41,7 +40,7 @@ impl Account {
4140
if self.owner.0 == COMPRESSED_TOKEN_PROGRAM && data.is_c_token_discriminator() =>
4241
{
4342
let data_slice = data.data.0.as_slice();
44-
let token_data = TokenData::try_from_slice(data_slice).map_err(|e| {
43+
let token_data = TokenData::parse(data_slice).map_err(|e| {
4544
IngesterError::ParserError(format!("Failed to parse token data: {:?}", e))
4645
})?;
4746
Ok(Some(token_data))

src/common/typedefs/account/v2.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::common::typedefs::unsigned_integer::UnsignedInteger;
1010
use crate::dao::generated::accounts::Model;
1111
use crate::ingester::error::IngesterError;
1212
use crate::ingester::persist::COMPRESSED_TOKEN_PROGRAM;
13-
use borsh::BorshDeserialize;
1413
use serde::Serialize;
1514
use utoipa::ToSchema;
1615

@@ -45,7 +44,7 @@ impl AccountV2 {
4544
if self.owner.0 == COMPRESSED_TOKEN_PROGRAM && data.is_c_token_discriminator() =>
4645
{
4746
let data_slice = data.data.0.as_slice();
48-
let token_data = TokenData::try_from_slice(data_slice).map_err(|e| {
47+
let token_data = TokenData::parse(data_slice).map_err(|e| {
4948
IngesterError::ParserError(format!("Failed to parse token data: {:?}", e))
5049
})?;
5150
Ok(Some(token_data))

src/common/typedefs/token_data.rs

Lines changed: 243 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ pub enum AccountState {
3030
frozen,
3131
}
3232

33-
#[derive(
34-
Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone, ToSchema, Serialize, Default,
35-
)]
33+
#[derive(Debug, PartialEq, Eq, Clone, ToSchema, Serialize, Default)]
3634
#[serde(rename_all = "camelCase")]
3735
pub struct TokenData {
3836
/// The mint associated with this account
@@ -46,6 +44,247 @@ pub struct TokenData {
4644
pub delegate: Option<SerializablePubkey>,
4745
/// The account's state
4846
pub state: AccountState,
49-
/// Placeholder for TokenExtension tlv data (unimplemented)
47+
/// TokenExtension TLV data (raw bytes, opaque to the indexer)
5048
pub tlv: Option<Base64String>,
5149
}
50+
51+
impl TokenData {
52+
/// Deserializes base fields via Borsh, then reads TLV as raw bytes (1-byte
53+
/// option tag + remaining bytes).
54+
pub fn parse(data: &[u8]) -> Result<Self, std::io::Error> {
55+
let mut buf = data;
56+
57+
let mint = SerializablePubkey::deserialize(&mut buf)?;
58+
let owner = SerializablePubkey::deserialize(&mut buf)?;
59+
let amount = UnsignedInteger::deserialize(&mut buf)?;
60+
let delegate = Option::<SerializablePubkey>::deserialize(&mut buf)?;
61+
let state = AccountState::deserialize(&mut buf)?;
62+
63+
let tlv = if buf.is_empty() {
64+
None
65+
} else {
66+
let option_tag = buf[0];
67+
buf = &buf[1..];
68+
69+
match option_tag {
70+
0 => None,
71+
1 if !buf.is_empty() => Some(Base64String(buf.to_vec())),
72+
other => {
73+
log::warn!(
74+
"Unexpected TLV: option_tag={}, remaining_bytes={}",
75+
other,
76+
buf.len()
77+
);
78+
None
79+
}
80+
}
81+
};
82+
83+
Ok(TokenData {
84+
mint,
85+
owner,
86+
amount,
87+
delegate,
88+
state,
89+
tlv,
90+
})
91+
}
92+
}
93+
94+
impl BorshSerialize for TokenData {
95+
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
96+
borsh::BorshSerialize::serialize(&self.mint, writer)?;
97+
borsh::BorshSerialize::serialize(&self.owner, writer)?;
98+
borsh::BorshSerialize::serialize(&self.amount, writer)?;
99+
borsh::BorshSerialize::serialize(&self.delegate, writer)?;
100+
borsh::BorshSerialize::serialize(&self.state, writer)?;
101+
102+
match &self.tlv {
103+
None => writer.write_all(&[0]),
104+
Some(tlv_bytes) => {
105+
writer.write_all(&[1])?;
106+
writer.write_all(&tlv_bytes.0)
107+
}
108+
}
109+
}
110+
}
111+
112+
#[cfg(test)]
113+
mod tests {
114+
use super::*;
115+
use solana_pubkey::Pubkey;
116+
117+
fn build_onchain_token_data_bytes(has_delegate: bool, tlv: Option<&[u8]>) -> Vec<u8> {
118+
let mut bytes = Vec::new();
119+
bytes.extend_from_slice(&[0x11u8; 32]); // mint
120+
bytes.extend_from_slice(&[0x22u8; 32]); // owner
121+
bytes.extend_from_slice(&100u64.to_le_bytes()); // amount
122+
if has_delegate {
123+
bytes.push(1);
124+
bytes.extend_from_slice(&[0x33u8; 32]);
125+
} else {
126+
bytes.push(0);
127+
}
128+
bytes.push(0); // state = initialized
129+
match tlv {
130+
Some(tlv_data) => {
131+
bytes.push(1); // Option tag = Some
132+
bytes.extend_from_slice(tlv_data);
133+
}
134+
None => {
135+
bytes.push(0); // Option tag = None
136+
}
137+
}
138+
bytes
139+
}
140+
141+
fn build_compressed_only_tlv() -> Vec<u8> {
142+
let mut tlv = Vec::new();
143+
tlv.extend_from_slice(&1u32.to_le_bytes()); // vec len = 1 element
144+
tlv.push(31); // ExtensionStruct enum variant = CompressedOnly
145+
tlv.extend_from_slice(&500u64.to_le_bytes()); // delegated_amount
146+
tlv.extend_from_slice(&0u64.to_le_bytes()); // withheld_transfer_fee
147+
tlv.push(1); // is_ata
148+
tlv
149+
}
150+
151+
#[test]
152+
fn parse_v1_no_delegate_no_tlv() {
153+
let bytes = build_onchain_token_data_bytes(false, None);
154+
let td = TokenData::parse(&bytes).unwrap();
155+
assert_eq!(td.mint.0, Pubkey::from([0x11; 32]));
156+
assert_eq!(td.owner.0, Pubkey::from([0x22; 32]));
157+
assert_eq!(td.amount.0, 100);
158+
assert!(td.delegate.is_none());
159+
assert_eq!(td.state, AccountState::initialized);
160+
assert!(td.tlv.is_none());
161+
}
162+
163+
#[test]
164+
fn parse_v1_with_delegate_no_tlv() {
165+
let bytes = build_onchain_token_data_bytes(true, None);
166+
let td = TokenData::parse(&bytes).unwrap();
167+
assert_eq!(td.delegate.unwrap().0, Pubkey::from([0x33; 32]));
168+
assert!(td.tlv.is_none());
169+
}
170+
171+
#[test]
172+
fn parse_v3_with_compressed_only_tlv() {
173+
let tlv_raw = build_compressed_only_tlv();
174+
let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw));
175+
176+
let td = TokenData::parse(&bytes).unwrap();
177+
assert_eq!(td.amount.0, 100);
178+
assert!(td.delegate.is_some());
179+
let tlv = td.tlv.unwrap();
180+
assert_eq!(tlv.0, tlv_raw);
181+
}
182+
183+
#[test]
184+
fn parse_v3_no_delegate_with_tlv() {
185+
let tlv_raw = build_compressed_only_tlv();
186+
let bytes = build_onchain_token_data_bytes(false, Some(&tlv_raw));
187+
188+
let td = TokenData::parse(&bytes).unwrap();
189+
assert!(td.delegate.is_none());
190+
assert!(td.tlv.is_some());
191+
assert_eq!(td.tlv.unwrap().0, tlv_raw);
192+
}
193+
194+
#[derive(Debug, BorshDeserialize)]
195+
struct OldTokenData {
196+
pub mint: SerializablePubkey,
197+
pub owner: SerializablePubkey,
198+
pub amount: UnsignedInteger,
199+
pub delegate: Option<SerializablePubkey>,
200+
pub state: AccountState,
201+
pub tlv: Option<Base64String>,
202+
}
203+
204+
#[test]
205+
fn old_try_from_slice_fails_with_not_all_bytes_read() {
206+
let tlv_raw = build_compressed_only_tlv();
207+
let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw));
208+
209+
let err = OldTokenData::try_from_slice(&bytes)
210+
.expect_err("old BorshDeserialize must fail on V3 TLV data");
211+
212+
assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
213+
assert!(
214+
err.to_string().contains("Not all bytes read"),
215+
"Expected exact production error 'Not all bytes read', got: {}",
216+
err
217+
);
218+
}
219+
220+
#[test]
221+
fn new_parse_succeeds_where_old_try_from_slice_fails() {
222+
let tlv_raw = build_compressed_only_tlv();
223+
let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw));
224+
225+
// Old code fails:
226+
assert!(OldTokenData::try_from_slice(&bytes).is_err());
227+
// New code succeeds and captures TLV:
228+
let td = TokenData::parse(&bytes).unwrap();
229+
assert_eq!(td.tlv.unwrap().0, tlv_raw);
230+
}
231+
232+
#[test]
233+
fn roundtrip_no_tlv() {
234+
let original = TokenData {
235+
mint: SerializablePubkey(Pubkey::new_unique()),
236+
owner: SerializablePubkey(Pubkey::new_unique()),
237+
amount: UnsignedInteger(42),
238+
delegate: None,
239+
state: AccountState::initialized,
240+
tlv: None,
241+
};
242+
let mut bytes = Vec::new();
243+
borsh::BorshSerialize::serialize(&original, &mut bytes).unwrap();
244+
let parsed = TokenData::parse(&bytes).unwrap();
245+
assert_eq!(parsed, original);
246+
}
247+
248+
#[test]
249+
fn roundtrip_with_tlv() {
250+
let original = TokenData {
251+
mint: SerializablePubkey(Pubkey::new_unique()),
252+
owner: SerializablePubkey(Pubkey::new_unique()),
253+
amount: UnsignedInteger(1_000_000),
254+
delegate: Some(SerializablePubkey(Pubkey::new_unique())),
255+
state: AccountState::frozen,
256+
tlv: Some(Base64String(vec![0xAA, 0xBB, 0xCC])),
257+
};
258+
let mut bytes = Vec::new();
259+
borsh::BorshSerialize::serialize(&original, &mut bytes).unwrap();
260+
let parsed = TokenData::parse(&bytes).unwrap();
261+
assert_eq!(parsed, original);
262+
}
263+
264+
#[test]
265+
fn byte_layout_no_delegate_no_tlv() {
266+
let bytes = build_onchain_token_data_bytes(false, None);
267+
// mint(32) + owner(32) + amount(8) + delegate_none(1) + state(1) + tlv_none(1) = 75
268+
assert_eq!(bytes.len(), 75);
269+
let td = TokenData::parse(&bytes).unwrap();
270+
assert!(td.tlv.is_none());
271+
}
272+
273+
#[test]
274+
fn byte_layout_with_delegate_no_tlv() {
275+
let bytes = build_onchain_token_data_bytes(true, None);
276+
// mint(32) + owner(32) + amount(8) + delegate_some(1+32) + state(1) + tlv_none(1) = 107
277+
assert_eq!(bytes.len(), 107);
278+
}
279+
280+
#[test]
281+
fn byte_layout_with_delegate_and_tlv() {
282+
let tlv_raw = build_compressed_only_tlv();
283+
// tlv_raw: u32(4) + discriminant(1) + u64(8) + u64(8) + u8(1) = 22
284+
assert_eq!(tlv_raw.len(), 22);
285+
let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw));
286+
// 107 (with delegate, no tlv excl the None byte) - 1 (remove None byte)
287+
// + 1 (Some tag) + 22 (tlv_raw) = 129
288+
assert_eq!(bytes.len(), 129);
289+
}
290+
}

tests/data/blocks/index_compress_and_close_with_tlv/443787702

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"slot":443787702,"transaction":["AfMMldycix0UIMexs2itDUJTBi79kaBhPggL3ZSkLwNRZJBE5VtLSCn+bTQF0n3pKRCWX6Uwkm4O2pWKtd/gngIBAAka23C4xq2ooHBygbq1iLRAK2Mo3Y7VfnLQrcRA7umUr2IGOszTBytVY9JMKCJBJO9kBRqGLkSYez+IfPg4BgJi/Av/BRJ/YmYhV6ByJ2ufhnUSfZGThjKLsdXIIHkx7ZPpDI2bLhfzRRfeR7LAd9xMdGmgOSCB64sMQmncryF2aMMSeT2HdkIUkDuAZeRxEKFIChjqVAY0L8I4Mnc6LzZMzB2UraHcjq+IyZwDkgrlmYv/UfZdTAkG/j+TvtuDFvG7NfsX+1mDkDWCPnO7jhPNTQ0DDtupetonCWjl6mDSxmhCboSPg945OPliydTtY/l/9uhFLfiR4kZsk0gAaFZctWgB6w3J9vFOfIpf3eyRupnD17dPMf/G5KAo1ZfOP8Wje2FmVIcMkdh9uz2DS1KkVe0AtuoC770TfW3WUd3b8/eZCrT85p3aV+dDhRU539SG/h4Gxyj0pdzRTE9uANanipqxvMcqJz0EAEYap1jE6IW3b+QuHrMpHpjO1U8CloJGqbcX2ea52eBuSdH20sJQ8zj+5ghY0qnYfaYge6X5Oqe8Z/v6LVUc+GHeluQgIHt2jrNvW/yN5DUm66zVLAucwMJEJikF5u3ZBWdo5eFPCKvNU0BUUuQXaAE5dMGug1UJyGBEjoP6FIMclQoM64flmT0hVKuhVfbd7kg3dV3B6dz4ZZvufDfzNUOZnUuSNaBAtdOApYo7URhP1DWsFjyYJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQ0rE3lRNoXPAvK1/VKRvZWbKwYKpSXqWzSBOx25t24Gp1X4ITkFTUQksVrwxDDPL0t/mHk62hJS1I82ZsbLzgkVo1cjeU6Ptl0HW2tyaZw43QLllIt1sOWgQY6Al1tECSw27CL1F4MA/bRKqmr/z/Ckbhy8ZBwOPtCdoTue9Qge68SM+zJku8NL9cWlqDT8Z1AAbymG2W8jW8iHXvTdRIitQVQrIZEXIUggO1H09MwL+P/N5d9c/J7jID/F3wgr5skYsL18z5FURIp6v2qPOXgpoej9CKfw0LOquHhS/DL7syh1EFyuhbW0RHYH7b/hRSe/tCORHKQEI7/RUnomdZ1KeRdychEf+c/Vi+h5xLzQjlP9nFVdEXZAI+4L4KaXARIbAAUGFxQYExYZFRECEA4EAw8MCAsHCQEKDQAGJ2BehxJ5KtV1Dw4FAAAAAQIDBAAFBgMEAAcIAwQACQoDBAALDA0EAA==","base64"],"meta":{"err":null,"status":{"Ok":null},"fee":5000,"preBalances":[4546785219,2801400,7101743674,288209677566,148241697,2735280,0,2795000,2795000,0,1461600,0,0,0,2733142,2795000,2795000,1,1141440,1141440,1141440,1141440,1614720,3048480,12348754,0],"postBalances":[4546830204,0,7101748689,288223603966,148241697,2735280,0,0,0,0,1461600,0,0,0,2733142,0,0,1,1141440,1141440,1141440,1141440,1614720,3048480,12348754,0],"innerInstructions":[{"index":0,"instructions":[{"programIdIndex":20,"accounts":[19,0,24,22,25,21,17,2,16,14,4,3,15,12,8,11,7,9,1,10,13,0,6],"data":"Fj1sHJvkAmaSgFteoZiYGHzVZWafAQz58zu55JT2cwVYPvtD6A4K4kBzErpBy6jfrz9DWapz2jaZR5VSL49Zas7Pr34rXoYa87ras1rT4C9hJFxQVUWW5TZhVwwmNM6qYRSYWYxiVdiUtdpdiGGi2JRnJGf7srseRTRSfq2rWhWHn5RLaFsmR5qnrhdnM2EpqDZHNBfbj2yX9B3Anym7nw2rQ6J6YDz16KtYxUjXqcgPpfvsrR51hK8xejGiPvrHdSAJ7yyiQKBec95YWpU8S13vpRGh8DUs89juGr6sVALdC1RQiVfkZYSP6nhMUsfpYTc3EhoP1it6yaQXqZT9NokjaVNuMu3vdLZWNC4PMH1PXYXH8T5ERLkKo1WapGb9Fn7DUc2RHskfmAorZ4HvG3DJbLrqzW94Bn","stackHeight":2},{"programIdIndex":19,"accounts":[0,24,22,25,21,17,2],"data":"4Hi8NSpJbGB4XY1JFRdruKFRv4b9bTmZ7osi4wTvrzvFKKcb9JzzoMo3hzZ18bDhcJZrKkrvHNa65bgYNVqRRgpxoXTpxvqMDDhhBcEowgjRPKtXsRYZSWGB4fojpjZuJzAedF7uFDbwbL1uZMiFvkrgGM8reGpc3N5iCW2A6RZA8ghx5P75tbb1xkHFvgvwHwTb5NsNS6QCQWXVBQLhwmsXcDqGXHKcdDgWUZYYHAtvYMJ8XSyC7Xmfyu5jG8h8WkutfTF1Bpnr2XffHypQAeiQetcubFDhhBGSLLYGUaen9cqfr2o2HHfgKy3fZAmNov4JT5SeQ65g4LL7rgihGESsEqTnrWjZpDyyT425efuN8mXKBGV3yhVjg9wbt1xQ59HC1ADvgdjQnsydzsA6azJGfvLzntDbhBPviEvnqpWsAjUcnCjGccoWK3nAsrPujhUDbrWN7Ms8D1vvkDzHto8Fb7YgwZM9ZZKhMBbY4h1GaHd8JxdUdWEQQPcibz8ackhaTGo9mJByxS6QCWQknVzUmE2dFS7U1ugLsQZfrPofkkk1fUf88dhJYmTymQwJeADRHzDqb3oFwXi9FTtaraLoXnvH26ZmY9Un3wFssqbNfUkp1h8hevzacq4buWmEMStxLpr2mtzU6hHu3T4eY9Ksz432DpMAAPgbfEBMWFEAXahJcwBMq482pZVSQWYX4Z2533e7LSGkgevsJxfJf9mqdhVseom4VqNRuvrfwS3pc8dX82Wcx5sPt5KHPyNxpQU5uGwkWH8UufRddRSsggmqPpwffsSi5cpbCTqwQ8eACQSpBZJ4G737wZbJ4MhDYonxdSMyF9DQdr3irKtWt5TAn3wnXVnYfV95VDD8i8PcYwvugQKRzArT4f5w1bHH3LyzrjVsPNhFjfm95yW3XT4YrXwnbCDoKphvHURRuyFNFFK46UKkgahLNBDvj5YEFW3vVtbtYE76D8iPjYzJxLYucK72KtGNRm357kvG6Cth8pWBBDaVsrfsYBm54vBZNBmVGXaoo1Dvkt8cmBEqwC4CcvmccbdaTommgTEMBWvzHtWwdix5NYsAfi6B7bFAySuTJsWEMVPxDXNUXL5RKdURFAZVP1j1hhndKETJrT6wayVH4NY7QTbFBjv6tas2jEizakkpfaW4pnpwxQ2GBvZwn48JVGLtAKi1tFVjmSLNqMvAb4vzw4EKihcq7WxDkPrs5S11dFfmdSim51jG6ArubQ6DMABH3opDGh4wBjML8AnJo2BvGAYXdYaz9dBNWoLJ3EF3K5cUPvd5ZwJajAFZ7CefETpKHyWnq7u1NLyK4PmBoxkugVecCZezMNWwfKSb6k3VLZMXmSVqFd","stackHeight":3},{"programIdIndex":17,"accounts":[0,2],"data":"3Bxs4S8GahzMQd9h","stackHeight":4},{"programIdIndex":21,"accounts":[25,22,2],"data":"2ctAyTe3sKSZHzm2twB7y1gJZjd6oxGarm5jf3uWTC7kbkCD14PVYSredMidiWKb2v69uAJwj3fAtqu9Eo431vW9zPHJG1PNTtZ2r7KvS5gJV7pM4Ltyiq3eftHVkxk4DovnEc728227TsTxvTQte3kYwYCThJMG2JyRjo7AnyezM4ex7xBpE3jheryYaVAgHXXiifN8YtwziY8w8LddfhhyuPW2qEmVwkpqaNisLgSiWaPQaFsXBQ9XpbT5xG1gj2YDdC1buEaqznQJoyE4m2uFTWXsX22MdQZiH61kdhAjz7eKJ4Mhag2ETzrvFU27A3p4XkFgsXs2EjdrRyYUeh3PdUU8VaXcecdkSrr1qgv8wrRsvKrA4HjBYBZB66iLRqqgmJY2GcsUMBwmGa8fPf7c2uBKhNi3XjX3E5fupCrxdnkD8MmuCQtVCZu2ZV","stackHeight":4}]}],"logMessages":["Program Lighton6oQpVkeewmo2mcPTQQp7kYHr4fWpAgJyEmDX invoke [1]","Program log: Instruction: CompressAndClose","Program log: compress_and_close:HidyR1csaEp4rWJk5cX3F46PkjGqE5CfoeRNF8GMe3Mo","Program log: compress_and_close:EVBgQ77q2krxQE3tHWGAqX7QaumfYLewDu1MUQiyqtDR","Program log: compress_and_close:8116dMhcMFQd9nxxjbH9ici19FKmYgQ7NtrCWNRdZVWa","Program log: compress_and_close:5UKejWcoRCLfQCrEtpYRNRDTkH3FRtqYGKT3WqSAZhQp","Program log: compress_and_close:RKT4QchrqahQxSCPrmZsJkznH7gFUQsR6ZusFCcYCJo","Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m invoke [2]","Program log: Transfer2","Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [3]","Program log: invoke_cpi_with_read_only","Program log: mode V2","Program 11111111111111111111111111111111 invoke [4]","Program 11111111111111111111111111111111 success","Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [4]","Program log: Instruction: InsertIntoQueues","Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 9240 of 83531 compute units","Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success","Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 39409 of 113663 compute units","Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success","Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m consumed 80225 of 147520 compute units","Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m success","Program Lighton6oQpVkeewmo2mcPTQQp7kYHr4fWpAgJyEmDX consumed 135398 of 200000 compute units","Program Lighton6oQpVkeewmo2mcPTQQp7kYHr4fWpAgJyEmDX success"],"preTokenBalances":[],"postTokenBalances":[],"rewards":[],"loadedAddresses":{"writable":[],"readonly":[]},"computeUnitsConsumed":135398,"costUnits":142403},"version":"legacy","blockTime":1771722294}

0 commit comments

Comments
 (0)