A crypto RFP should let three competent teams read the same document, price substantially the same work, identify substantially the same risks, and explain any differences.
If one bidder prices a prototype, another prices production infrastructure, and a third quietly assumes the buyer will handle deployment, audits, RPC costs, wallets, indexing, and maintenance, you do not have three comparable proposals.
You have three interpretations.
The RFP’s job is to remove interpretation before price competition begins.
Vague scope -> different assumptions -> incomparable bids -> change requests -> disputed acceptance -> disputed payment.
Gitcoin’s description of the RFP mechanism follows the same basic procurement logic: define the problem, requirements, objectives, success criteria, budget, and timeline before inviting competing proposals, then evaluate responses against predefined criteria and track execution against milestones and deliverables. See Gitcoin’s RFP mechanism guide.
This is a scoping and delivery template. It is not formal legal advice.
Stop requesting “a Web3 platform”
Start with the sentence that usually causes the damage.
Before: “Build us a Web3 platform.”
That statement specifies almost nothing.
What chain? What users? What transactions? Custodial or non-custodial? Existing contracts or new contracts? Upgradeable or immutable? Which wallets? Which tokens? Which oracle? Which indexer? Which backend? Which admin roles? Who controls deployment keys? Who pays infrastructure? What does “production ready” mean? Is an audit included? Who fixes audit findings? Who maintains the system after launch?
Now reconstruct it.
After:
Deliver a production web application allowing approved users to connect an EVM wallet, view positions indexed from the specified contracts, submit the four transactions listed in Appendix A, and receive confirmed transaction status in the interface. The supplier will deliver the frontend, indexing integration, contract interaction layer, automated tests, deployment configuration, operational documentation, and testnet deployment. Mainnet deployment will be executed by the buyer using buyer-controlled signing credentials after the acceptance conditions in Milestone 4 have passed.
That is priceable.
Another example:
Before: “Integrate Chainlink.”
After:
Integrate the specified price feed contracts on the named networks. Document feed addresses, decimal handling, heartbeat assumptions, stale-price behaviour, fallback behaviour, and failure conditions. Acceptance requires automated tests for normal prices, stale data, unavailable data, boundary values, and rejected transactions when the defined freshness threshold is exceeded.
Better.
And another:
Before: “Smart contracts must be secure.”
After:
Provide a documented contract threat model, explicit security invariants, unit tests, integration tests, property or invariant tests for the listed critical properties, static-analysis results, remediation of agreed audit findings, and a final test report tied to the release commit.
That is the pattern throughout the RFP.
Do not specify aspirations. Specify observable outputs.
Use this RFP skeleton
The following structure is designed for protocols, dApps, wallets, token systems, DeFi products, DAO tooling, blockchain infrastructure, integrations, and related crypto engineering.
Business objective
Do not begin with features.
Begin with the business result.
text
Copy
PROJECT OBJECTIVE
We are procuring [system/service].
The business objective is:
[measurable problem or outcome]
The system is intended to enable:
[specific user outcome]
The project will be considered commercially successful if:
[measurable success conditions]
This RFP does not ask the supplier to:
[list adjacent objectives explicitly excluded]
Bad:
Build a staking platform.
Better:
Allow holders of Token X to deposit the token into the protocol, accrue rewards according to the supplied reward rules, withdraw subject to the defined restrictions, and view current deposit and reward information through a browser interface.
Do not make vendors reverse-engineer your business model from a feature list.
Users and permissions
Name the actors.
text
Copy
USERS AND ROLES
The system has the following actors:
1. End user
2. Protocol administrator
3. Emergency operator
4. Treasury signer
5. Governance executor
6. Backend service
7. External integration
8. Read-only analyst
For each actor specify:
- actions permitted
- actions prohibited
- authentication method
- on-chain role, if any
- off-chain permissions, if any
- assets or data accessible
- maximum authority
- revocation process
“Admin” is not a sufficient role definition.
If one address can pause, upgrade, mint, withdraw treasury assets, alter oracle configuration, and replace implementation contracts, state that.
If those powers are separated, state that too.
Functional scope
Separate required behaviour from possible future behaviour.
text
Copy
IN SCOPE
FR-01:
User can connect the supported wallets listed below.
FR-02:
User can execute [transaction].
FR-03:
System displays [state] sourced from [contract/API/indexer].
FR-04:
Authorised role can execute [administrative action].
FR-05:
System rejects [invalid condition].
OUT OF SCOPE
- native mobile applications
- fiat onboarding
- governance design
- token economics design
- bridge development
- third-party security audit
- 24/7 production operations
- additional chains not explicitly listed
Number the requirements.
Then require bidders to answer each with:
Comply | Partial | Alternative | Excluded
This exposes hidden scope differences before award.
Specify architecture before asking for a fixed price
“Web3” is not an architecture.
Your RFP should identify either the required architecture or the architectural decisions that the supplier must make during a paid discovery milestone.
At minimum, specify:
| Area | RFP must state |
|---|---|
| Networks | Chain, Mainnet/testnet, L1/L2, supported network IDs |
| Smart contracts | New, existing, forked, upgradeable, immutable |
| Upgrade model | Proxy pattern, governance process, timelock, or no upgrades |
| Frontend | Framework constraints, hosting target, browser support |
| Backend | Required services, APIs, databases, queues |
| Indexing | Hosted indexer, custom indexer, direct RPC, required latency |
| Wallets | Exact wallet connection requirements |
| RPC | Required providers, buyer supplied or supplier supplied |
| Oracles | Provider, feeds, update assumptions, failure behaviour |
| Bridges | Specific bridge or interoperability dependency |
| Storage | On-chain, database, IPFS, object storage, other |
| Identity | Wallet-only, SIWE, OAuth, KYC vendor, allowlist |
| Cloud | Buyer account, supplier account, target provider |
| Observability | Logs, metrics, alerting, transaction monitoring |
| Admin control | Multisig, governance, EOA, hardware wallet, other |
For security-sensitive systems, the architecture section should also identify trust boundaries, privileged roles, external dependencies, asset flows, and assumptions.
This is not bureaucratic decoration. OWASP’s Smart Contract Security Verification Standard explicitly includes secure architecture, design principles, and threat modelling among its control groups, alongside access control, external communication, cryptography, oracle-related risks, business logic, and secure development and deployment practices. See the OWASP Smart Contract Security Verification Standard.
For an EVM project, use those control areas to force specificity.
text
Copy
THREAT MODEL REQUIREMENTS
Assets at risk:
[funds, governance power, credentials, user data, protocol state]
Privileged actors:
[list]
External trust dependencies:
[list]
Expected attacker capabilities:
[list]
Critical invariants:
[list]
Failure modes requiring protection:
[list]
Emergency actions:
[list]
Residual risks explicitly accepted by buyer:
[list]
Do not write:
Protect against hacks.
Write:
An unauthorised account must not be able to mint tokens, change the implementation contract, withdraw treasury assets, modify the oracle source, alter protocol fees, or acquire an administrative role through any externally callable path.
Now someone can test it.
Convert deliverables into milestones that can actually be accepted
Milestones are not calendar labels.
“Phase 1: Development” is not a milestone.
A milestone needs five components:
output + evidence + acceptance test + deadline + payment
A useful structure is:
| Milestone | Supplier delivers | Buyer verifies | Payment trigger |
|---|---|---|---|
| Discovery | requirements, architecture, threat model, dependency register | named documents approved | written acceptance |
| Core build | source code, tests, CI, test environment | specified automated tests pass | milestone acceptance |
| Integration | external integrations and end-to-end flows | integration scenarios pass | milestone acceptance |
| Security | security evidence, audit package, remediation | agreed findings resolved or disposition approved | security acceptance |
| Release | production candidate, deployment scripts, runbooks | release checklist passes | release acceptance |
| Handover | repositories, documentation, credentials transfer, training | buyer confirms control and access | final acceptance |
Then make each milestone precise.
Example milestone clause
Before:
Milestone 2: Smart contract development.
After:
text
Copy
MILESTONE: SMART CONTRACT IMPLEMENTATION
Supplier shall deliver:
1. Solidity source code for contracts A, B, and C.
2. Deployment scripts for Sepolia and Ethereum Mainnet.
3. Unit tests covering every externally callable state-changing function.
4. Integration tests covering the workflows in AC-01 through AC-08.
5. Invariant or property tests covering INV-01 through INV-05.
6. Generated ABI artefacts.
7. NatSpec documentation for public and external interfaces.
8. Updated architecture diagram.
9. Updated threat model.
10. Testnet deployment addresses.
11. Build and test instructions.
12. Commit hash identifying the milestone release.
Target date:
[date]
Acceptance:
All mandatory acceptance tests pass against the nominated release commit.
Payment:
[amount/percentage] becomes payable following written milestone acceptance.
Testing deserves this level of specificity because smart contract behaviour can become difficult or costly to change after deployment. Ethereum’s current developer documentation describes pre-Mainnet testing as a minimum security requirement and distinguishes unit, integration, property-based, manual, local-chain, and testnet approaches. See Ethereum’s smart contract testing guidance.
Do not therefore accept:
Tests included.
Ask which tests. Against which requirements. Running where. Producing what evidence.
Write acceptance tests before development starts
Every significant requirement should have an observable pass condition.
text
Copy
AC-01 WALLET CONNECTION
Given:
A user opens the production-candidate frontend using a supported browser.
When:
The user selects a supported wallet and approves connection.
Then:
The interface displays the connected address and current supported network.
Pass condition:
Successful on each wallet and browser combination listed in Appendix B.
For a contract:
text
Copy
AC-07 UNAUTHORISED WITHDRAWAL
Given:
Account A does not hold WITHDRAWER_ROLE.
When:
Account A calls withdraw(amount, recipient).
Then:
The transaction reverts.
No protocol balance changes.
No recipient balance changes.
Evidence:
Automated test included in the release repository and passing in CI.
For an external dependency:
text
Copy
AC-12 STALE ORACLE DATA
Given:
The oracle timestamp is older than the configured maximum age.
When:
A user attempts the price-dependent operation.
Then:
The operation follows the specified stale-data policy.
Pass condition:
Observed behaviour matches requirement FR-18.
For frontend work:
text
Copy
AC-21 TRANSACTION FAILURE
Given:
A submitted transaction reverts.
Then:
The UI does not display success.
The pending state terminates.
The user receives the defined failure state.
No duplicate transaction is automatically submitted.
“Looks good” is not acceptance.
Acceptance = specified expected result + reproducible test + evidence.
Treat security, deployment, repositories, and secrets as scope
This is where crypto RFPs become expensive after signature.
Someone eventually asks:
“Who was supposed to do that?”
Prevent the question.
Security scope
State whether the supplier must provide:
text
Copy
- threat modelling
- secure architecture review
- unit testing
- integration testing
- invariant/property testing
- fuzzing
- static analysis
- dependency scanning
- frontend security testing
- backend/API testing
- deployment review
- multisig configuration review
- governance transaction review
- audit preparation
- auditor support
- audit remediation
- audit re-test support
- bug bounty preparation
- incident-response documentation
Do not write “independent audit included” unless you mean it.
Specify:
text
Copy
AUDIT
Auditor selected by:
[buyer/supplier/jointly]
Auditor paid by:
[party]
Audit fee included in proposal:
[yes/no]
Audit scope:
[repositories/contracts/commit]
Audit timing:
[stage]
Supplier response obligations:
[required]
Remediation included:
[yes/no, limits]
Re-test included:
[yes/no]
Treatment of findings:
Critical:
High:
Medium:
Low:
Informational:
Who may approve accepted residual risk:
[role]
Also distinguish audit completion from system acceptance.
An audit report is an input.
It is not evidence that every functional requirement works.
Repository ownership
Specify the repository from day one.
text
Copy
REPOSITORIES
All project source code shall be maintained in:
[buyer-owned GitHub/GitLab organisation]
Required repositories:
[list]
Buyer shall retain administrator access throughout the engagement.
Supplier shall use:
[pull-request requirements]
[review requirements]
[CI requirements]
[release/tag convention]
Required handover artefacts:
- full source history
- issues required for handover
- CI configuration
- deployment scripts
- dependency files and lockfiles
- build instructions
- test instructions
- release notes
Then settle intellectual property and licensing separately with appropriate professional advice.
At the scoping level, answer:
Who owns newly created code?
Which pre-existing supplier components remain supplier-owned?
Which open-source licences apply?
Can the supplier reuse generic components?
When do ownership or licence rights become effective?
Does payment affect transfer?
Do not leave those answers implicit.
Secrets management
The public RFP should describe the process for secrets.
It should not contain the secrets.
OWASP recommends controlled storage, provisioning, auditing, rotation, centralisation or standardisation, and least-privilege access for secrets such as API keys, credentials, SSH keys, certificates, and related privileged material. See OWASP’s secrets management guidance.
Use a clause such as:
text
Copy
SECRETS
Production secrets shall not be committed to source control.
The proposal shall identify:
- secrets-management system
- secret owners
- supplier access requirements
- environment separation
- provisioning process
- rotation process
- revocation process
- emergency access process
- logging/audit requirements
- handover procedure
Production signing credentials remain under buyer control unless specifically stated otherwise.
Deployment responsibility
“Deploy to production” is dangerously underspecified.
Split it.
text
Copy
DEPLOYMENT RESPONSIBILITY MATRIX
Supplier:
- prepares deployment scripts
- produces deployment parameters
- performs rehearsal on specified testnet
- produces deployment runbook
- verifies bytecode/configuration
- supports production deployment
Buyer:
- controls production signing credentials
- approves final parameters
- signs production transactions
- pays gas
- controls cloud production account
- approves release
Post-deployment:
- supplier performs smoke tests
- buyer confirms administrative control
- deployed addresses are recorded
- contract verification is completed
- monitoring is confirmed operational
For upgradeable contracts, also specify who controls upgrade authority.
For a multisig, specify who supplies signers.
For governance-controlled deployments, specify whether governance lead time is part of the project schedule.
For a DAO, “deployment date” may be a dependency on proposal submission, voting, timelock, and execution. Put those dependencies in the plan instead of pretending the vendor controls them.
Price the hidden work before award
A useful RFP contains a dependency register.
text
Copy
BUYER-SUPPLIED DEPENDENCIES
D-01:
Final token economics supplied by [date].
D-02:
Brand assets supplied by [date].
D-03:
Buyer creates cloud account and grants required access by [date].
D-04:
Buyer provides test credentials for Integration X by [date].
D-05:
External auditor booking confirmed by [date].
D-06:
Governance approval expected by [date].
D-07:
Production multisig established before deployment.
Then specify what happens when a dependency is late.
Not the legal remedy. The schedule mechanism.
text
Copy
A missed buyer dependency shall be recorded within [X] business days together with its expected impact on the affected milestone dates.
Do the same for integrations.
For every third-party integration, request:
provider
product/API/contract
network
authentication
rate limits or commercial tier assumed
test environment
production environment
buyer account required
recurring cost owner
known dependency
failure behaviour
replacement or fallback requirement
“Wallet integration” might mean WalletConnect only.
It might mean injected wallets, mobile deep links, hardware wallets, chain switching, SIWE authentication, transaction simulation, gas estimation, account abstraction, and session persistence.
The price difference is not a vendor problem.
It is a scope problem.
Make maintenance and payment conditions measurable
“Three months of support” is weak.
Support doing what?
Write:
text
Copy
MAINTENANCE PERIOD
Term:
[date to date]
Included:
- correction of defects against accepted requirements
- dependency updates [defined limits]
- production incident investigation [defined limits]
- security remediation [defined limits]
- operational support [defined limits]
Excluded:
- new features
- new chains
- redesigned business logic
- third-party API replacement unless caused by supplier implementation defect
- regulatory changes
- token economics changes
Support hours:
[hours/time zone]
Severity definitions:
P1:
P2:
P3:
P4:
Target acknowledgement:
[per severity]
Target workaround:
[per severity, if applicable]
Target resolution:
[per severity, if applicable]
Monthly included effort:
[hours, if relevant]
Additional rate:
[rate]
Avoid fake precision. A guaranteed two-hour fix for an unknown critical protocol defect may be commercially meaningless. Distinguish acknowledgement, investigation, workaround, and permanent remediation.
Budget
Do not force vendors to guess whether you have £20,000 or £500,000 available.
State a range when procurement rules permit it.
text
Copy
BUDGET
Target budget range:
[amount to amount]
Currency:
[GBP/USD/EUR/etc.]
The proposed price must state whether it includes:
- discovery
- design
- smart contract development
- frontend
- backend
- infrastructure
- testing
- audit preparation
- independent audit fees
- audit remediation
- deployment support
- cloud/provider charges
- maintenance
- taxes
- travel
- third-party licences
For crypto-denominated payments, remove another ambiguity.
text
Copy
PAYMENT ASSET
Contractual price denomination:
[USD/GBP/etc.]
Settlement asset:
[USDC/USDT/ETH/etc.]
Settlement network:
[network]
Conversion rule, if required:
[defined mechanism]
Conversion timestamp:
[defined time]
Network fees paid by:
[party]
Required recipient wallet:
[process]
Payment trigger:
[accepted milestone/invoice/etc.]
Do not write:
25% in ETH.
Unless everyone knows whether that means 25% of a fiat-denominated milestone converted to ETH, or a fixed ETH amount agreed on signature.
Those are materially different payment terms.
Change control
No RFP survives contact with development unchanged.
That is normal.
Invisible change is not.
text
Copy
CHANGE REQUEST
A proposed change must state:
1. requirement being changed
2. reason
3. deliverables affected
4. acceptance tests affected
5. timeline impact
6. price impact
7. security impact
8. dependency impact
No scope change takes effect until approved through the agreed change-control process.
A feature request is not “small” because it fits in one sentence.
Small sentence != small engineering change.
Compare proposals against assumptions, not sales prose
Require every bidder to use the same response structure.
text
Copy
PROPOSAL RESPONSE FORMAT
1. Executive summary
2. Requirement compliance matrix
3. Proposed architecture
4. Security approach
5. Delivery team and named roles
6. Milestones
7. Deliverables per milestone
8. Acceptance dependencies
9. Project assumptions
10. Buyer dependencies
11. Third-party dependencies
12. Explicit exclusions
13. Risk register
14. Audit approach
15. Deployment approach
16. Maintenance proposal
17. Price by milestone
18. Third-party costs
19. Payment terms
20. Relevant prior work
Then score the same things across suppliers.
A practical evaluation model might weight:
| Criterion | What you are actually testing |
|---|---|
| Scope compliance | Did they price the thing requested? |
| Technical approach | Is the architecture credible? |
| Security approach | Have they understood the attack surface? |
| Delivery plan | Are dependencies and sequencing realistic? |
| Acceptance quality | Can deliverables be objectively verified? |
| Relevant experience | Have they shipped comparable systems? |
| Maintenance | Who owns problems after launch? |
| Price | What is the total comparable cost? |
| Exceptions | What did they remove, alter, or assume? |
Do not compare headline totals before normalising exclusions.
Proposal A at £80,000 is not cheaper than Proposal B at £110,000 if Proposal A excludes the audit, deployment, indexer, monitoring, remediation, and maintenance that Proposal B includes.
Create a bid-normalisation sheet.
text
Copy
Vendor A Vendor B Vendor C
Core build
Audit
Audit remediation
Infrastructure
Deployment
Documentation
Maintenance
Third-party fees
Optional items
Total comparable cost
Then add an assumption register.
text
Copy
ASSUMPTION A-04
Vendor assumes buyer supplies production RPC subscription.
Status:
Accepted / Rejected / Clarification required
Cost impact if false:
[amount]
Schedule impact if false:
[days]
This is where procurement gets useful.
Not at the pitch deck.
At the assumption boundary.
Keep confidential material out of the public RFP
A public crypto RFP can contain enough technical detail to support pricing without publishing operational secrets.
Publish requirements. Do not publish credentials.
Public specification != public security vault.
Do not put the following into a public RFP:
- private keys or seed phrases
- production API secrets
- cloud administrator credentials
- database credentials
- SSH private keys
- authentication tokens
- signing credentials
- unpublished recovery material
- secret multisig recovery procedures
- personal identity documents
- private customer or employee data
- non-public vulnerability details
- unremediated exploit instructions
- confidential audit material
- confidential commercial agreements
- vendor credentials supplied under restricted terms
- internal incident-response access details
Also consider whether detailed internal network diagrams, privileged service account names, exact emergency-access procedures, unreleased contract addresses, unreleased deployment parameters, and sensitive counterparty information belong in a restricted appendix rather than the forum post.
Use two layers.
text
Copy
PUBLIC RFP
Contains:
- objective
- scope
- functional requirements
- sanitised architecture
- required integrations
- sanitised threat categories
- deliverables
- milestones
- acceptance framework
- budget
- proposal requirements
- evaluation method
Then:
text
Copy
CONFIDENTIAL TECHNICAL PACK
May contain:
- detailed architecture
- restricted integration documentation
- non-public contract information
- security findings
- internal infrastructure details
- sensitive operational procedures
- confidential commercial constraints
Control access to the confidential pack.
Record who receives it.
State whether information disclosed during bidding must be deleted or returned after the process, subject to the actual contractual and legal arrangements your advisers put in place.
Do not solve an RFP ambiguity problem by creating a security problem.
The final scope test
Before publishing, take every important sentence and ask:
Could two reasonable vendors interpret this differently and still honestly claim compliance?
If yes, keep cutting.
Before: “Production ready.”
After: “All mandatory acceptance tests pass against release commit X, the nominated production deployment has been completed, required monitoring is operational, runbooks have been delivered, administrative control has been verified, and no unresolved security finding remains above the buyer’s stated release threshold.”
Before: “Full documentation.”
After: “Deliver architecture documentation, repository setup instructions, local build instructions, test execution instructions, deployment runbook, contract interface documentation, environment configuration reference, administrator runbook, incident-response contacts, known limitations, and maintenance handover notes.”
Before: “Ongoing support.”
After: “Provide the maintenance services, severity definitions, response obligations, exclusions, support window, included effort, and commercial rates stated in the maintenance schedule for the defined term.”
Before: “Complete integration.”
After: “The integration passes test cases INT-01 through INT-14 in the agreed test environment, production credentials have been provisioned by the buyer, failure handling has been demonstrated, observability is active, and the runbook identifies the integration owner and recovery procedure.”
That is the objective.
Not more words.
Less uncertainty.
Primary research question
Among completed crypto software procurements, does requiring milestone-specific acceptance tests and explicit buyer/supplier ownership boundaries at RFP stage reduce post-award scope changes, payment disputes, and delivery delays compared with RFPs that specify only feature lists and target dates?
That question is worth testing.
The likely mechanism is concrete: a detailed RFP forces assumptions into the open while bids are still competing. A vague RFP leaves those assumptions hidden until engineering begins, when changing vendor, architecture, price, or schedule is substantially harder.
The useful dataset would compare RFP specificity against subsequent change requests, milestone slippage, disputed deliverables, supplemental funding, and final cost. Gitcoin’s RFP model already treats predefined success criteria, budgets, timelines, evaluation criteria, milestones, and deliverables as core parts of structured procurement, making those variables natural candidates for measurement.
Until that evidence is assembled, use the safer operational rule:
If you cannot point to the artefact, test, owner, deadline, dependency, and payment trigger, the work is not fully scoped.
Who delivers what, by when, using whose access, verified how, owned by whom, paid when.
That is an RFP.