@projectsolo/solo-mission-mcp 0.21.14 → 0.22.1
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.
- package/README.md +99 -15
- package/dist/chunk-NUGGTARW.js +196 -0
- package/dist/{chunk-TKRT2V2W.js → chunk-OP4QYTL4.js} +5 -0
- package/dist/{client-LDWK5HLP.js → client-NS6J6IO2.js} +1 -1
- package/dist/deployment-UCUWVIPJ.js +43 -0
- package/dist/escrowErrors-4XSAYLGT.js +56 -0
- package/dist/index.js +239 -160
- package/dist/verify-7EUVRUAS.js +445 -0
- package/dist/{wallet-V4T4NTCM.js → wallet-LX7SI5RE.js} +28 -14
- package/dist/wire-RLDY4AJR.js +24 -0
- package/package.json +2 -2
- package/src/config.ts +11 -0
- package/src/index.ts +1 -1
- package/src/scripts/check-tools-against-spec.ts +3 -3
- package/src/solana/deployment.test.ts +61 -0
- package/src/solana/deployment.ts +89 -0
- package/src/solana/escrowErrors.ts +78 -0
- package/src/solana/fixtures/config-account.json +6 -0
- package/src/solana/fixtures/funding-transaction-v2-lottery.json +49 -0
- package/src/solana/fixtures/funding-transaction-v2-plain.json +46 -0
- package/src/solana/fixtures/solo_escrow.v2.idl-excerpt.json +683 -0
- package/src/solana/verify.test.ts +605 -78
- package/src/solana/verify.ts +545 -84
- package/src/solana/wallet.test.ts +85 -2
- package/src/solana/wallet.ts +74 -31
- package/src/solana/wire.test.ts +129 -0
- package/src/solana/wire.ts +264 -0
- package/src/tools/missions.ts +45 -117
- package/src/tools/solana.test.ts +356 -0
- package/src/tools/solana.ts +309 -70
- package/src/tools/tracks.ts +1 -1
- package/dist/verify-KAETIGV5.js +0 -136
- /package/src/solana/fixtures/{funding-transaction.json → funding-transaction-v1.json} +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The program id every check hangs off must not come from the API being checked.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, afterEach } from 'vitest'
|
|
5
|
+
import { PINNED_DEPLOYMENTS, resolvePinnedProgram, resolveTrustedRpc, solanaRpcUrl } from './deployment'
|
|
6
|
+
|
|
7
|
+
const DEVNET = '2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a'
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
delete process.env.SOLO_SOLANA_PROGRAM_ID
|
|
11
|
+
delete process.env.SOLO_SOLANA_RPC_URL
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('resolvePinnedProgram', () => {
|
|
15
|
+
it('pins the devnet escrow program', () => {
|
|
16
|
+
expect(PINNED_DEPLOYMENTS.devnet.program_id).toBe(DEVNET)
|
|
17
|
+
expect(resolvePinnedProgram({ cluster: 'devnet', program_id: DEVNET })).toEqual({ program_id: DEVNET })
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('refuses a program id the API reports for a pinned cluster when it differs', () => {
|
|
21
|
+
const r = resolvePinnedProgram({ cluster: 'devnet', program_id: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' })
|
|
22
|
+
expect(r).toEqual({ problem: expect.stringMatching(/but this server pins 2CPC5V63/) })
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('refuses a cluster nothing is pinned for', () => {
|
|
26
|
+
expect(resolvePinnedProgram({ cluster: 'mainnet-beta', program_id: DEVNET })).toEqual({
|
|
27
|
+
problem: expect.stringMatching(/no escrow program is pinned for cluster "mainnet-beta"/),
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('lets SOLO_SOLANA_PROGRAM_ID pin a program, and still requires the API to agree', () => {
|
|
32
|
+
process.env.SOLO_SOLANA_PROGRAM_ID = DEVNET
|
|
33
|
+
expect(resolvePinnedProgram({ cluster: 'localnet', program_id: DEVNET })).toEqual({ program_id: DEVNET })
|
|
34
|
+
expect(resolvePinnedProgram({ cluster: 'devnet', program_id: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' })).toEqual({
|
|
35
|
+
problem: expect.stringMatching(/\(SOLO_SOLANA_PROGRAM_ID\)/),
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('resolveTrustedRpc', () => {
|
|
41
|
+
it('uses SOLO_SOLANA_RPC_URL or the pinned endpoint, never the API', () => {
|
|
42
|
+
expect(resolveTrustedRpc({ cluster: 'devnet' })).toEqual({ rpc_url: 'https://api.devnet.solana.com' })
|
|
43
|
+
// Pinning a program for an unknown cluster is not enough: the API's rpc_url could serve a
|
|
44
|
+
// fake mint or Config.
|
|
45
|
+
process.env.SOLO_SOLANA_PROGRAM_ID = DEVNET
|
|
46
|
+
expect(resolveTrustedRpc({ cluster: 'mainnet-beta' })).toEqual({
|
|
47
|
+
problem: expect.stringMatching(/set SOLO_SOLANA_RPC_URL/),
|
|
48
|
+
})
|
|
49
|
+
process.env.SOLO_SOLANA_RPC_URL = 'https://my.rpc'
|
|
50
|
+
expect(resolveTrustedRpc({ cluster: 'mainnet-beta' })).toEqual({ rpc_url: 'https://my.rpc' })
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('solanaRpcUrl (display-only reads)', () => {
|
|
55
|
+
it('prefers SOLO_SOLANA_RPC_URL, then the pinned endpoint, then the API', () => {
|
|
56
|
+
expect(solanaRpcUrl({ cluster: 'devnet', rpc_url: 'https://api.example' })).toBe('https://api.devnet.solana.com')
|
|
57
|
+
expect(solanaRpcUrl({ cluster: 'localnet', rpc_url: 'http://127.0.0.1:8899' })).toBe('http://127.0.0.1:8899')
|
|
58
|
+
process.env.SOLO_SOLANA_RPC_URL = 'https://my.rpc'
|
|
59
|
+
expect(solanaRpcUrl({ cluster: 'devnet', rpc_url: 'https://api.example' })).toBe('https://my.rpc')
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The escrow deployments this package trusts, pinned in code.
|
|
3
|
+
*
|
|
4
|
+
* `/agent/solana/config` comes from the same backend that builds the transaction the agent is asked
|
|
5
|
+
* to sign. If the program id came from there too, a backend could name a program of its own —
|
|
6
|
+
* with its own Config and its own "Operator" — and every derived address, the co-signer check and
|
|
7
|
+
* the "pinned" program check would agree with it. The API's program id is therefore only accepted
|
|
8
|
+
* when it equals the one pinned here for the cluster it reports.
|
|
9
|
+
*
|
|
10
|
+
* A deployment this version does not know (localnet, or a new mainnet program before this package
|
|
11
|
+
* is updated) needs `SOLO_SOLANA_PROGRAM_ID` set to the program id the operator of this server
|
|
12
|
+
* trusts. Until then, funding and refunds are refused rather than signed on the API's word.
|
|
13
|
+
*
|
|
14
|
+
* The same goes for the RPC endpoint the checked reads use (mint decimals, the escrow Config): it
|
|
15
|
+
* is `SOLO_SOLANA_RPC_URL` or the pinned cluster's public endpoint, never the API's `rpc_url`. A
|
|
16
|
+
* backend-chosen RPC could serve a fake mint with other decimals and scale the budget the agent
|
|
17
|
+
* approves.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface PinnedDeployment {
|
|
21
|
+
cluster: string;
|
|
22
|
+
program_id: string;
|
|
23
|
+
/** Public RPC endpoint for reads the server checks itself (overridable). */
|
|
24
|
+
rpc_url: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const PINNED_DEPLOYMENTS: Readonly<Record<string, PinnedDeployment>> = {
|
|
28
|
+
// solo-escrow-solana u1.1.0 on devnet (the live private beta).
|
|
29
|
+
devnet: {
|
|
30
|
+
cluster: 'devnet',
|
|
31
|
+
program_id: '2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a',
|
|
32
|
+
rpc_url: 'https://api.devnet.solana.com',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The program id to verify against: `SOLO_SOLANA_PROGRAM_ID` if set, else the pinned id for the
|
|
38
|
+
* reported cluster. The API's `program_id` must equal it.
|
|
39
|
+
*/
|
|
40
|
+
export function resolvePinnedProgram(cfg: {
|
|
41
|
+
cluster?: string;
|
|
42
|
+
program_id: string;
|
|
43
|
+
}): { program_id: string } | { problem: string } {
|
|
44
|
+
const override = (process.env.SOLO_SOLANA_PROGRAM_ID ?? '').trim();
|
|
45
|
+
const pinned = override || PINNED_DEPLOYMENTS[cfg.cluster ?? '']?.program_id;
|
|
46
|
+
if (!pinned) {
|
|
47
|
+
return {
|
|
48
|
+
problem:
|
|
49
|
+
`no escrow program is pinned for cluster ${JSON.stringify(cfg.cluster)} — set ` +
|
|
50
|
+
'SOLO_SOLANA_PROGRAM_ID to the program id you trust, or use a version of this package ' +
|
|
51
|
+
'that pins it',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (cfg.program_id !== pinned) {
|
|
55
|
+
return {
|
|
56
|
+
problem:
|
|
57
|
+
`the API reports escrow program ${cfg.program_id} for cluster ${JSON.stringify(cfg.cluster)}, ` +
|
|
58
|
+
`but this server pins ${pinned}${override ? ' (SOLO_SOLANA_PROGRAM_ID)' : ''} — refusing to ` +
|
|
59
|
+
'sign for a program it does not trust',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return { program_id: pinned };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The RPC endpoint for reads that feed a signing decision — mint decimals and the escrow Config:
|
|
67
|
+
* `SOLO_SOLANA_RPC_URL` if set, else the pinned cluster's public endpoint. Never the API's
|
|
68
|
+
* `rpc_url`, so an unpinned cluster needs `SOLO_SOLANA_RPC_URL`.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveTrustedRpc(cfg: { cluster?: string }): { rpc_url: string } | { problem: string } {
|
|
71
|
+
const rpc = (process.env.SOLO_SOLANA_RPC_URL ?? '').trim() || PINNED_DEPLOYMENTS[cfg.cluster ?? '']?.rpc_url;
|
|
72
|
+
if (!rpc) {
|
|
73
|
+
return {
|
|
74
|
+
problem:
|
|
75
|
+
`no RPC endpoint is pinned for cluster ${JSON.stringify(cfg.cluster)} — set SOLO_SOLANA_RPC_URL ` +
|
|
76
|
+
'to an endpoint you trust; the API-reported rpc_url is not used for reads that decide what to sign',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return { rpc_url: rpc };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The RPC endpoint for display-only reads (get_solana_wallet balances): the trusted one when there
|
|
84
|
+
* is one, else the `rpc_url` the API reports.
|
|
85
|
+
*/
|
|
86
|
+
export function solanaRpcUrl(cfg: { cluster?: string; rpc_url: string }): string {
|
|
87
|
+
const trusted = resolveTrustedRpc(cfg);
|
|
88
|
+
return 'rpc_url' in trusted ? trusted.rpc_url : cfg.rpc_url;
|
|
89
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The escrow program errors an agent can hit while funding or refunding, named and explained.
|
|
3
|
+
*
|
|
4
|
+
* A failed submission surfaces as `custom program error: 0x17ed` (or, in the program logs, as
|
|
5
|
+
* `Error Code: TooLateToCancel. Error Number: 6125.`), which tells an agent nothing about what to
|
|
6
|
+
* do next. Codes are from solo-escrow-solana u1.1.0 `idl/solo_escrow.json` and are checked against
|
|
7
|
+
* the vendored IDL excerpt in `verify.test.ts`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface EscrowErrorInfo {
|
|
11
|
+
code: number;
|
|
12
|
+
name: string;
|
|
13
|
+
what_to_do: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ESCROW_ERRORS: Record<number, Omit<EscrowErrorInfo, 'code'>> = {
|
|
17
|
+
6012: {
|
|
18
|
+
name: 'SettlementWindowTooShort',
|
|
19
|
+
what_to_do:
|
|
20
|
+
'settlement_deadline must be at least qualify_deadline + min_review_window + the finalize ' +
|
|
21
|
+
'grace. Create a new mission with a longer work_duration_hours.',
|
|
22
|
+
},
|
|
23
|
+
6016: {
|
|
24
|
+
name: 'TooEarlyForEmergencyRefund',
|
|
25
|
+
what_to_do: 'emergency_refund opens only once settlement_deadline has passed. Retry after it.',
|
|
26
|
+
},
|
|
27
|
+
6026: {
|
|
28
|
+
name: 'RefundAlreadyClaimed',
|
|
29
|
+
what_to_do: 'the refundable amount was already claimed — nothing is left to refund.',
|
|
30
|
+
},
|
|
31
|
+
6027: { name: 'NothingToRefund', what_to_do: 'the task holds nothing refundable.' },
|
|
32
|
+
6124: {
|
|
33
|
+
name: 'LotteryRequiresOperator',
|
|
34
|
+
what_to_do:
|
|
35
|
+
'a lottery create_task needs the platform Operator\'s co-signature over the exact message. ' +
|
|
36
|
+
'Request a fresh funding transaction and sign it unchanged.',
|
|
37
|
+
},
|
|
38
|
+
6125: {
|
|
39
|
+
name: 'TooLateToCancel',
|
|
40
|
+
what_to_do:
|
|
41
|
+
'cancel is refused on chain from qualify_deadline on. Let the mission settle, or use ' +
|
|
42
|
+
'emergency_refund once settlement_deadline has passed without a settlement.',
|
|
43
|
+
},
|
|
44
|
+
6132: {
|
|
45
|
+
name: 'FeeAboveSponsorMax',
|
|
46
|
+
what_to_do:
|
|
47
|
+
'the program\'s fee rose above the max_fee_bps you were quoted, so the escrow refused to ' +
|
|
48
|
+
'charge more. Cancel the mission (cancel_mission) and create a new one for a fresh quote.',
|
|
49
|
+
},
|
|
50
|
+
6133: {
|
|
51
|
+
name: 'QualifyDeadlineTooFar',
|
|
52
|
+
what_to_do: 'qualify_deadline may be at most 180 days ahead. Create a new mission with a shorter hiring window.',
|
|
53
|
+
},
|
|
54
|
+
6134: {
|
|
55
|
+
name: 'SettlementDeadlineTooFar',
|
|
56
|
+
what_to_do:
|
|
57
|
+
'settlement_deadline may be at most 90 days after qualify_deadline. Create a new mission with a ' +
|
|
58
|
+
'shorter work window.',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** Finds a known escrow error in an RPC, backend or program-log message. */
|
|
63
|
+
export function escrowErrorFromMessage(message: string | undefined | null): EscrowErrorInfo | null {
|
|
64
|
+
if (!message) return null;
|
|
65
|
+
const candidates: number[] = [];
|
|
66
|
+
for (const m of message.matchAll(/custom program error: 0x([0-9a-f]+)/gi)) {
|
|
67
|
+
candidates.push(parseInt(m[1], 16));
|
|
68
|
+
}
|
|
69
|
+
for (const m of message.matchAll(/Error Number: (\d+)/g)) candidates.push(Number(m[1]));
|
|
70
|
+
for (const code of candidates) {
|
|
71
|
+
const info = ESCROW_ERRORS[code];
|
|
72
|
+
if (info) return { code, ...info };
|
|
73
|
+
}
|
|
74
|
+
for (const [code, info] of Object.entries(ESCROW_ERRORS)) {
|
|
75
|
+
if (new RegExp(`\\b${info.name}\\b`).test(message)) return { code: Number(code), ...info };
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "Snapshot of the devnet escrow Config account (getAccountInfo, base64) taken when the v2 fixtures were built.",
|
|
3
|
+
"address": "7HXi3y1i3p4LVV3WGV6R4CM7waxNAXrjCX6SRSUcjEca",
|
|
4
|
+
"owner": "2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a",
|
|
5
|
+
"data_base64": "mwyq4B76zIKW202tPDdOkYY2QQSUHVPaQPTp1RCoPYDbrYr3viyq6AZ/1+SgwJ+6qgP06ONyeuY1+/CpwGlQo1QkW8/pmAQoBn/X5KDAn7qqA/To43J65jX78KnAaVCjVCRbz+mYBCgGf9fkoMCfuqoD9OjjcnrmNfvwqcBpUKNUJFvP6ZgEKAAACgAAAAAAAAAADgQAAAAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
|
|
6
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "Real v2 lottery (Operator co-signed) funding response, built on devnet by solo_firebase main 358df1e's own builders (describeFundingTransactionV2 + buildOperatorCoSignedTransaction) for the never-funded test sponsor in test-keypair.pubkey. Never submitted.",
|
|
3
|
+
"response": {
|
|
4
|
+
"task_id": "1038",
|
|
5
|
+
"accounts": {
|
|
6
|
+
"program_id": "2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a",
|
|
7
|
+
"config": "7HXi3y1i3p4LVV3WGV6R4CM7waxNAXrjCX6SRSUcjEca",
|
|
8
|
+
"task": "HxGz9PPRknrjYMpEZBJFygbTsabyBJMJ5V7ieUz38WE5",
|
|
9
|
+
"vault": "Eg8Hj4oTRoy7xtA4vXpCRPyhvbBY3jCuM8otWsE5GSDN",
|
|
10
|
+
"whitelist": "97xTnhyGDmJkZsoNtcm7gjV48yfaBstijFDqiUFru7Jr",
|
|
11
|
+
"mint": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E",
|
|
12
|
+
"sponsor": "GXkK4gbmGPGFmB7vobHeY82ktbAw9VPnHZJits1P2Qjw",
|
|
13
|
+
"sponsor_token_account": "BT5mmmDkqBDkm1LzhA9NaiEg8iLeVnyVoQztYVwNn51V"
|
|
14
|
+
},
|
|
15
|
+
"declared": {
|
|
16
|
+
"budget": "10000",
|
|
17
|
+
"base_pool": "5000",
|
|
18
|
+
"lottery_winner_count": 1,
|
|
19
|
+
"lottery_prize_per_winner": "2000",
|
|
20
|
+
"qualify_deadline": "1790746898",
|
|
21
|
+
"settlement_deadline": "1790754098",
|
|
22
|
+
"seed_commit": "011d2003d45b7077279624af04893449e3c9b9ca7af24f0b66392a51d436818d",
|
|
23
|
+
"max_fee_bps": 0,
|
|
24
|
+
"operator_cosigned": true
|
|
25
|
+
},
|
|
26
|
+
"transaction_base64": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+UiU+WXJ0VjmtoyW2tOvlwe7hgrpcUWRt9cqkEtbxwbKD5pDAVWMZY/sZJfM85vFSRPplFA0JKr+VFvOou6QLAgEGDOa/s1hzUJIzu8ouno08w0xOKRpCxclFPd0LvIgaV/R+Bn/X5KDAn7qqA/To43J65jX78KnAaVCjVCRbz+mYBChdYiLKQxJO7f2wf2Zen2PiT6lZjCsYDNgDlIVDr9MRw5tDXa3ipzH/EOFvMWR2jqvY2kMEzBeqGI0KGtvR061Eyy3SlIlwIvFkjG6ewkxG4v6P+I3ZdywRzup40Q+5ZQn75AKI8/MlPZYADjzBWvE1+rf2jG+psyfR2BHLVNJUIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEcYq0VKhiU4ktY09qsij+rs+4b6Yt6VTnLfH9HKPyLcmlwpi3dEh8irDXYuBeelr9ra81Js5JF779Op1Y4ebznilsPINlCy+dlo0+WnBLgmlHMRNxcGJTTgj45SCbOkTxBwQrSJibjN7eiWjtGYLfQwfBf0s2Q6KtbBFFOSJw2EG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTR8me0KWjNV4HmGCSl7Z0eutyD9g5zgRFJDnDscS0FNAQcMAAIJCgUEAwsGAQgHVsJQBrTofzCrECcAAAAAAACIEwAAAAAAAAEAAADQBwAAAAAAABKhvGoAAAAAMr28agAAAAABHSAD1FtwdyeWJK8EiTRJ48m5ynryTwtmOSpR1DaBjQAA",
|
|
27
|
+
"blockhash": "4XtQ6pTDn6ypSdgmL9CYSj5AogBV8JkDMGPoCwMf8YXn",
|
|
28
|
+
"valid_until_slot": 493031885,
|
|
29
|
+
"message_sha256": "307bc3325cdb063f6e4ae32dd56831784029b71c4d202bc10ee35437c97ec8ff",
|
|
30
|
+
"escrow_interface": "v2",
|
|
31
|
+
"note": "co-signed by the platform Operator (required for a lottery): add your signature and submit exactly these bytes through confirm-funding — any change invalidates the co-signature. The blockhash expires in about 60-90 seconds; request a fresh transaction if signing takes longer"
|
|
32
|
+
},
|
|
33
|
+
"mission": {
|
|
34
|
+
"token_address": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E",
|
|
35
|
+
"onchain_status": "pending_funding",
|
|
36
|
+
"budget_raw": "10000",
|
|
37
|
+
"reward_per_human_raw": "1000",
|
|
38
|
+
"max_humans": 5,
|
|
39
|
+
"lottery_winner_count": 1,
|
|
40
|
+
"lottery_prize_per_winner_raw": "2000",
|
|
41
|
+
"qualify_deadline": 1790746898,
|
|
42
|
+
"settlement_deadline": 1790754098,
|
|
43
|
+
"seed_commit": "0x011d2003d45b7077279624af04893449e3c9b9ca7af24f0b66392a51d436818d",
|
|
44
|
+
"solana_quoted_fee_bps": 0
|
|
45
|
+
},
|
|
46
|
+
"program_id": "2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a",
|
|
47
|
+
"sponsor": "GXkK4gbmGPGFmB7vobHeY82ktbAw9VPnHZJits1P2Qjw",
|
|
48
|
+
"mint": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E"
|
|
49
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "Real v2 non-lottery funding response, built on devnet by solo_firebase main 358df1e's own builders (describeFundingTransactionV2 + buildUnsignedTransaction) for the never-funded test sponsor in test-keypair.pubkey. Never submitted.",
|
|
3
|
+
"response": {
|
|
4
|
+
"task_id": "1038",
|
|
5
|
+
"accounts": {
|
|
6
|
+
"program_id": "2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a",
|
|
7
|
+
"config": "7HXi3y1i3p4LVV3WGV6R4CM7waxNAXrjCX6SRSUcjEca",
|
|
8
|
+
"task": "HxGz9PPRknrjYMpEZBJFygbTsabyBJMJ5V7ieUz38WE5",
|
|
9
|
+
"vault": "Eg8Hj4oTRoy7xtA4vXpCRPyhvbBY3jCuM8otWsE5GSDN",
|
|
10
|
+
"whitelist": "97xTnhyGDmJkZsoNtcm7gjV48yfaBstijFDqiUFru7Jr",
|
|
11
|
+
"mint": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E",
|
|
12
|
+
"sponsor": "GXkK4gbmGPGFmB7vobHeY82ktbAw9VPnHZJits1P2Qjw",
|
|
13
|
+
"sponsor_token_account": "BT5mmmDkqBDkm1LzhA9NaiEg8iLeVnyVoQztYVwNn51V"
|
|
14
|
+
},
|
|
15
|
+
"declared": {
|
|
16
|
+
"budget": "10000",
|
|
17
|
+
"base_pool": "10000",
|
|
18
|
+
"lottery_winner_count": 0,
|
|
19
|
+
"lottery_prize_per_winner": "0",
|
|
20
|
+
"qualify_deadline": "1790746899",
|
|
21
|
+
"settlement_deadline": "1790754099",
|
|
22
|
+
"seed_commit": "86b1c32bea6da1cb166282d19ff55af7001d941c28f05a31cdfc540a4a791741",
|
|
23
|
+
"max_fee_bps": 0,
|
|
24
|
+
"operator_cosigned": false
|
|
25
|
+
},
|
|
26
|
+
"transaction_base64": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAYL5r+zWHNQkjO7yi6ejTzDTE4pGkLFyUU93Qu8iBpX9H5dYiLKQxJO7f2wf2Zen2PiT6lZjCsYDNgDlIVDr9MRw5tDXa3ipzH/EOFvMWR2jqvY2kMEzBeqGI0KGtvR061Eyy3SlIlwIvFkjG6ewkxG4v6P+I3ZdywRzup40Q+5ZQn75AKI8/MlPZYADjzBWvE1+rf2jG+psyfR2BHLVNJUIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEcYq0VKhiU4ktY09qsij+rs+4b6Yt6VTnLfH9HKPyLcmlwpi3dEh8irDXYuBeelr9ra81Js5JF779Op1Y4ebznilsPINlCy+dlo0+WnBLgmlHMRNxcGJTTgj45SCbOkTxBwQrSJibjN7eiWjtGYLfQwfBf0s2Q6KtbBFFOSJw2EG3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqTR8me0KWjNV4HmGCSl7Z0eutyD9g5zgRFJDnDscS0FNAQYMAAEICQQDAgoFBgcGVsJQBrTofzCrECcAAAAAAAAQJwAAAAAAAAAAAAAAAAAAAAAAABOhvGoAAAAAM728agAAAACGscMr6m2hyxZigtGf9Vr3AB2UHCjwWjHN/FQKSnkXQQAA",
|
|
27
|
+
"blockhash": "4XtQ6pTDn6ypSdgmL9CYSj5AogBV8JkDMGPoCwMf8YXn",
|
|
28
|
+
"valid_until_slot": 493031885,
|
|
29
|
+
"escrow_interface": "v2",
|
|
30
|
+
"note": "blockhash expires in about 60-90 seconds; request a fresh transaction if signing takes longer"
|
|
31
|
+
},
|
|
32
|
+
"mission": {
|
|
33
|
+
"token_address": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E",
|
|
34
|
+
"onchain_status": "pending_funding",
|
|
35
|
+
"budget_raw": "10000",
|
|
36
|
+
"reward_per_human_raw": "2000",
|
|
37
|
+
"max_humans": 5,
|
|
38
|
+
"qualify_deadline": 1790746899,
|
|
39
|
+
"settlement_deadline": 1790754099,
|
|
40
|
+
"seed_commit": "0x86b1c32bea6da1cb166282d19ff55af7001d941c28f05a31cdfc540a4a791741",
|
|
41
|
+
"solana_quoted_fee_bps": 0
|
|
42
|
+
},
|
|
43
|
+
"program_id": "2CPC5V63FDs7SdWu89iSYYsTEpqBwuQeYuA9ASzuSo8a",
|
|
44
|
+
"sponsor": "GXkK4gbmGPGFmB7vobHeY82ktbAw9VPnHZJits1P2Qjw",
|
|
45
|
+
"mint": "ECXjKm8nNMYFaUuv19DRxSqMKDckmddgKhBHrjHWU73E"
|
|
46
|
+
}
|