docs: bundled contract format description
This commit is contained in:
181
docs/BUNDLED_CONTRACT.md
Normal file
181
docs/BUNDLED_CONTRACT.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# Warp Bundled Contract Format
|
||||||
|
|
||||||
|
This document describes the core concepts behind the Warp bundled contract format.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The idea behind Warp Bundled Contract Format is to increase the Developer and User Experience.
|
||||||
|
Normally, when a contract is being deployed on Arweave, one have to wait some time:
|
||||||
|
|
||||||
|
1. for the contract's transactions mining (~2 minutes)
|
||||||
|
2. for the proper contract's transactions confirmation (assuming at least 10 blocks - ~20 minutes)
|
||||||
|
|
||||||
|
This in total gives ~20-25 minutes, which:
|
||||||
|
|
||||||
|
1. Breaks the DX, e.g. in case developer wants to quickly test the new contract version on Arweave mainnet
|
||||||
|
2. Breaks the UX, e.g. if given protocol deploys the contracts dynamically - e.g. via GUI (e.g. deploying
|
||||||
|
NFT collections, connecting deployed data with access rights, etc.)
|
||||||
|
|
||||||
|
Additionally, deploying contracts requires some amount of ARs in the wallet - which might further increase
|
||||||
|
the entry barrier, both for developers and given protocol users.
|
||||||
|
|
||||||
|
## Advantages of using Warp Gateway for contracts deployment
|
||||||
|
1. Contract is instantly available - as soon as proper response from Bundlr network is received.
|
||||||
|
2. Contract deployment does not require any ARs in the wallet - the deployment via Bundlr network is either
|
||||||
|
fully subsidized by the Arweave (for transactions <= 100KiB) or by the Warp (for transactions > 100KiB).
|
||||||
|
The max transaction size is currently 2MiB.
|
||||||
|
3. Even though the Bundlr transactions are created and signed by the Warp's wallet, it is still possible to identify
|
||||||
|
the original transaction owner/signer.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Instead of posting the contract and contract source transactions directly to Arweave mainnet, both are sent to Warp
|
||||||
|
Gateway (`/gateway/contracts/deploy` endpoint) (this is the default behaviour of Warp's SDK `warp.createContract.deploy` function, when `forMainnet` instance is being used).
|
||||||
|
|
||||||
|
The Warp Gateway then:
|
||||||
|
|
||||||
|
1. Posts contract transactions (i.e. the base contract transaction and contract source transaction - or only the
|
||||||
|
contract interaction, if deploying from existing source) to the Bundlr network. Each contract transaction is sent as
|
||||||
|
a separate Bundlr transaction - as the `data` of the bundled transaction. The Bundlr transaction in this case might
|
||||||
|
be considered as a "carrier" of the original transaction. Additionally - some additional tags to the Bundlr transaction
|
||||||
|
are added.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const bTx = bundlr.createTransaction(JSON.stringify(transaction), {tags});
|
||||||
|
await bTx.sign();
|
||||||
|
const bundlrResponse = await bTx.upload();
|
||||||
|
```
|
||||||
|
|
||||||
|
Transaction which is sent to Bundlr, consists of:
|
||||||
|
|
||||||
|
| Transaction field | Value |
|
||||||
|
|---------------------------------------------|-------------------------------------------------------|
|
||||||
|
| `data` | The original transaction, JSON stringified |
|
||||||
|
| `tag['Uploader']` | `RedStone` |
|
||||||
|
| `tag['Uploader-Contract-Owner']` | The original owner/signar of the contract transaction |
|
||||||
|
| `tag['Uploader-Tx-Id']` | The id of the original transaction |
|
||||||
|
| ...all the tags of the original transaction | |
|
||||||
|
|
||||||
|
**NOTE** The original transaction is not modified in any way - this is to preserve the original
|
||||||
|
signature!
|
||||||
|
|
||||||
|
2. After receiving proper response and recipes from Bundlr, the Warp gateway indexes the contract
|
||||||
|
transactions data internally - to make them instantly available.
|
||||||
|
|
||||||
|
3. Finally, the Warp gateway returns an object as a `response` - that consists of fields:
|
||||||
|
- `response.contractId` - the original contract tx id
|
||||||
|
- `response.bundleContractId` - the Bundlr contract tx id
|
||||||
|
- `response.srcTxId` - the original contract source transaction id
|
||||||
|
- `response.bundleSrcId` - the Bundlr source tx id.
|
||||||
|
|
||||||
|
## Contract transaction retrieval via Arweave gateway
|
||||||
|
|
||||||
|
1. Directly via `response.bundleContractId` - e.g. https://arweave.net/Yy9WoplIYqy03O7_ovUr4TrvwryxHEneuNep7ATDftI
|
||||||
|
**NOTE 1** The response object contains the full, original tx - including its data and id
|
||||||
|
- `hs9JlOG0LMkTa4VdJ-nf6I46kLbWbCpvZczdl3N-ASQ` in this case.
|
||||||
|
**NOTE 2** The `data` field contains the original contract's data. Usually it is an initial contract state or an asset - for AtomicNFT contracts.
|
||||||
|
**NOTE 3** The `Yy9WoplIYqy03O7_ovUr4TrvwryxHEneuNep7ATDftI` is the Bundlr's tx id - assigned by
|
||||||
|
the `bundlr.createTransaction()`.
|
||||||
|
It is part of `ANS-104` bundle, that is uploaded to Arweave by Bundlr network - with the original tx as a `data-item`.
|
||||||
|
|
||||||
|
2. Using the GQL endpoint, using the original contract tx id (`hs9JlOG0LMkTa4VdJ-nf6I46kLbWbCpvZczdl3N-ASQ` in this case) and `Uploader-Tx-Id` tag, e.g.
|
||||||
|
|
||||||
|
```qql
|
||||||
|
query {
|
||||||
|
transactions(
|
||||||
|
tags: [{
|
||||||
|
name: "Uploader-Tx-Id",
|
||||||
|
values: ["hs9JlOG0LMkTa4VdJ-nf6I46kLbWbCpvZczdl3N-ASQ"]
|
||||||
|
}]
|
||||||
|
) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
tags {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
block {
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"transactions": {
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": "Yy9WoplIYqy03O7_ovUr4TrvwryxHEneuNep7ATDftI",
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "Uploader",
|
||||||
|
"value": "RedStone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Uploader-Contract-Owner",
|
||||||
|
"value": "33F0QHcb22W7LwWR1iRC8Az1ntZG09XQ03YWuw2ABqA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Uploader-Tx-Id",
|
||||||
|
"value": "hs9JlOG0LMkTa4VdJ-nf6I46kLbWbCpvZczdl3N-ASQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Uploader-Bundler",
|
||||||
|
"value": "https://node2.bundlr.network"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "App-Name",
|
||||||
|
"value": "SmartWeaveContract"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "App-Version",
|
||||||
|
"value": "0.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Contract-Src",
|
||||||
|
"value": "cK9mwwuR2CR72ubcI34ClssjQUL5G7cZEd649CVPJWw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SDK",
|
||||||
|
"value": "RedStone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"block": {
|
||||||
|
"height": 1013105
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**NOTE** The `transactions.edges.node.id` is an id of the Bundlr transaction - the 'carrier' of the original transaction.
|
||||||
|
|
||||||
|
## Contract transaction retrieval via Warp gateway
|
||||||
|
The Warp `/gateway/contract` endpoint allows to retrieve the Bundle contracts data directly via the original tx id.
|
||||||
|
This endpoint is used by default for loading contracts data by the Warp SDK - when `forMainnet` instance is being used.
|
||||||
|
|
||||||
|
|
||||||
|
## Contract transaction data retrieval
|
||||||
|
1. Using the Warp gateway - `gateway/contract-data/:original-tx-id`.
|
||||||
|
E.g.: https://gateway.redstone.finance/gateway/contract-data/hs9JlOG0LMkTa4VdJ-nf6I46kLbWbCpvZczdl3N-ASQ.
|
||||||
|
This endpoint underneath maps the original tx id to the Bundlr tx id.
|
||||||
|
Having the original Bundlr tx id - it loads the original tx data either from arweave.net cache - or fallbacks to the Bundlr node.
|
||||||
|
The data is then decoded using a dedicated function - https://github.com/warp-contracts/gateway/blob/main/src/gateway/router/routes/contractDataRoute.ts#L57
|
||||||
|
2. Using Arweave gateway -
|
||||||
|
1. get the Bundlr tx id - as shown in the GQL example
|
||||||
|
2. load the tx data using the `arweave.net/{txId}` endpoint
|
||||||
|
3. decode the response `data` field using the https://github.com/warp-contracts/gateway/blob/main/src/gateway/router/routes/contractDataRoute.ts#L57
|
||||||
|
algorithm.
|
||||||
@@ -28,10 +28,10 @@ async function main() {
|
|||||||
address: "http://13.53.39.138:5666"
|
address: "http://13.53.39.138:5666"
|
||||||
})
|
})
|
||||||
.build()*/
|
.build()*/
|
||||||
const contract = warp.contract("f4skRMstoodrRluvl4OCY-Xo50AamgxYwBCZKzw3Uvo");
|
//const contract = warp.contract("qx1z1YInqcp4Vf5amJER2R8E_SEyY6pmHS1912VSUAs");
|
||||||
|
|
||||||
|
|
||||||
/*const jsContractSrc = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.js'), 'utf8');
|
const jsContractSrc = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.js'), 'utf8');
|
||||||
const wasmContractSrc = fs.readFileSync(path.join(__dirname, 'data/rust/rust-pst_bg.wasm'));
|
const wasmContractSrc = fs.readFileSync(path.join(__dirname, 'data/rust/rust-pst_bg.wasm'));
|
||||||
const initialState = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.json'), 'utf8');
|
const initialState = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.json'), 'utf8');
|
||||||
|
|
||||||
@@ -40,35 +40,35 @@ async function main() {
|
|||||||
wallet,
|
wallet,
|
||||||
initState: initialState,
|
initState: initialState,
|
||||||
src: jsContractSrc,
|
src: jsContractSrc,
|
||||||
});*/
|
});
|
||||||
|
|
||||||
// case 2 - deploy from source, js contract
|
// case 2 - deploy from source, js contract
|
||||||
/*const contractTxId = await warp.createContract.deployFromSourceTx({
|
/*const {contractTxId} = await warp.createContract.deployFromSourceTx({
|
||||||
wallet,
|
wallet,
|
||||||
initState: initialState,
|
initState: initialState,
|
||||||
srcTxId: "Hj0S0iK5rG8yVf_5u-usb9vRZg1ZFkylQLXu6rcDt-0",
|
srcTxId: "Hj0S0iK5rG8yVf_5u-usb9vRZg1ZFkylQLXu6rcDt-0",
|
||||||
}, true);*/
|
});*/
|
||||||
|
|
||||||
// case 3 - full deploy, wasm contract
|
// case 3 - full deploy, wasm contract
|
||||||
/*const contractTxId = await warp.createContract.deploy({
|
/*const {contractTxId} = await warp.createContract.deploy({
|
||||||
wallet,
|
wallet,
|
||||||
initState: initialState,
|
initState: initialState,
|
||||||
src: wasmContractSrc,
|
src: wasmContractSrc,
|
||||||
wasmSrcCodeDir: path.join(__dirname, 'data/rust/src'),
|
wasmSrcCodeDir: path.join(__dirname, 'data/rust/src'),
|
||||||
wasmGlueCode: path.join(__dirname, 'data/rust/rust-pst.js')
|
wasmGlueCode: path.join(__dirname, 'data/rust/rust-pst.js')
|
||||||
}, true);*/
|
});*/
|
||||||
|
|
||||||
// case 4 - deploy from source, wasm contract
|
// case 4 - deploy from source, wasm contract
|
||||||
/*const contractTxId = await warp.createContract.deployFromSourceTx({
|
/*const {contractTxId} = await warp.createContract.deployFromSourceTx({
|
||||||
wallet,
|
wallet,
|
||||||
initState: initialState,
|
initState: initialState,
|
||||||
srcTxId: "5wXT-A0iugP9pWEyw-iTbB0plZ_AbmvlNKyBfGS3AUY",
|
srcTxId: "5wXT-A0iugP9pWEyw-iTbB0plZ_AbmvlNKyBfGS3AUY",
|
||||||
}, true);*/
|
});*/
|
||||||
|
|
||||||
/*const contract = warp.contract(contractTxId)
|
const contract = warp.contract(contractTxId)
|
||||||
.setEvaluationOptions({
|
/*.setEvaluationOptions({
|
||||||
bundlerUrl: "http://13.53.39.138:5666/"
|
bundlerUrl: "http://13.53.39.138:5666/"
|
||||||
})
|
})*/
|
||||||
.connect(wallet);
|
.connect(wallet);
|
||||||
|
|
||||||
await contract.writeInteraction<any>({
|
await contract.writeInteraction<any>({
|
||||||
@@ -84,7 +84,7 @@ async function main() {
|
|||||||
await contract.writeInteraction<any>({
|
await contract.writeInteraction<any>({
|
||||||
function: "storeBalance",
|
function: "storeBalance",
|
||||||
target: "M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI",
|
target: "M-mpNeJbg9h7mZ-uHaNsa5jwFFRAq0PsTkNWXJ-ojwI",
|
||||||
});*/
|
});
|
||||||
|
|
||||||
const {cachedValue} = await contract.readState();
|
const {cachedValue} = await contract.readState();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user