-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathresolve-signatures.ts
118 lines (109 loc) · 3.85 KB
/
resolve-signatures.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import {isTransaction} from "../interaction/interaction"
import {Interaction, InteractionAccount} from "@onflow/typedefs"
import {sansPrefix} from "@onflow/util-address"
import {
Transaction,
TransactionProposalKey,
encodeTransactionPayload as encodeInsideMessage,
encodeTransactionEnvelope as encodeOutsideMessage,
} from "../encode/encode"
import {
createSignableVoucher,
findInsideSigners,
findOutsideSigners,
} from "./voucher"
export async function resolveSignatures(ix: Interaction) {
if (isTransaction(ix)) {
try {
let insideSigners = findInsideSigners(ix)
const insidePayload = encodeInsideMessage(prepForEncoding(ix))
// Promise.all could potentially break the flow if there are multiple inside signers trying to resolve at the same time
// causing multiple triggers of authz function that tries to render multiple auth iiframes/tabs/extensions
// as an alternative, use this:
// for(const insideSigner of insideSigners) {
// await fetchSignature(ix, insidePayload)(insideSigner);
// }
await Promise.all(insideSigners.map(fetchSignature(ix, insidePayload)))
let outsideSigners = findOutsideSigners(ix)
const outsidePayload = encodeOutsideMessage({
...prepForEncoding(ix),
payloadSigs: insideSigners.map(id => ({
address: ix.accounts[id].addr || "",
keyId: ix.accounts[id].keyId || 0,
sig: ix.accounts[id].signature || "",
})),
})
// Promise.all could potentially break the flow if there are multiple outside signers trying to resolve at the same time
// causing multiple triggers of authz function that tries to render multiple auth iframes/tabs/extensions
// as an alternative, use this:
// for(const outsideSigner of outsideSigners) {
// await fetchSignature(ix, outsidePayload)(outsideSigner);
// }
await Promise.all(outsideSigners.map(fetchSignature(ix, outsidePayload)))
} catch (error) {
console.error("Signatures", error, {ix})
throw error
}
}
return ix
}
function fetchSignature(ix: Interaction, payload: string) {
return async function innerFetchSignature(id: string) {
const acct = ix.accounts[id]
if (acct.signature != null && acct.signature !== undefined) return
const {signature} = await acct.signingFunction(
buildSignable(acct, payload, ix)
)
ix.accounts[id].signature = signature
}
}
export function buildSignable(
acct: InteractionAccount,
message: string,
ix: Interaction
) {
try {
return {
f_type: "Signable",
f_vsn: "1.0.1",
message,
addr: sansPrefix(acct.addr),
keyId: acct.keyId,
roles: acct.role,
cadence: ix.message.cadence,
args: ix.message.arguments.map(d => ix.arguments[d].asArgument),
data: {},
interaction: ix,
voucher: createSignableVoucher(ix),
}
} catch (error) {
console.error("buildSignable", error)
throw error
}
}
function prepForEncoding(ix: Interaction): Transaction {
const payerAddress = sansPrefix(
(Array.isArray(ix.payer) ? ix.accounts[ix.payer[0]] : ix.accounts[ix.payer])
.addr || ""
)
const proposalKey: TransactionProposalKey = ix.proposer
? {
address: sansPrefix(ix.accounts[ix.proposer].addr) || "",
keyId: ix.accounts[ix.proposer].keyId || 0,
sequenceNum: ix.accounts[ix.proposer].sequenceNum || 0,
}
: {}
return {
cadence: ix.message.cadence,
refBlock: ix.message.refBlock,
computeLimit: ix.message.computeLimit,
arguments: ix.message.arguments.map(id => ix.arguments[id].asArgument),
proposalKey,
payer: payerAddress,
authorizers: ix.authorizations
.map(cid => sansPrefix(ix.accounts[cid].addr) || "")
.reduce((prev: string[], current) => {
return prev.find(item => item === current) ? prev : [...prev, current]
}, []),
}
}