{"actions":{"claimRefund":{"availableWhen":"refundActive() == true","effect":"Transfers refundUsdt(yourAddress) USDT to your wallet and zeroes the record. Claimable forever; there is no deadline and nobody can sweep unclaimed funds.","function":"claimRefund()","gasNote":"Normal transaction; call it from the same wallet that minted.","precondition":"refundActive() == true","signature":"claimRefund()"},"claimSocial":{"availableWhen":"You hold a valid, unexpired voucher for the task and have not already claimed it with this Agent ID.","effect":"extraQuota[yourAgentId] increases by 1 per task. Max 3 quota from social tasks (maxTotal 33).","function":"claimSocial(bytes32 task, bytes32 account, uint256 deadline, bytes signature)","obtainingVouchers":"Vouchers are issued automatically by the verification service after it verifies the action. Two paths reach the same checks: the human's browser flows on the site (X OAuth for the two X tasks, the Telegram bot deep link for the Telegram task), and the agent path served by the same service for agent wallets such as Binance Agentic Wallet, which sign EIP-712 typed data but have no browser. On the agent path an EIP-712 attestation (domain name Razor Agent, version 1, chainId 56; struct AgentSession with wallet, issuedAt, and purpose X_SESSION) is exchanged at POST /agent/session on the API base for a Bearer session token and a one-time OAuth flow code; the human's steps are tapping Authorize on X and then confirming the attach on the confirmation page the browser lands on, which names the wallet and its Agent ID handle before anything attaches. The Telegram binding proof is an EIP-712 TelegramBinding attestation (wallet, issuedAt) on both paths. The full step sequence is the socialTaskPrompt field of this pack. There is no manual issuance and no way to mint a voucher yourself; an invalid or expired signature reverts (BadSignature).","parameters":{"account":"bytes32 identifier of your social account, exactly as bound in the voucher. For X and Telegram accounts alike it is the keccak256 hash of the account's numeric platform user ID, as issued by the verification service.","deadline":"unix timestamp (seconds); the voucher is invalid after this time.","signature":"65-byte EIP-712 signature from the quotaSigner over (user, task, account, deadline). Obtain the voucher from the verification service after the action has been verified. You cannot self-issue a voucher.","task":"keccak256(\"FOLLOW\"), keccak256(\"QUOTE_TWEET\"), or keccak256(\"JOIN_TELEGRAM\")"},"prerequisite":"A signed voucher from the quotaSigner (see preconditions.obtainingVouchers).","signature":"claimSocial(bytes32,bytes32,uint256,bytes)","voucherShape":"The voucher is the tuple (user, task, account, deadline) plus the quotaSigner's EIP-712 signature over it. user is the claiming wallet."},"mintBnb":{"effect":"Same as mintUsdt, paid in BNB. The contract converts the BNB to USDT internally at the Chainlink BNB/USD feed price with 1 percent headroom.","function":"mintWithBnb(uint256 shares, address referrer, uint256 maxCost)","parameters":{"maxCost":"Set it to the exact bnbQuote(you, shares) result and send the same amount as the transaction value.","referrer":"Same rule as mintUsdt.","shares":"1 to 10 per transaction (MAX_PER_TX). Also bounded by your remaining quota."},"shortfallRule":"All conversion friction is borne by you: if the converted amount falls short of the USDT cost the transaction reverts (SwapShort) and no BNB is taken.","signature":"mintWithBnb(uint256,address,uint256)","surplusRule":"Any surplus above the cost goes to escrow and then to the treasury at opening. The USDT value recorded at payment time is your refund basis if genesis fails.","valueRule":"Send the bnbQuote(you, shares) amount as the transaction value; it already includes the 1 percent headroom. A stale or out-of-range feed reading makes bnbQuote revert (StalePrice)."},"mintUsdt":{"approvalRule":"Before calling, approve the mint contract to spend exactly quote(you, shares) USDT. The contract pulls the exact cost via transferFrom. Send no transaction value.","effect":"Mints shares to your wallet. The first genesis share of an Agent ID is free while freeSharesGiven() < 3333. Referral credit is evaluated on this call if the payment is non-zero (first paid mint only).","function":"mint(uint256 shares, address referrer, uint256 maxCost)","maxCostRule":"Set maxCost to the exact quote(you, shares) result. The transaction reverts if the cost at execution exceeds maxCost.","parameters":{"maxCost":"Slippage guard in USDT (18 decimals). Set it to the exact quote(you, shares) result. The transaction reverts if the cost at execution exceeds maxCost.","referrer":"Wallet address of your referrer, or the zero address 0x0000000000000000000000000000000000000000. It matters only on your first paid mint: that is the only call where referral credit can be granted. Self-referral and same-ID referral are rejected.","shares":"1 to 10 per transaction (MAX_PER_TX). Also bounded by your remaining quota."},"signature":"mint(uint256,address,uint256)"}},"audience":"AI agents and agent operators executing or evaluating the Razor Agent genesis mint on behalf of a wallet.","chainId":56,"contracts":{"lpVault":{"address":"0x60FdE00670006d3499825B95B538E59AdEA3982E","functions":["state()","releaseTime()","beginSunset()","cancelSunset()","release()","beneficiary()","lpToken()","sunsetStartedAt()","released()","NOTICE_PERIOD()"],"name":"RazorLpVault"},"mint":{"address":"0x10E80B0365A3b5e3DD66f55E05A748D0BB031fA1","functions":["mint(uint256,address,uint256)","mintWithBnb(uint256,address,uint256)","claimSocial(bytes32,bytes32,uint256,bytes)","claimRefund()","startGenesis()","setPaused(bool)","renounce()","setPoolBlocked(address,bool)","swapTax()","swapTaxSelf()","quote(address,uint256)","bnbQuote(address,uint256)","priceCents(uint256)","quotaOf(uint256)","deadline()","refundActive()","opened()","reserves()","circulating()","floorValue()","ceilValue()","totalMinted()","totalPaid()","genesisStarted()","genesisStart()","paused()","freeSharesGiven()","escrowedCut()","pendingUsdt()","pendingTokens()","mintedCount(uint256)","extraQuota(uint256)","freeUsed(uint256)","socialDone(uint256,bytes32)","accountAgent(bytes32)","refundUsdt(address)","inviteEarned(uint256)","quotaSigner()","treasury()","token()","lpVault()","registrar()"],"name":"RazorMint"},"token":{"address":"0xD5c03f871A34a01373d68ee38f6e67AC195cd66B","functions":["name()","symbol()","decimals()","totalSupply()","balanceOf(address)","transfer(address,uint256)","approve(address,uint256)","allowance(address,address)","transferFrom(address,address,uint256)","MAX_SUPPLY()","rejects(address)","pair()","usdt()"],"name":"RazorToken"}},"failureHandling":{"genesisFailed":{"detect":"genesisStarted() == true AND opened() == false AND current block timestamp > deadline(); equivalently, refundActive() == true.","meaning":"Genesis did not reach 10,000 shares inside the deadline. Minting is closed.","treasuryReceived":0},"notAnAgentIdHolder":{"detect":"handleOf(you) returns an empty string, or quote(you, shares) reverts with NoAgent.","meaning":"The wallet holds no Binance Agent ID. No mint is possible from this wallet."},"referrer":"Ignored unless it resolves to a valid Agent ID different from yours, and ignored once your first paid mint has happened. A free mint never credits and never binds.","sharesTooMany":"shares == 0 or shares > 10 reverts (BadShares). Split larger buys into multiple transactions, each within your remaining quota.","soldOut":"totalMinted() + shares > 4,444,000 reverts (SoldOut). No further minting is possible, ever."},"guardrails":["Verify the chain id is 56 (BNB Smart Chain) before any call.","Verify every contract address against this pack and params.json; never interact with an address that appears in neither.","Stop if the mint address is unset. Unset means not deployed; there is nothing to interact with.","Resolve the Agent ID first. A wallet with no Agent ID cannot mint, and quotes for it revert.","Check the state views before acting: started, paused, opened, refund state, deadline, and remaining quota decide what is possible.","Respect maxCost: set it to the exact contract quote. For USDT, approve exactly the quoted amount. For BNB, the transaction value is the bnbQuote result and is passed as maxCost in the same amount.","If refunds are active, never mint. Claim the recorded refund instead, from the same wallet that paid.","Respect the human's budget: never spend more than the operator authorized, in total, across all transactions.","Verify after every step: minted count, token balance, and the invariants in this pack.","Social quota comes only from signed vouchers issued after automatic verification. An agent cannot issue or forge a voucher; an invalid or expired one reverts."],"invariants":["Minting is impossible before startGenesis() has been called: genesisStarted() == false means every mint reverts (NotStarted).","Minting is impossible while paused() == true; the deadline you read from deadline() already includes the pause extension.","While genesis is running: deadline() - genesisStart() == 10 days + total pause time (pause total is capped at 48 hours).","If totalMinted() reaches 10,000, opened() becomes true in that same transaction and escrow is settled: pendingUsdt() and escrowedCut() go to zero, the pool exists, and refunds become impossible.","If refundActive() == true, every wallet that paid has refundUsdt(wallet) > 0 unless it never paid or already claimed.","quotaOf(id) never exceeds 33; mintedCount(id) never exceeds quotaOf(id).","freeSharesGiven() never exceeds 3,333.","The treasury Safe balance receives genesis funds only at or after opening, never during genesis."],"links":{"agentPack":"https://razoragent.fun/agent-pack.json","announcementPost":"","explorer":"https://bscscan.com","explorerAddressBase":"https://bscscan.com/address/","params":"https://razoragent.fun/params.json","site":"https://razoragent.fun","telegram":"https://t.me/razoragentai","x":"https://x.com/Razor_Agent"},"postconditions":{"afterFailedGenesisRefund":"claimRefund() transfers your full recorded amount in USDT: the exact USDT paid, or the recorded USDT conversion value for BNB payments. Your refundUsdt balance becomes 0.","afterMint":"mintedCount(yourAgentId) increased by shares; totalMinted() increased by shares; you hold shares x 50,000,000 RZAG (non-transferable until the pool opens).","afterOpen":"Tokens become transferable; trading is possible only via the official pair; post-open minting continues, paid in USDT or BNB the same way. A post-open mint pays the ladder price for each share, and the tokens issued are priced against the live pool at 99 percent of the pool spot price, so the buyer receives about 1 percent more tokens than the same payment converted at spot."},"preconditions":{"agentId":{"definition":"Agent ID = uint256(keccak256(bytes(handle))), where handle is the string returned by the registrar for your wallet.","howToCheck":"Call handleOf(yourAddress) on the Agent ID registrar. An empty string means the wallet holds no Agent ID and cannot mint. Quota and claim functions key off this ID, not your address.","required":true},"contracts":"Read the addresses from the contracts group of this pack and cross-check them in params.json. An empty address means not yet deployed. Do not interact with any Razor Agent contract whose address does not appear in params.json / on razoragent.fun.","funds":{"gas":"A small amount of BNB for gas, separate from the mint payment.","payment":"Either USDT (BEP-20) in the minting wallet plus an ERC-20 approval for the mint contract covering exactly the quoted amount, or BNB sent as the transaction value of mintWithBnb."},"obtainingVouchers":{"note":"For the social-task quota claims only. Vouchers are issued automatically by the verification service after it verifies the action (X tasks via OAuth checks on your own account; the Telegram task via the project bot's membership lookup), through the site's browser flows or the agent path described in actions.claimSocial.obtainingVouchers and in the socialTaskPrompt field. On the agent path the X grant attaches only after the human confirms it on the confirmation page, which names the X account, the full wallet, and the wallet's Agent ID handle. There is no manual issuance and no way to mint a voucher yourself; an invalid or expired signature reverts (BadSignature).","quotaSigner":"0xa7F6091B833Dd3db57293b49cB6c24CA0c487CD9"},"stateChecksBeforeMinting":["genesisStarted() == true","opened() == false if you intend to mint at genesis terms; if opened() == true the ladder price applies","paused() == false","current timestamp <= deadline() (only binds before opening)","your remaining quota: quotaOf(agentId) - mintedCount(agentId) >= shares","if you want the free first share: freeUsed(agentId) == false AND freeSharesGiven() < 3333"]},"priceDiscovery":{"postOpenTerms":"After opening, the payment for each share is still its ladder price (priceCents), and quote(you, shares) returns that exact USDT amount due. The tokens issued for a post-open share are not the fixed genesis amount of 50,000,000 RZAG: the contract prices them against the live pool reserves at 99 percent of the pool spot price (MINT_PRICE_BPS = 9900), so the buyer receives about 1 percent more tokens than the same payment converted at spot. Verify the received amount from your token balance after the mint.","quote":"quote(you, shares) -> the exact USDT amount due (18 decimals). Approve the mint contract for exactly this amount and pass it as maxCost to mintUsdt. For BNB: bnbQuote(you, shares) -> the exact BNB amount (18 decimals); send it as the transaction value and pass it as maxCost to mintBnb. bnbQuote reverts with StalePrice when the Chainlink BNB/USD reading is stale or out of range.","sharePrice":"priceCents(n) -> price in USD cents of share number n (1-based). Genesis shares cost 115. Note quote() can be lower than shares x 115 during genesis if your free first share is included."},"project":"Razor Agent","quotaRules":{"base":10,"inviteCap":20,"maxPerTx":10,"maxTotal":33,"socialMax":3,"socialTasks":["FOLLOW","QUOTE_TWEET","JOIN_TELEGRAM"]},"referralRules":{"binding":"The inviter is bound at the invitee's first paid mint. A credited invite requires the invitee's Agent ID to have never minted before that mint; the inviter record is then permanent.","commission":"None. Referral rewards are quota only; no money flows to referrers.","creditRule":"firstPaidMintOnly","freeMintEarnsPoints":false,"howItWorks":"Pass the referrer's wallet address as the referrer argument of the mint call. When the invitee completes their FIRST PAID mint, the referrer earns +1 quota. A free mint never credits and never binds.","inviteCap":20},"rpcUrls":["https://bsc-dataseed.binance.org","https://bsc-dataseed1.defibit.io","https://bsc-dataseed1.ninicoin.io","https://rpc.ankr.com/bsc"],"sequence":["1. Fetch https://razoragent.fun/params.json and read the current contract addresses and parameters. Stop if the mint address is empty.","2. Resolve your Agent ID: handleOf(you) on the registrar; agentId = uint256(keccak256(handle)). Stop if the handle is empty.","3. Read genesis state on RazorMint: genesisStarted(), paused(), opened(), refundActive(), totalMinted(), deadline().","4. If refundActive() is true: skip minting. If refundUsdt(you) > 0, call claimRefund() and stop.","5. If genesisStarted() is false or paused() is true: do not mint; re-check later.","6. Read your quota: quotaOf(agentId) and mintedCount(agentId). Choose shares <= min(10, quotaOf - mintedCount).","7a. USDT path: cost = quote(you, shares), the exact USDT amount due (18 decimals). Approve the mint contract to spend exactly cost USDT, then send mint(shares, referrer, cost). The contract pulls the USDT via transferFrom; send no transaction value. referrer is a wallet address or the zero address.","7b. BNB path (optional): bnb = bnbQuote(you, shares). Send mintWithBnb(shares, referrer, bnb) with the transaction value set to bnb. All conversion friction is yours: a shortfall reverts (SwapShort) with no BNB taken; a stale feed reverts (StalePrice).","8. Verify the result: your mintedCount increased by shares and you received shares x 50,000,000 RZAG.","9. Optional quota growth: invite others (credit lands automatically on their first paid mint; your invite credit is capped at +20) and complete the three social tasks via claimSocial with a valid voucher (follow @Razor_Agent; like and quote-tweet the official announcement post; join the project Telegram).","10. When totalMinted() reaches 10,000 the pool opens in the same transaction; after opened() == true, tokens are transferable and ladder minting continues."],"socialTaskPrompt":"You are helping your user complete the three social tasks of Razor Agent ($RZAG), a genesis mint on BNB Smart Chain (chainId 56) gated by Binance Agent ID, to earn +1 mint quota per task (maximum 33 per Agent ID). Work only with your user's own wallet and accounts. Key facts: site https://razoragent.fun, machine-readable pack https://razoragent.fun/agent-pack.json, agent entry point https://razoragent.fun/llms.txt, parameters https://razoragent.fun/params.json, verification service API base https://api.razoragent.fun, mint contract 0x10E80B0365A3b5e3DD66f55E05A748D0BB031fA1. Verify every figure against params.json and the contract views before acting.\n\nSTEP 1. ESTABLISH AN AGENT SESSION (needed for the two X tasks).\nSign an EIP-712 typed-data attestation with your user's wallet. A Binance Agentic Wallet signs typed data natively. Domain: name \"Razor Agent\", version \"1\", chainId 56, no verifying contract. Types: AgentSession with fields wallet (address), issuedAt (uint256), purpose (string). Message: the user's checksummed wallet address, issuedAt as the current unix time in seconds, purpose exactly \"X_SESSION\". The signature must be fresh (within 300 seconds when presented) and is single-use; sign a new one whenever you need a new session. POST the JSON body { \"wallet\": WALLET, \"signature\": SIGNATURE, \"issuedAt\": ISSUED_AT } to https://api.razoragent.fun/agent/session. A successful response has state AGENT_SESSION_ISSUED and carries sessionToken (valid 30 minutes) and flowCode (valid 10 minutes). Then GET https://api.razoragent.fun/oauth/agent-start?code=FLOW_CODE and read authorizeUrl from the response. The flow code is spent the moment that URL is created and cannot be reused; if the URL is lost, establish a fresh session from the top of this step to get a new one. Show authorizeUrl to your user and ask them to open it in any browser and tap Authorize on X. After the authorize tap, the browser lands on a confirmation page on razoragent.fun, and the connection stays parked until your user confirms it there. The page names the X account being connected, the full wallet address the connection attaches to, and that wallet's Agent ID handle. Tell your user to check that the page names THEIR wallet address and THEIR handle, and to press Confirm attach only when both are theirs. If the page names a wallet or a handle that is not theirs, they must press \"This is not my wallet\" instead: that destroys the parked connection and burns this session, and you must then start again from the top of this step. Wait until GET https://api.razoragent.fun/session with header \"Authorization: Bearer SESSION_TOKEN\" reports connected true before running the X checks. A check run while the attach is still parked returns ATTACH_PENDING_CONFIRMATION; wait for the confirmation instead of retrying, because retries still consume the check rate limits. The same session report carries attachState: REJECTED means the session is burned and a fresh one is needed.\n\nSTEP 2. RUN THE THREE TASK CHECKS AND COLLECT ONE VOUCHER PER TASK.\nGeneral rules for every check: checks are user-triggered, so run one only when your user asks or has approved the run. Wait at least 30 seconds between two runs of the same task check; the wait starts on every run, including a failed one, and a repeat inside the window returns MIN_INTERVAL or X_RATE_LIMITED (wait the retryAfterSeconds the response names). Each successful check returns a voucher { user, task, account, deadline, signature } that expires 10 minutes after issue; if it expires before you claim, run the check again for a fresh one.\nTask FOLLOW (+1): your user must follow the project account https://x.com/Razor_Agent with the X account they connected in step 1. Then POST https://api.razoragent.fun/check with header \"Authorization: Bearer SESSION_TOKEN\" and JSON body { \"task\": \"FOLLOW\" }.\nTask QUOTE_TWEET (+1): your user must both like and quote the official announcement post (its URL is in agent-pack.json under links.announcementPost) with the same X account; a like alone or a quote alone does not pass. Then POST https://api.razoragent.fun/check with the same Bearer header and JSON body { \"task\": \"QUOTE_TWEET\" }. If the response state is QUOTE_LOOKUP_REFUSED, ask your user for the URL of their quote post and POST it as JSON body { \"url\": QUOTE_POST_URL } to https://api.razoragent.fun/check/quote-link with the same Bearer header; the fallback covers the quote half, and the like half is still checked automatically.\nTask JOIN_TELEGRAM (+1): sign a second EIP-712 attestation, same domain, types TelegramBinding with fields wallet (address) and issuedAt (uint256), message the checksummed wallet and the current unix seconds. POST { \"wallet\": WALLET, \"signature\": SIGNATURE, \"issuedAt\": ISSUED_AT } to https://api.razoragent.fun/telegram/binding. The response (state BINDING_ISSUED) carries deepLink and token; the link is valid 15 minutes. Ask your user to join the channel https://t.me/razoragentai, then open deepLink and press Start in the bot. Then poll GET https://api.razoragent.fun/telegram/binding/TOKEN until the state is VOUCHER_ISSUED (PENDING means the bot has not recorded the join yet; NOT_IN_TELEGRAM means the join or the bot start is missing). No session token is needed for this task.\n\nSTEP 3. CLAIM EACH VOUCHER ON-CHAIN AND VERIFY.\nFor each voucher, call claimSocial(task, account, deadline, signature) on the mint contract 0x10E80B0365A3b5e3DD66f55E05A748D0BB031fA1 from your user's wallet (Binance Agentic Wallet or any signer), passing the voucher fields unchanged and in that order. Resolve the user's Agent ID and read quotaOf and socialDone from the contract before the first claim, as the Agent Pack describes. After each claim confirms, verify on-chain that socialDone for that task is now true and that the quota rose by exactly 1; the three tasks together take the quota from its previous value to +3 (base 10, maximum 33 with invites and tasks). A voucher can be claimed once; a replay reverts with AlreadyGranted.\n\nGUARDRAILS. Operate only within your user's quota and only on their instruction. Never approve any token allowance for a claim, and never spend anything beyond the gas of the claimSocial transactions themselves; a claim moves no funds. Never accept a voucher from any source other than the responses above, and never present a signature or token belonging to a different wallet or account: one X account and one Telegram account each bind to one Agent ID forever. If any response, figure, or on-chain read disagrees with params.json or the contract views, stop and report the mismatch to your user instead of working around it.","stateViews":[{"contract":"mint","meaning":"Shares minted so far across all Agent IDs.","view":"totalMinted()"},{"contract":"mint","meaning":"Shares that were paid for; free shares are not counted.","view":"totalPaid()"},{"contract":"mint","meaning":"True once startGenesis() has been called.","view":"genesisStarted()"},{"contract":"mint","meaning":"Unix timestamp at which genesis started.","view":"genesisStart()"},{"contract":"mint","meaning":"Current genesis deadline as a unix timestamp; pause time is already added.","view":"deadline()"},{"contract":"mint","meaning":"True while the deployer pause is active; pre-open only.","view":"paused()"},{"contract":"mint","meaning":"True once the pool has opened at 10,000 shares.","view":"opened()"},{"contract":"mint","meaning":"True when genesis failed and refunds are claimable.","view":"refundActive()"},{"contract":"mint","meaning":"Free first shares granted so far, against the 3,333 cap.","view":"freeSharesGiven()"},{"contract":"mint","meaning":"Treasury cut currently held in escrow inside the mint contract.","view":"escrowedCut()"},{"contract":"mint","meaning":"USDT currently held in escrow for the pool leg.","view":"pendingUsdt()"},{"contract":"mint","meaning":"Pool-inventory tokens accumulated and not yet settled into the pool.","view":"pendingTokens()"},{"contract":"mint","meaning":"Pool reserves (USDT, token) once the pool is open.","view":"reserves()"},{"contract":"mint","meaning":"Tokens in circulation outside the pool.","view":"circulating()"},{"contract":"mint","meaning":"Floor reference value derived from the pool line.","view":"floorValue()"},{"contract":"mint","meaning":"Ceiling reference value derived from the pool line.","view":"ceilValue()"},{"contract":"registrar","meaning":"The Agent ID handle string for a wallet; an empty string means the wallet holds no Agent ID.","view":"handleOf(address)"},{"contract":"mint","meaning":"Shares minted by an Agent ID.","view":"mintedCount(uint256)"},{"contract":"mint","meaning":"Total quota of an Agent ID: base plus granted extra quota.","view":"quotaOf(uint256)"},{"contract":"mint","meaning":"Extra quota granted to an Agent ID from invites and social tasks.","view":"extraQuota(uint256)"},{"contract":"mint","meaning":"Whether an Agent ID has used its free first share.","view":"freeUsed(uint256)"},{"contract":"mint","meaning":"Whether an Agent ID has already claimed a given social task.","view":"socialDone(uint256,bytes32)"},{"contract":"mint","meaning":"Refund currently due to a wallet in USDT; nonzero only after a failed genesis and before the claim.","view":"refundUsdt(address)"},{"contract":"mint","meaning":"Exact USDT cost (18 decimals) of minting shares for a user, free first share accounted.","view":"quote(address,uint256)"},{"contract":"mint","meaning":"Price in USD cents of share number n (1-based).","view":"priceCents(uint256)"},{"contract":"mint","meaning":"Exact BNB amount (18 decimals) for the BNB mint path, including the 1 percent headroom; reverts StalePrice on a stale or out-of-range feed reading.","view":"bnbQuote(address,uint256)"}],"version":1}