Skip to content

Commit

Permalink
feat: Added support for parsing signatures and inner transactions fro…
Browse files Browse the repository at this point in the history
…m algod block
  • Loading branch information
robdmoore committed Jan 21, 2024
1 parent 43297d3 commit b05027d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 13 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"typescript": "^5.2.2"
},
"peerDependencies": {
"@algorandfoundation/algokit-utils": "^5.0.1",
"@algorandfoundation/algokit-utils": "^5.2.2",
"algosdk": "^2.7.0"
},
"publishConfig": {
Expand Down
66 changes: 59 additions & 7 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TransactionResult } from '@algorandfoundation/algokit-utils/types/indexer'
import type { MultisigTransactionSubSignature, TransactionResult } from '@algorandfoundation/algokit-utils/types/indexer'
import { ApplicationOnComplete } from '@algorandfoundation/algokit-utils/types/indexer'
import algosdk, { OnApplicationComplete, Transaction, TransactionType } from 'algosdk'
import { Buffer } from 'buffer'
Expand Down Expand Up @@ -195,7 +195,7 @@ export function algodOnCompleteToIndexerOnComplete(appOnComplete: OnApplicationC
* @param closeAmount The amount of microAlgos that were transferred if the transaction had a close
* @returns The indexer transaction formation (`TransactionResult`)
*/
export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock): TransactionResult {
export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock & { getChildOffset?: () => number }): TransactionResult {
const {
transaction,
createdAssetId,
Expand All @@ -207,12 +207,17 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock)
roundOffset,
parentOffset,
parentTransactionId,
roundIndex,
parentTransaction,
} = t

if (!transaction.type) {
throw new Error(`Received no transaction type for transaction ${transaction.txID()}`)
}

let childOffset = roundOffset
const getChildOffset = t.getChildOffset ? t.getChildOffset : () => ++childOffset

const encoder = new TextEncoder()
const decoder = new TextDecoder()

Expand Down Expand Up @@ -325,16 +330,63 @@ export function getIndexerTransactionFromAlgodTransaction(t: TransactionInBlock)
'rekey-to': transaction.reKeyTo ? algosdk.encodeAddress(transaction.reKeyTo.publicKey) : undefined,
'closing-amount': closeAmount,
'created-application-index': createdAppId,
'auth-addr': blockTransaction.sgnr ? algosdk.encodeAddress(blockTransaction.sgnr) : undefined,
'inner-txns': blockTransaction.dt?.itx?.map((ibt) =>
getIndexerTransactionFromAlgodTransaction({
block,
blockTransaction: ibt,
roundIndex,
roundOffset: getChildOffset(),
...extractTransactionFromBlockTransaction(ibt, block),
getChildOffset,
parentOffset,
parentTransaction,
parentTransactionId,
}),
),
signature:
blockTransaction.sig || blockTransaction.lsig || blockTransaction.msig
? {
sig: blockTransaction.sig ? Buffer.from(blockTransaction.sig).toString('base64') : undefined,
logicsig: blockTransaction.lsig
? {
logic: Buffer.from(blockTransaction.lsig.l).toString('base64'),
args: blockTransaction.lsig.arg ? blockTransaction.lsig.arg.map((a) => Buffer.from(a).toString('base64')) : undefined,
signature: blockTransaction.lsig.sig ? Buffer.from(blockTransaction.lsig.sig).toString('base64') : undefined,
'multisig-signature': blockTransaction.lsig.msig
? {
version: blockTransaction.lsig.msig.v,
threshold: blockTransaction.lsig.msig.thr,
subsignature: blockTransaction.lsig.msig.subsig.map(
(s) =>
({
'public-key': Buffer.from(s.pk).toString('base64'),
signature: Buffer.from(s.s).toString('base64'),
}) as MultisigTransactionSubSignature,
),
}
: undefined,
}
: undefined,
multisig: blockTransaction.msig
? {
version: blockTransaction.msig.v,
threshold: blockTransaction.msig.thr,
subsignature: blockTransaction.msig.subsig.map((s) => ({
'public-key': Buffer.from(s.pk).toString('base64'),
signature: Buffer.from(s.s).toString('base64'),
})),
}
: undefined,
}
: undefined,
// todo: do we need any of these?
//"auth-addr"
//"close-rewards"
//"receiver-rewards"
//"sender-rewards"
//"global-state-delta"
//"inner-txns"
//"keyreg-transaction"
//"local-state-delta"
//"receiver-rewards"
//"sender-rewards"
//logs
//signature
}
}
44 changes: 43 additions & 1 deletion src/types/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export interface Block {
txns: BlockTransaction[]
}

/** Data that is returned in a raw Algorand block for a single transaction */
/** Data that is returned in a raw Algorand block for a single transaction
*
* @see https://github.com/algorand/go-algorand/blob/master/data/transactions/signedtxn.go#L32
*/
export interface BlockTransaction {
/** The encoded transaction data */
txn: EncodedTransaction
Expand All @@ -73,6 +76,45 @@ export interface BlockTransaction {
hgi: boolean
/** Has genesis hash */
hgh?: boolean
/** Transaction ED25519 signature */
sig?: Uint8Array
/** Logic signature */
lsig?: LogicSig
/** Transaction multisig signature */
msig?: MultisigSig
/** The signer, if signing with a different key than the Transaction type `from` property indicates */
sgnr?: Uint8Array
}

/** Data that represents a multisig signature
* @see https://github.com/algorand/go-algorand/blob/master/data/transactions/logicsig.go#L32
*/
export interface LogicSig {
/** Logic sig code */
l: Uint8Array
/** ED25519 signature for delegated operations */
sig?: Uint8Array
/** Multisig signature for delegated operations */
msig?: MultisigSig
/** Arguments passed into the logic signature */
arg?: Buffer[]
}

/** Data that represents a multisig signature
* @see https://github.com/algorand/go-algorand/blob/master/crypto/multisig.go#L36
*/
export interface MultisigSig {
/** Multisig version */
v: number
/** Multisig threshold */
thr: number
/** Sub-signatures */
subsig: {
/** ED25519 public key */
pk: Uint8Array
/** ED25519 signature */
s: Uint8Array
}[]
}

/** Data that is returned in a raw Algorand block for a single inner transaction */
Expand Down
39 changes: 39 additions & 0 deletions tests/scenarios/transform-complex-txn.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ describe('Complex transaction with many nested inner transactions', () => {
"asset-config-transaction": {},
"asset-freeze-transaction": undefined,
"asset-transfer-transaction": undefined,
"auth-addr": undefined,
"closing-amount": undefined,
"confirmed-round": 35214367,
"created-application-index": undefined,
Expand All @@ -219,6 +220,43 @@ describe('Complex transaction with many nested inner transactions', () => {
"genesis-id": "mainnet-v1.0",
"group": "6ZssGapPFZ+DyccRludq0YjZigi05/FSeUAOFNDGGlo=",
"id": "QLYC4KMQW5RZRA7W5GYCJ4CUVWWSZKMK2V4X3XFQYSGYCJH6LI4Q/inner/5",
"inner-txns": [
{
"application-transaction": undefined,
"asset-config-transaction": {},
"asset-freeze-transaction": undefined,
"asset-transfer-transaction": {
"amount": 536012365,
"asset-id": 1390638935,
"close-amount": undefined,
"close-to": undefined,
"receiver": "AACCDJTFPQR5UQJZ337NFR56CC44T776EWBGVJG5NY2QFTQWBWTALTEN4A",
"sender": "RS7QNBEPRRIBGI5COVRWFCRUS5NC5NX7UABZSTSFXQ6F74EP3CNLT4CNAM",
},
"auth-addr": undefined,
"closing-amount": undefined,
"confirmed-round": 35214367,
"created-application-index": undefined,
"created-asset-index": undefined,
"fee": undefined,
"first-valid": 35214365,
"genesis-hash": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
"genesis-id": "mainnet-v1.0",
"group": undefined,
"id": "QLYC4KMQW5RZRA7W5GYCJ4CUVWWSZKMK2V4X3XFQYSGYCJH6LI4Q/inner/5",
"inner-txns": undefined,
"intra-round-offset": 148,
"last-valid": 35214369,
"lease": "",
"note": "",
"payment-transaction": undefined,
"rekey-to": undefined,
"round-time": 1705252440,
"sender": "RS7QNBEPRRIBGI5COVRWFCRUS5NC5NX7UABZSTSFXQ6F74EP3CNLT4CNAM",
"signature": undefined,
"tx-type": "axfer",
},
],
"intra-round-offset": 147,
"last-valid": 35214369,
"lease": "",
Expand All @@ -227,6 +265,7 @@ describe('Complex transaction with many nested inner transactions', () => {
"rekey-to": undefined,
"round-time": 1705252440,
"sender": "AACCDJTFPQR5UQJZ337NFR56CC44T776EWBGVJG5NY2QFTQWBWTALTEN4A",
"signature": undefined,
"tx-type": "appl",
}
`)
Expand Down

0 comments on commit b05027d

Please sign in to comment.