# Symonfi in Hackathon, creating buidler react and storage.
# Terms
cStorage - Centralized Storage (by example Firebase, Postgres, etc.)
# Process - From Solidity to React component
1. Buidler run -> compiles .sol -> generates artifacts, typechain, deployment files.
2. Buidler plugin storage -> checks runs through all storage patterns. For each appointed smart contract pattern, the runtime checks the patterns against the abi's in artifacts. It should warn if interfaces are not fulfilled and come with a suggestion. If successful it should apply the pattern logic to a ts/tsx file. This ts/tsx file should expose all pattern interfaces and connect the react context for all smart contract and storage interactions.
3. Buidler plugin react - Should create a react context (component) for a react application. This context should provide access blockchain provider functions, the ts/tsx storage file, and all smart contract functions from Typechain.
2. Plugin takes artifacts, Typechain, deployment files and generates a react context where these files are initiated.
[](https://)
[Sequence](https://www.sequencediagram.org/index.html?presentationMode=readOnly#initialData=C4S2BsFMAICEFcQBMoCdoGUCeBbAZgPYB2I0ASvEaDpAFC0CGAxsAegCKQBuk4BADpFT1aAVQDOQgLQA+AMLhSALmhF+AD2gAjRCiHQA7g2BMAFrQUhZAdWNmVTAjn4go46ADpxBcNFnQAHSIAc0giIWNIdwZUUDxmYHEAGmhgLEEzBhAiFKRIfj5cMOBoPFcoj1pbE1NZDFZUBlDoFQoiaHEGpro+AVK2aEhmU2h+Y2AhInoEkC5IzC7Q2nq2brqcGOA5YmBGlgBBWABJFW3ncCxDMBHsidR4pkgAfmXFyAAeKSkMDdjtqj2wEOJ2gqCi8HAwFeq1CX3kihUmFMBAM0HgknQ4ngTEe4ncNDx3WgAyxwVCnRAxGJ7WRqNY0Ec50uBhAphKtyED0glRWjVhMgAKpBzpEAKIhbKQFSwBiSJDU0bGEaOIhlYIpULhRoTQKqygsSlEdzZDpOGBGS7AUzGBkMdpBcCRdBaGDoyDyrSXAjwYD8H2jcDwYLZHlvT5SIUiibi4PhFrkcGQ2hhJDQvmQOHVewJrFJvIzOY63ndKp2WqyADyPr9JRUAHEwhEdd7ff6WVbdZsQA9Eik0hlrdlcvlCjQqClOjCYGU3JUq63gLJIwUxRLwvXG9qYB5EpowQkGTtIOpgHPqz7w8vHdG11LQYmoVnTOH5zWVGDc1CgA)

# Buidler Symfoni React
Takes your Buidler context with solidity, typechain. deploy and creates a pluggable react context with contract loading, web3modal and ethers v5. All typed interfaces and ready.
React context (object) should have the following properties:
```typescript
cont buidlerPluginReact = {
ready: () => boolean,
provider: Ethers.provider,
[contractName : HolisticContractObject] : {
storage: {...HolisticObject} // If symfoni storage plugin is present,
contract: TypechainContract (class instance with provider),
factory: TypechainContractFactory (class instance with provider),
ready: boolean,
attach: (address: string) => Promise<Boolean>
}
}
```
:::info
Caution: If the react app buidlerPluginReact[contractName] instance switches to another instance(contractAddress) will mutate the object and rerender all other components dependent. This config may be an anti-pattern, and we should evaluate this later. Maybe give the developer a Pin function that copies the instance to the locale state or something.
:::
## Holistic object
### Package developer - One object that lets developers
* Interact with all contract functions
* Interact with storage functions
* Deploy a contract
* Connect to a contract instance
### Frontend developer - One object that lets developers
:::danger
Not sure about this
:::
# Buidler Symfoni Storage
Plugs into Buidler Symfoni React to provide a storage context i react application. Out of the box the storage plugin provides the frontend developer with easy access to storage providers in their react context. We will focus on providing support for [Textile](https://textile.io), but strive to make the interface applicable to any storage.
Buidler symfoni storage will also provide the developer will well tested patterns for interactions between storage and EVM. By example, saving a document hash on chain and the document data to storage. This can be achived with 3 lines of json config, some code generation for Solidity and typescript interfaces for the frontend.
## Pattern: document
Service providers want to attach a private document to contract(s) without saving the whole document on chain(privacy and traceability).
Developers want to save, get, check and list documents. By leveraging this pattern for a smart contract and centralizes storage we can provde a storage interface like this:
## Why not Swarm
* Not deletable.
* For most restricted access functions one would need to run its own node.
### Interfaces
#### saveDocument
```typescript=
saveDocument(document: blob, name: string, type: string, read: entityId [], update: entityId[], delete: entityId[] ) -> documentId
```
1. Creates a hash from document blob.
2. Create random pub/priv key.
3. Encrypts document blob with priv key return reference.
4. Save encrypted document reference data into manifest and encrypt manifest with each pub key in access list.
5. Save all manifests as an ACL with unuqie key. Return ACL key.
6. Saves document hash and ACL key to chain, saveDocument(hash, acl). (Probably need some kind of ACL on this function) returns chain document id
:::info
* Save rules in firestore must be updated to only allow new editions. Else anyone could overwrite.
* Else one need to process each request through a server which does not overwrite or checks blockchain for a empty reference or something.
:::
#### getDocument
```typescript=
getDocument(documentId) -> document { id: string, data : blob, valid: boolean, ...}
```
1. Get encrypted manifest from documentId
2. Decrypt document manifest.
3. Get encrypted file from decrypted manifest reference.
4. return decrypted document.
#### listDocuments
```typescript=
listDocuments() -> documentId []
```
1. Get a list of all documents from chain.
2. (if traceability) validates the data with its reference to smart contract instance.
3. returns list of data
:::info
* Access list must be public to be able to retreive semi performance optmized query. Decrypting all is probably not feasible.
* Access list could be only available through a centralized server.
:::
#### updateDocument
```typescript=
updateDocument(documentId, data {...}) -> Promise<boolean>
```
1. Creates a hash from document blob.
2. Use pk from manifest and encrypt document blob with pub key. Encrypt manifest with random pub key. Saves encrypted document and encrypted manifest to storage. Gets firestoreId back
3. Saves document hash and firestore id to chain.
4. Saves document hash and firestoreID to chain saveDocument(hash, ref).
5. returns firestoreId back
:::info
* Access list must be public to be able to retreive semi performance optmized query. Decrypting all is probably not feasible.
* Access list could be only available through a centralized server.
:::
#### deleteDocument
```typescript=
deleteDocument(documentId) -> Promise<boolean>
```
### Config
Requirements for this pattern
* Firestore connection config
* Functions interacting with the blockchain must be present in the smart contract.
* What smart contract to apply this pattern too.
Through config, the developer should be able to attach one or more patterns to a smart contract.
```typescript
type Storage = {
[network: string]: {
firestoreConfig: FirestoreConfigObject
[contractName: string]: {
pattern: "document" | "data";
target?: "eth" | "storage" // Defaults to storage
name?: string;
save?: string;
get?: string;
list?: string;
check?: string;
}[];
};
};
```
```javascript=
const storage = {
dev: {
firestoreConfig: {...}
SimpleStorage: [
{
pattern: "document", // can be document / data or any other patterns we create
target: "storage",
name: "dealAgreement",
save: "saveDocument",
get: "getDocument",
list: "listDocument",
check: "checkDocument",
},
],
},
};
```
When adding a pattern too buidler.config.ts/js we should perform a chech if the smart contract contains the needed functions and that the input and output parameters are correct. Else we should suggest functions needed.
Pattern property is the only required field. If the pattern property provided and nothing else, the property name will default to "document" and all the functions will default to by example *save: "saveDocument"* and so on. With this structure one would be able to simply provide two document patterns to a smart contract and differ then by name. If you need to specify a concrete function to call you can define that function for its interface in this config.
## Pattern: private data (storage auth)
Goal: Deletability, Privacy (restricted access)
Service providers want users to entrust private data to their storage. Sometimes they may want proof that some data has been stored (traceability). The user or developer may want to give certain entities the right to read, update, or delete data.
Developers want to save, get, check and list data blobs.
saveData(data : any, name: string, type : string, read: entityId [], update: entityId[], delete: entityId[] ) -> dataId
1. Saves data to firestore
2. (if traceability) save dataId and hash to chain and reference back to firestore.
3. returns dataId
listData() -> Data []
1. Firestore rules should only give a list of data that the entity has access too.
2. (if traceability) With the on-chain reference in the data, the data can be validated
3. returns list of data
getData() -> Data []
1. Firestore rules should only give back data that the entity has access too.
2. (if traceability) validates the data with reference to chain.
3. returns list of data
checkData() -> Data []
2. (if traceability) validates the data with reference to chain.
3. returns boolean
## Pattern: private parameter
Service providers have a solidity function where they want a paramtert to be only visible to a certain entity.
We will call certain entity; encryption target. Encryption target could either be set in the smart contract through a variable which must be an address, it can be set in the config through encryptionTarget or dynamically inputed when users run the function. If set to dynamic | undefined. The function generated will require encryptionTarget when run.
```typescript
type Storage = {
[network: string]: {
firestoreConfig: FirestoreConfigObject
[contractName: string]: {
pattern: "privateParameter";
function: string,
parameterPosition?: number // Defaults to 0
encryptionTarget?: string
}[];
};
};
```
```javascript=
const storage = {
dev: {
firestoreConfig: {...}
SimpleStorage: [
{
pattern: "privateParameter",
function: "issueByPartition",
parameterPosition: 2,
encryptionTarget "0x1h5io1hoj1okkjuhy4y14yuoi12yh4uio12u5135",
},
],
},
};
```
### Multi party encryption target (maybe)
If one need to give multiple entieties decryption access, one could encrypt a manifest for each entiety. Save all manifest in a list. Then reference that list in the parameter.
When someone wants to retrieve the data. They could lookup the list, try to decrypt each one. When successfull decryption, get reference to the data and decrypt the data with manifest decryption key.
# Storage auth (server)
A service (server running a centralized process) that lets anyone get an entityID if they can prove ownership over a public address (can be other types of authentication). When the proof is verified, the service generates an eneityId with the corresponding public address in the service provider's storage.
# Entity storage
Some data mapping userId to a public address. This data can then be used to create authentication rules (feks. in Firestore rules) on which users should be able to see what data.
# Questions
## Who should be primary / replica storage
Should chain or cStorage be the primary storage for the document/data?
For example, If a developer wants to list all documents. Should we do a query against cStorage or blockchain?
If the goal is traceability, then blockchain should be primary.
If goal is privacy/deletability the cStorage should be primary.