@hivemindhq/snap 1.1.0

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 ADDED
@@ -0,0 +1,218 @@
1
+ # Hive Mind Snap
2
+
3
+ A MetaMask Snap that displays real-time trust and reputation data from the [Intuition](https://intuition.systems) knowledge graph during transaction signing.
4
+
5
+ ## What Does This Snap Do?
6
+
7
+ When you're about to send a transaction to an address, the Hive Mind Snap shows you:
8
+
9
+ - **Trust Signals** — How many people have staked that the address is trustworthy (or not)
10
+ - **Aliases** — Community-assigned labels for the address
11
+ - **Stake Amounts** — The economic weight behind each trust signal
12
+ - **Your Position** — Whether you've already staked on this address
13
+ - **dApp Origin Trust** — Trust data for the dApp you're interacting with
14
+ - **Trusted Circle** — See which of your trusted contacts have staked on this address
15
+
16
+ This helps you make informed decisions before interacting with unknown addresses or dApps.
17
+
18
+ ## Features
19
+
20
+ | Feature | Description |
21
+ |---------|-------------|
22
+ | **Transaction Insights** | `onTransaction` hook displays trust data before you sign |
23
+ | **Trust Triple Display** | Shows support/oppose positions on `[address] has tag trustworthy` |
24
+ | **dApp Origin Trust** | Shows trust data for the dApp origin (transaction source) |
25
+ | **Trusted Circle** | Highlights when your trusted contacts have staked on an address |
26
+ | **Distribution Analysis** | Analyzes stake distribution health (concentrated vs. distributed) |
27
+ | **Alias Display** | Shows community-assigned aliases for addresses |
28
+ | **Multi-chain Support** | Works on Intuition Testnet (chain ID: 13579) and Mainnet (chain ID: 1155) |
29
+ | **Interactive UI** | Links to create trust signals or view more data on the web |
30
+ | **Persistent Cache** | Trusted circle cached for 1 hour for optimal performance |
31
+
32
+ ## Installation
33
+
34
+ ### From npm (once published)
35
+
36
+ ```bash
37
+ # The snap will be installable directly through MetaMask
38
+ # Package name: @hivemindhq/snap
39
+ ```
40
+
41
+ ### For Development
42
+
43
+ See the [Development](#development) section below.
44
+
45
+ ## Permissions
46
+
47
+ This Snap requires the following permissions:
48
+
49
+ | Permission | Purpose |
50
+ |------------|---------|
51
+ | `endowment:transaction-insight` | Display insights before transaction signing |
52
+ | `endowment:page-home` | Custom home page in MetaMask |
53
+ | `endowment:network-access` | Query the Intuition GraphQL API |
54
+ | `endowment:rpc` | Communicate with dapps |
55
+ | `snap_manageState` | Cache trusted circle data for performance |
56
+
57
+ ## Development
58
+
59
+ ### Prerequisites
60
+
61
+ - [MetaMask Flask](https://docs.metamask.io/snaps/get-started/install-flask) (development version of MetaMask)
62
+ - Node.js ≥ 18.6.0
63
+ - Yarn
64
+
65
+ ### Setup
66
+
67
+ 1. Clone the repository:
68
+ ```bash
69
+ git clone https://github.com/hivemindhq-io/snap.git
70
+ cd intuition-snap
71
+ ```
72
+
73
+ 2. Install dependencies:
74
+ ```bash
75
+ yarn install
76
+ ```
77
+
78
+ 3. Start the development server:
79
+ ```bash
80
+ yarn start
81
+ ```
82
+
83
+ 4. Open `http://localhost:8000` and connect the Snap to MetaMask Flask
84
+
85
+ ### Chain Configuration
86
+
87
+ By default, the Snap connects to **Intuition Testnet**. To use mainnet:
88
+
89
+ ```bash
90
+ yarn start:mainnet
91
+ ```
92
+
93
+ Or explicitly specify testnet:
94
+
95
+ ```bash
96
+ yarn start:testnet
97
+ ```
98
+
99
+ ## Testing
100
+
101
+ ### Automated Tests
102
+
103
+ Run the test suite:
104
+
105
+ ```bash
106
+ yarn test
107
+ ```
108
+
109
+ Tests use [`@metamask/snaps-jest`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-jest) for Snap-specific testing utilities.
110
+
111
+ **What's tested:**
112
+ - `onHomePage` handler — Renders correctly with expected content
113
+ - `Account.tsx` components — All UI rendering variations (26 tests)
114
+
115
+ ### Manual E2E Testing
116
+
117
+ The `onTransaction` handler requires network access to the Intuition GraphQL API. Because `@metamask/snaps-jest` runs the Snap in an isolated worker process, network requests cannot be mocked from the test process.
118
+
119
+ **To test transaction insights:**
120
+
121
+ 1. Start the development server: `yarn start`
122
+ 2. Open http://localhost:8000 in a browser with MetaMask Flask
123
+ 3. Install the Snap
124
+ 4. Initiate a transaction on Intuition Testnet/Mainnet
125
+ 5. Verify trust data displays correctly in the transaction confirmation
126
+
127
+ ## Architecture
128
+
129
+ ```
130
+ src/
131
+ ├── index.tsx # Entry point, exports handlers
132
+ ├── onTransaction.tsx # Transaction insight handler
133
+ ├── onUserInput.tsx # User interaction handler
134
+ ├── account.tsx # Account (destination) data fetching
135
+ ├── origin.tsx # dApp origin data fetching
136
+ ├── distribution.ts # Stake distribution analysis
137
+ ├── queries.ts # GraphQL queries for Intuition API
138
+ ├── config.ts # Chain configuration (testnet/mainnet)
139
+ ├── types.ts # TypeScript type definitions
140
+ ├── util.ts # Utility functions
141
+ ├── components/ # JSX UI components
142
+ │ ├── Account.tsx # Destination address display
143
+ │ ├── Origin.tsx # dApp origin display
144
+ │ ├── TrustedCircle.tsx # Trusted contacts display
145
+ │ ├── UnifiedFooter.tsx # Combined footer CTAs
146
+ │ ├── Footer/ # Account footer actions
147
+ │ └── OriginFooter/ # Origin footer actions
148
+ ├── trusted-circle/ # Trusted circle module
149
+ │ ├── service.ts # API & business logic
150
+ │ ├── cache.ts # Persistent cache
151
+ │ └── types.ts # Type definitions
152
+ ├── images/ # Snap icon assets
153
+ └── vendors/ # Vendor configuration (git-ignored)
154
+ ```
155
+
156
+ ## Configuration
157
+
158
+ Chain settings are defined in `src/config.ts`:
159
+
160
+ | Network | Chain ID | RPC URL | Currency |
161
+ |---------|----------|---------|----------|
162
+ | Testnet | 13579 | `https://testnet.rpc.intuition.systems` | tTRUST |
163
+ | Mainnet | 1155 | `https://rpc.intuition.systems` | TRUST |
164
+
165
+ ### Atoms Used
166
+
167
+ The Snap queries the Intuition knowledge graph using these predefined atoms:
168
+
169
+ | Atom | Purpose |
170
+ |------|---------|
171
+ | `hasTag` | Predicate for trust triples |
172
+ | `trustworthy` | The "trustworthy" characteristic |
173
+ | `hasAlias` | Predicate for alias relationships |
174
+
175
+ ## Building
176
+
177
+ ```bash
178
+ # Build the snap bundle
179
+ yarn build
180
+
181
+ # Clean and rebuild
182
+ yarn build:clean
183
+ ```
184
+
185
+ The built bundle is output to `dist/bundle.js`.
186
+
187
+ ## Linting
188
+
189
+ ```bash
190
+ # Run all linters
191
+ yarn lint
192
+
193
+ # Fix auto-fixable issues
194
+ yarn lint:fix
195
+ ```
196
+
197
+ ## Contributing
198
+
199
+ 1. Fork the repository
200
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
201
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
202
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
203
+ 5. Open a Pull Request
204
+
205
+ Please ensure:
206
+ - All tests pass (`yarn test`)
207
+ - Code passes linting (`yarn lint`)
208
+ - No `console.*` statements in production code
209
+
210
+ ## License
211
+
212
+ This project is dual-licensed under [Apache 2.0](../../LICENSE.APACHE2) and [MIT](../../LICENSE.MIT0).
213
+
214
+ ## Links
215
+
216
+ - [Intuition Documentation](https://docs.intuition.systems)
217
+ - [MetaMask Snaps Documentation](https://docs.metamask.io/snaps/)
218
+ - [Repository](https://github.com/hivemindhq-io/snap)
package/dist/bundle.js ADDED
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function n(t,e,n){if("string"==typeof t)throw new Error(`An HTML element ("${String(t)}") was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.`);if(!t)throw new Error("A JSX fragment was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.");return t({...e,key:n})}function r(t,e,r){return n(t,e,r)}function i(t){return Object.fromEntries(Object.entries(t).filter((([,t])=>void 0!==t)))}function o(t){return e=>{const{key:n=null,...r}=e;return{type:t,props:i(r),key:n}}}t.r(e),t.d(e,{onHomePage:()=>mt,onTransaction:()=>pt,onUserInput:()=>ht});const a=o("Box"),s=o("Heading"),l=o("Text"),c=o("Divider"),d=o("Link"),u={backendUrl:"https://mainnet.intuition.sh/v1/graphql",rpcUrl:"https://rpc.intuition.systems",chainId:1155,chainIdHex:"0x483",chainName:"Intuition Mainnet",chainKey:"intuition-mainnet",currencySymbol:"TRUST",decimalPrecision:18,hasTagAtomId:"0x6de69cc0ae3efe4000279b1bf365065096c8715d8180bc2a98046ee07d3356fd",trustworthyAtomId:"0xe9c0e287737685382bd34d51090148935bdb671c98d20180b2fec15bd263f73a",hasAliasAtomId:"0xf8cfb4e3f1db08f72f255cf7afaceb4b32684a64dac0f423cdca04dd15cf4fd6"},p=u,h=async(t,e)=>{const n=await fetch(p.backendUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:t,variables:e})});if(!n.ok)throw new Error(`GraphQL request failed: ${n.status} ${n.statusText}`);const r=await n.json();if(r.errors&&r.errors.length>0)throw new Error(`GraphQL error: ${r.errors[0].message}`);return r},m='\nquery TripleWithPositionAggregates($subjectId: String!, $predicateId: String!, $objectId: String!) {\n triples(where: {\n subject_id: { _eq: $subjectId },\n predicate_id: { _eq: $predicateId },\n object_id: { _eq: $objectId }\n }) {\n term_id\n subject_id\n predicate_id\n object_id\n creator_id\n counter_term_id\n\n # Main vault (support) market data\n term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n curve_id\n }\n }\n\n # Counter vault (oppose) market data\n counter_term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n curve_id\n }\n }\n\n # Triple-specific aggregated market data\n triple_term {\n term_id\n counter_term_id\n total_market_cap\n total_position_count\n }\n\n # Detailed triple vault data per curve\n triple_vault {\n term_id\n counter_term_id\n curve_id\n position_count\n market_cap\n }\n\n positions_aggregate {\n aggregate {\n count\n sum {\n shares\n }\n avg {\n shares\n }\n }\n }\n\n counter_positions_aggregate {\n aggregate {\n count\n sum {\n shares\n }\n avg {\n shares\n }\n }\n }\n\n positions(\n order_by: { shares: desc }\n limit: 30\n ) {\n id\n account_id\n term_id\n curve_id\n shares\n account {\n id\n label\n }\n }\n\n counter_positions(\n order_by: { shares: desc }\n limit: 30\n ) {\n id\n account_id\n term_id\n curve_id\n shares\n account {\n id\n label\n }\n }\n }\n chainlink_prices(limit: 1, order_by: { id: desc }) {\n usd\n }\n backup_chainlink_prices: chainlink_prices(\n limit: 1,\n order_by: { id: desc },\n where: { usd: { _is_null: false } }\n ) {\n usd\n }\n}\n',g="\nquery OriginAtom($originUrl: String!) {\n atoms(where: {\n _or: [\n { label: { _ilike: $originUrl } },\n { data: { _ilike: $originUrl } }\n ]\n }, limit: 1) {\n term_id\n type\n label\n image\n data\n emoji\n creator_id\n }\n}\n",_="\nquery UserTrustedCircle($userAddress: String!, $predicateId: String!, $objectId: String!) {\n positions(\n where: {\n account_id: { _ilike: $userAddress },\n triple: {\n predicate_id: { _eq: $predicateId },\n object_id: { _eq: $objectId }\n }\n },\n order_by: { shares: desc },\n limit: 200\n ) {\n triple {\n subject_id\n subject {\n label\n }\n }\n }\n}\n";var f,b;!function(t){t.NoAtom="NoAtom",t.AtomWithoutTrustTriple="AtomWithoutTrustTriple",t.AtomWithTrustTriple="AtomWithTrustTriple"}(f||(f={})),function(t){t.NoOrigin="NoOrigin",t.NoAtom="OriginNoAtom",t.AtomWithoutTrustTriple="OriginAtomWithoutTrustTriple",t.AtomWithTrustTriple="OriginAtomWithTrustTriple"}(b||(b={}));const v=(t,e)=>`caip10:${e}:${t}`,w=(t,e)=>{const n=BigInt(t),r=BigInt(10**e),i=n/r,o=(n%r).toString().padStart(e,"0").slice(0,6);return Number(`${i}.${o}`)},y=o("Section"),T=o("Row"),A=o("Address"),I=o("Bold"),C=o("Value"),S={"well-distributed":"success",moderate:"warning",concentrated:"warning","whale-dominated":"warning"},k={"well-distributed":"#22c55e",moderate:"#eab308",concentrated:"#f97316","whale-dominated":"#ef4444"},$={"well-distributed":"Well Distributed",moderate:"Moderate",concentrated:"Concentrated","whale-dominated":"Whale Dominated"},j={"well-distributed":"🟢 Distributed",moderate:"🟡 Moderate",concentrated:"⚠️ Concentrated","whale-dominated":"⛔️ Whale"};function P(t,e){const n=t.filter((t=>t>0));if(0===n.length)return 0;const r=n.reduce(((t,e)=>t+e),0);if(0===r)return 0;return[...n].sort(((t,e)=>e-t)).slice(0,e).reduce(((t,e)=>t+e),0)/r*100}const W={gini:{wellDistributed:.35,moderate:.55,concentrated:.75},top1:{wellDistributed:30,moderate:50,concentrated:80},minStakersForAnalysis:3};function N(t,e,n){const{gini:r,top1:i,minStakersForAnalysis:o}=W;return e>=i.concentrated?"whale-dominated":n<o?e>=i.moderate?"concentrated":0===n?"well-distributed":"moderate":t<=r.wellDistributed?"well-distributed":t<=r.moderate?"moderate":t<=r.concentrated?"concentrated":"whale-dominated"}function O(t){const e=t.filter((t=>t>0)),n=e.length,r=e.reduce(((t,e)=>t+e),0);if(0===n){const t="well-distributed";return{gini:0,nakamoto:0,top1Percent:0,top3Percent:0,stakerCount:0,totalShares:0,status:t,snapColor:S[t],hexColor:k[t],label:"No Stakes",shortLabel:"None"}}const i=function(t){const e=t.filter((t=>t>0)),n=e.length;if(0===n)return 0;if(1===n)return 0;const r=e.reduce(((t,e)=>t+e),0)/n;if(0===r)return 0;let i=0;for(let t=0;t<n;t++)for(let r=0;r<n;r++){const n=e[t],o=e[r];void 0!==n&&void 0!==o&&(i+=Math.abs(n-o))}const o=i/(2*n*n*r);return Math.max(0,Math.min(1,o))}(e),o=function(t){const e=t.filter((t=>t>0));if(0===e.length)return 0;const n=.51*e.reduce(((t,e)=>t+e),0),r=[...e].sort(((t,e)=>e-t));let i=0;for(let t=0;t<r.length;t++){const e=r[t];if(void 0!==e&&(i+=e,i>=n))return t+1}return r.length}(e),a=P(e,1),s=P(e,3),l=N(i,a,n);return{gini:i,nakamoto:o,top1Percent:a,top3Percent:s,stakerCount:n,totalShares:r,status:l,snapColor:S[l],hexColor:k[l],label:$[l],shortLabel:j[l]}}function x(t){return O(t.map((t=>t.shares)).filter((t=>!isNaN(t)&&t>0)))}function q(t){var e,n;if(!t||0===t.count)return O([]);const{count:r,sum:i,avg:o}=t,a=(null===(e=i)||void 0===e?void 0:e.shares)||0;null===(n=o)||void 0===n||n.shares;if(0===r||0===a)return O([]);let s,l;s=1===r?100:2===r?70:r<=5?100/Math.sqrt(r):Math.max(20,100/Math.pow(r,.7)),l=1===r?0:2===r?.5:r<=5?.6:r<=10?.5:.4;const c=N(l,s,r);return{gini:l,nakamoto:1===r?1:Math.ceil(.3*r),top1Percent:s,top3Percent:Math.min(100,1.3*s),stakerCount:r,totalShares:a,status:c,snapColor:S[c],hexColor:k[c],label:$[c],shortLabel:j[c]}}function U(t,e,n,r,i,o){const{level:a,ratio:s}=function(t,e){const n=t+e;if(0===n)return{level:"no-stakes",ratio:50};const r=t/n*100;return r>=70?{level:"trusted",ratio:r}:r>=30?{level:"mixed",ratio:r}:{level:"untrusted",ratio:r}}(t,e),l=n&&n.length>0?x(n):q(i),c=r&&r.length>0?x(r):q(o),d=function(t,e){const n=["well-distributed","moderate","concentrated","whale-dominated"];return n.indexOf(t)>=n.indexOf(e)?t:e}(l.status,c.status);return{trustLevel:a,trustRatio:s,forDistribution:l,againstDistribution:c,overallDistribution:d,overallSnapColor:S[d]}}function D(t){if(0===t.length)return"";const e=t.slice(0,3).map((t=>function(t){if(/^0x[a-fA-F0-9]{40}$/u.test(t))return`${t.slice(0,6)}...${t.slice(-4)}`;if(t.startsWith("caip10:")){const e=t.split(":"),n=e[e.length-1];if(n&&/^0x[a-fA-F0-9]{40}$/u.test(n))return`${n.slice(0,6)}...${n.slice(-4)}`}return t}(t.label)));if(t.length>3){const n=t.length-3;return`${e.join(", ")} +${n} more`}return e.join(", ")}const L=({forContacts:t,againstContacts:e})=>0===t.length&&0===e.length?null:r(y,{children:[n(s,{size:"sm",children:"Your Trusted Contacts"}),t.length>0&&n(T,{label:"FOR",children:n(l,{color:"success",children:n(I,{children:D(t)})})}),e.length>0&&n(T,{label:"AGAINST",children:n(l,{color:"warning",children:n(I,{children:D(e)})})})]}),M=()=>n(s,{size:"sm",children:"Destination"}),E=t=>t.map((t=>({shares:parseFloat(t.shares)||0}))),F=({alternateTrustData:t,isContract:e})=>{if(!t.hasAlternateTrustData)return null;const r=t.alternateIsCaip?`Also has data as a contract on ${p.chainName}`:"Also has data as an EOA";return n(l,{color:"default",children:r})},R={[f.NoAtom]:t=>{const{address:e,isContract:i,alternateTrustData:o}=t,a=i?"contract":"address";return r(y,{children:[n(M,{}),n(T,{label:"Address",children:n(A,{address:e})}),n(T,{label:"Status",variant:"warning",children:n(l,{color:"warning",children:r(I,{children:["Unknown ",a]})})}),n(l,{color:"default",children:"No community data on Intuition"}),n(F,{alternateTrustData:o,isContract:i})]})},[f.AtomWithoutTrustTriple]:t=>{const{address:e,account:i,alias:o,isContract:a,alternateTrustData:s}=t;return r(y,{children:[n(M,{}),n(T,{label:"Address",children:n(A,{address:e})}),!!o&&n(T,{label:"Alias",children:n(l,{children:n(I,{children:o})})}),n(T,{label:"Status",children:n(l,{color:"default",children:"No trust rating yet"})}),n(l,{color:"default",children:"Known address, awaiting community votes"}),n(F,{alternateTrustData:s,isContract:a})]})},[f.AtomWithTrustTriple]:t=>{var e,i,o,a;const{address:s,triple:c,alias:d,isContract:u,alternateTrustData:h,trustedCircle:m}=t,{counter_term:{vaults:[g]},term:{vaults:[_]},positions:f,counter_positions:b,positions_aggregate:v,counter_positions_aggregate:S}=c,k=(null===(e=_)||void 0===e?void 0:e.market_cap)||"0",$=w(k,18),j=(null===(i=g)||void 0===i?void 0:i.market_cap)||"0",P=w(j,18),{badge:W,color:N}=((t,e)=>{const n=t+e;if(0===n)return{badge:"No Stakes",color:"muted"};const r=t/n*100;return r>=70?{badge:"Trusted",color:"success"}:r>=30?{badge:"Mixed",color:"warning"}:{badge:"Untrusted",color:"warning"}})($,P),O=(t=>{const{forDistribution:e}=t,n=["success","warning","muted","default"].includes(e.snapColor)?e.snapColor:"default";return{label:e.shortLabel,color:n}})(U($,P,E(f),E(b),null===(o=v)||void 0===o?void 0:o.aggregate,null===(a=S)||void 0===a?void 0:a.aggregate));return r(y,{children:[n(M,{}),n(T,{label:"Address",children:n(A,{address:s})}),!!d&&n(T,{label:"Alias",children:n(l,{children:n(I,{children:d})})}),n(T,{label:"Trust",children:n(l,{color:N,children:n(I,{children:W})})}),n(T,{label:"Distribution",children:n(l,{color:O.color,children:n(I,{children:O.label})})}),n(T,{label:`FOR (${f.length})`,children:n(C,{value:`${$.toFixed(2)} ${p.currencySymbol}`,extra:""})}),n(T,{label:`AGAINST (${b.length})`,children:n(C,{value:`${P.toFixed(2)} ${p.currencySymbol}`,extra:""})}),n(F,{alternateTrustData:h,isContract:u}),m?n(L,{forContacts:m.forContacts,againstContacts:m.againstContacts}):null]})}},H={1155:"https://explorer.hivemindhq.io",13579:"https://testnet.explorer.hivemindhq.io"}[p.chainId],V={name:"Hive Mind Explorer",noAtom:t=>{const{address:e,chainId:n,isContract:r}=t,i=r?v(e,n):e,o=new URL("/snap/action",H);return o.searchParams.set("intent","complete_trust_triple"),o.searchParams.set("address",i),o.searchParams.set("chain_id",n),{url:o.toString()}},atomWithoutTrustTriple:t=>{const{account:e}=t;if(!e)throw new Error("atomWithoutTrustTriple: account not found");const{term_id:n}=e,r=new URL("/snap/action",H);return r.searchParams.set("intent","create_trust_triple"),r.searchParams.set("atom_id",n),{url:r.toString()}},atomWithTrustTriple:t=>{const{triple:e}=t;if(!e)throw new Error("atomWithTrustTriple: triple not found");const{term_id:n}=e,r=new URL("/snap/action",H);return r.searchParams.set("intent","stake_trust_triple"),r.searchParams.set("triple_id",n),{url:r.toString()}},viewAtom:t=>{const{account:e}=t;if(!e)throw new Error("viewAtom: account not found");const{term_id:n}=e;return{url:new URL(`/atoms/${n}`,H).toString()}},createAlias:t=>{const{account:e}=t;if(!e)throw new Error("createAlias: account not found");const{term_id:n}=e,r=new URL("/snap/action",H);return r.searchParams.set("intent","create_alias"),r.searchParams.set("subject_id",n),{url:r.toString()}},originAtomWithoutTrustTriple:t=>{const{origin:e}=t;if(!e)throw new Error("originAtomWithoutTrustTriple: origin not found");const{term_id:n}=e,r=new URL("/snap/action",H);return r.searchParams.set("intent","create_trust_triple"),r.searchParams.set("atom_id",n),{url:r.toString()}},originAtomWithTrustTriple:t=>{const{triple:e}=t;if(!e)throw new Error("originAtomWithTrustTriple: triple not found");const{term_id:n}=e,r=new URL("/snap/action",H);return r.searchParams.set("intent","stake_trust_triple"),r.searchParams.set("triple_id",n),{url:r.toString()}},viewOriginAtom:t=>{const{origin:e}=t;if(!e)throw new Error("viewOriginAtom: origin not found");const{term_id:n}=e;return{url:new URL(`/atoms/${n}`,H).toString()}}},B=V,G=({href:t,label:e})=>n(a,{children:n(d,{href:t,children:e})}),J=t=>{if(t.accountType!==f.NoAtom)return null;const{url:e}=B.noAtom(t);return n(G,{href:e,label:"Create trust claim"})},z=t=>{if(t.accountType===f.NoAtom)return null;if(t.accountType===f.AtomWithoutTrustTriple){const{url:e}=B.atomWithoutTrustTriple(t);return n(G,{href:e,label:"Is this address trustworthy? Vote"})}if(t.accountType===f.AtomWithTrustTriple){const{triple:e,userAddress:r}=t;if(!!r&&(e.positions.some((t=>{var e;return(null===(e=t.account_id)||void 0===e?void 0:e.toLowerCase())===r.toLowerCase()}))||e.counter_positions.some((t=>{var e;return(null===(e=t.account_id)||void 0===e?void 0:e.toLowerCase())===r.toLowerCase()}))))return null;const{url:i}=B.atomWithTrustTriple(t);return n(G,{href:i,label:"Is this address trustworthy? Vote"})}return null},K=t=>{if(t.accountType===f.NoAtom)return null;if(t.alias)return null;const{url:e}=B.createAlias(t);return n(G,{href:e,label:"Add alias"})},Q=t=>{if(t.accountType===f.NoAtom)return null;const{url:e}=B.viewAtom(t);return n(G,{href:e,label:"View more about this address"})},X=()=>n(s,{size:"sm",children:"dApp Origin"}),Y=t=>t.map((t=>({shares:parseFloat(t.shares)||0}))),Z={[b.NoOrigin]:t=>null,[b.NoAtom]:t=>{const{hostname:e}=t;return r(y,{children:[n(X,{}),n(T,{label:"From",children:n(l,{children:n(I,{children:e||"Unknown"})})}),n(T,{label:"Status",variant:"warning",children:n(l,{color:"warning",children:n(I,{children:"Unknown dApp"})})}),n(l,{color:"default",children:"No community data. Proceed with caution."})]})},[b.AtomWithoutTrustTriple]:t=>{var e;const{hostname:i,origin:o}=t;return r(y,{children:[n(X,{}),n(T,{label:"From",children:n(l,{children:n(I,{children:i||(null===(e=o)||void 0===e?void 0:e.label)||"Unknown"})})}),n(T,{label:"Status",children:n(l,{color:"default",children:"No trust rating yet"})}),n(l,{color:"default",children:"Known dApp, awaiting community votes"})]})},[b.AtomWithTrustTriple]:t=>{var e,i,o,a,s,c,d,u,h;const{hostname:m,origin:g,triple:_,trustedCircle:f}=t,b=null===(i=_.term)||void 0===i||null===(e=i.vaults)||void 0===e?void 0:e[0],v=null===(a=_.counter_term)||void 0===a||null===(o=a.vaults)||void 0===o?void 0:o[0],A=(null===(s=b)||void 0===s?void 0:s.market_cap)||"0",S=w(A,18),k=(null===(c=v)||void 0===c?void 0:c.market_cap)||"0",$=w(k,18),j=(null===(d=_.positions)||void 0===d?void 0:d.length)||0,P=(null===(u=_.counter_positions)||void 0===u?void 0:u.length)||0,{badge:W,color:N}=((t,e)=>{const n=t+e;if(0===n)return{badge:"No Stakes",color:"muted"};const r=t/n*100;return r>=70?{badge:"Trusted",color:"success"}:r>=30?{badge:"Mixed",color:"warning"}:{badge:"Untrusted",color:"warning"}})(S,$),O=(t=>{const{forDistribution:e}=t,n=["success","warning","muted","default"].includes(e.snapColor)?e.snapColor:"default";return{label:e.shortLabel,color:n}})(U(S,$,Y(_.positions||[]),Y(_.counter_positions||[])));return r(y,{children:[n(X,{}),n(T,{label:"From",children:n(l,{children:n(I,{children:m||(null===(h=g)||void 0===h?void 0:h.label)||"Unknown"})})}),n(T,{label:"Trust",children:n(l,{color:N,children:n(I,{children:W})})}),n(T,{label:"Distribution",children:n(l,{color:O.color,children:n(I,{children:O.label})})}),n(T,{label:`FOR (${j})`,children:n(C,{value:`${S.toFixed(2)} ${p.currencySymbol}`,extra:""})}),n(T,{label:`AGAINST (${P})`,children:n(C,{value:`${$.toFixed(2)} ${p.currencySymbol}`,extra:""})}),f?n(L,{forContacts:f.forContacts,againstContacts:f.againstContacts}):null]})}},tt=t=>{if(t.originType===b.NoOrigin||t.originType===b.NoAtom)return null;if(t.originType===b.AtomWithoutTrustTriple){const{url:e}=B.originAtomWithoutTrustTriple(t);return n(G,{href:e,label:"Is this dApp trustworthy? Vote"})}if(t.originType===b.AtomWithTrustTriple){const{url:e}=B.originAtomWithTrustTriple(t);return n(G,{href:e,label:"Is this dApp trustworthy? Vote"})}return null},et=t=>{if(t.originType===b.NoOrigin||t.originType===b.NoAtom)return null;const{url:e}=B.viewOriginAtom(t);return n(G,{href:e,label:"View more about this dApp"})},nt=({accountProps:t,originProps:e})=>{const i=e.originType===b.AtomWithoutTrustTriple||e.originType===b.AtomWithTrustTriple;return r(a,{children:[n(c,{}),r(a,{children:[n(J,{...t}),n(z,{...t}),n(K,{...t}),n(Q,{...t}),i&&n(tt,{...e}),i&&n(et,{...e})]})]})},rt=t=>{var e,n,r,i,o,a;if(!t)return 0n;return BigInt((null===(r=t.term)||void 0===r||null===(n=r.vaults)||void 0===n||null===(e=n[0])||void 0===e?void 0:e.market_cap)??"0")+BigInt((null===(a=t.counter_term)||void 0===a||null===(o=a.vaults)||void 0===o||null===(i=o[0])||void 0===i?void 0:i.market_cap)??"0")},it=async(t,e)=>{const{to:n,data:r}=t,i=v(n,e),o=await(async(t,e)=>{if("0x"!==e)return{type:"contract",certainty:"definite"};try{const e=await fetch(p.rpcUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",method:"eth_getCode",params:[t,"latest"],id:1})});if(!e.ok)return{type:"unknown",certainty:"uncertain",reason:"eth_getCode_failed"};const n=(await e.json()).result;return"0x"===n||null===n?{type:"eoa",certainty:"definite"}:{type:"contract",certainty:"definite"}}catch(t){return{type:"unknown",certainty:"uncertain",reason:"eth_getCode_failed"}}})(n,r),a="contract"===o.type||"uncertain"===o.certainty;try{var s,l,c;const[t]=await Promise.all([h("\nquery AddressAtoms($plainAddress: String!, $caipAddress: String!) {\n # Atoms matching plain address format (for EOAs)\n plainAtoms: atoms(where: {\n _or: [\n { label: { _ilike: $plainAddress } },\n { data: { _ilike: $plainAddress } }\n ]\n }, limit: 1) {\n term_id\n type\n label\n image\n data\n emoji\n creator_id\n }\n\n # Atoms matching CAIP format (for smart contracts)\n caipAtoms: atoms(where: {\n _or: [\n { label: { _ilike: $caipAddress } },\n { data: { _ilike: $caipAddress } }\n ]\n }, limit: 1) {\n term_id\n type\n label\n image\n data\n emoji\n creator_id\n }\n}\n",{plainAddress:n,caipAddress:i})]),{plainAtoms:e,caipAtoms:r}=t.data,g=null===(s=e)||void 0===s?void 0:s[0],_=null===(l=r)||void 0===l?void 0:l[0];if(!g&&!_)return{account:null,triple:null,isContract:a,alias:null,classification:o,alternateTrustData:{hasAlternateTrustData:!1}};const{hasTagAtomId:f,trustworthyAtomId:b,hasAliasAtomId:v}=p,w=[],y=[];g&&(w.push(h(m,{subjectId:g.term_id,predicateId:f,objectId:b})),y.push("plain")),_&&(w.push(h(m,{subjectId:_.term_id,predicateId:f,objectId:b})),y.push("caip"));const T=await Promise.all(w),A={};y.forEach(((t,e)=>{A[t]=T[e].data.triples[0]||null}));const I=((t,e,n,r,i)=>n||e?n?e?"definite"===t.certainty?"contract"===t.type?{primary:n,primaryTriple:i,alternate:e,alternateTriple:r,usedCaip:!0}:{primary:e,primaryTriple:r,alternate:n,alternateTriple:i,usedCaip:!1}:rt(i)>=rt(r)?{primary:n,primaryTriple:i,alternate:e,alternateTriple:r,usedCaip:!0}:{primary:e,primaryTriple:r,alternate:n,alternateTriple:i,usedCaip:!1}:{primary:n,primaryTriple:i,alternate:null,alternateTriple:null,usedCaip:!0}:{primary:e,primaryTriple:r,alternate:null,alternateTriple:null,usedCaip:!1}:{primary:null,primaryTriple:null,alternate:null,alternateTriple:null,usedCaip:!1})(o,g||null,_||null,A.plain||null,A.caip||null),C=rt(I.alternateTriple),S={hasAlternateTrustData:C>0n,alternateAtomId:null===(c=I.alternate)||void 0===c?void 0:c.term_id,alternateMarketCap:C.toString(),alternateIsCaip:!I.usedCaip};let k=null;if(I.primary){var d,u;const t=await h('\n query GetTriplesWithHighestStake($subjectId: String!, $predicateId: String!) {\n triples(\n where: {\n subject_id: { _eq: $subjectId },\n predicate_id: { _eq: $predicateId }\n },\n order_by: { triple_term: { total_market_cap: desc } }\n ) {\n term_id\n subject_id\n predicate_id\n object_id\n creator_id\n counter_term_id\n\n # Triple-specific aggregated market data (stake information)\n triple_term {\n term_id\n counter_term_id\n total_market_cap\n total_position_count\n }\n\n # Individual vault data\n term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n curve_id\n }\n }\n\n counter_term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n curve_id\n }\n }\n\n # Object information for context\n object {\n label\n image\n data\n }\n }\n\n chainlink_prices(limit: 1, order_by: { id: desc }) {\n usd\n }\n }\n',{subjectId:I.primary.term_id,predicateId:v});k=(null===(u=t.data.triples[0])||void 0===u||null===(d=u.object)||void 0===d?void 0:d.label)||null}return{account:I.primary,triple:I.primaryTriple,isContract:a,alias:k,classification:o,alternateTrustData:S}}catch(t){throw t}},ot=async t=>{const e=(t=>{if(t)try{return new URL(t).hostname}catch{var e;return null===(e=t.match(/^(?:https?:\/\/)?([^\/]+)/))||void 0===e?void 0:e[1]}})(t);if(!t||!e)return{origin:null,triple:null,hostname:void 0};try{var n;const i=null===(n=(await h(g,{originUrl:t})).data.atoms)||void 0===n?void 0:n[0];if(!i){var r;const t=null===(r=(await h(g,{originUrl:e})).data.atoms)||void 0===r?void 0:r[0];return t?await at(t,e):{origin:null,triple:null,hostname:e}}return await at(i,e)}catch{return{origin:null,triple:null,hostname:e}}},at=async(t,e)=>{const{hasTagAtomId:n,trustworthyAtomId:r}=p;try{var i;const o=await h('\nquery OriginTrustTriple($subjectId: String!, $predicateId: String!, $objectId: String!) {\n triples(where: {\n subject_id: { _eq: $subjectId },\n predicate_id: { _eq: $predicateId },\n object_id: { _eq: $objectId }\n }) {\n term_id\n\n term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n }\n }\n\n counter_term {\n vaults(where: { curve_id: { _eq: "1" } }) {\n term_id\n market_cap\n position_count\n }\n }\n\n positions(order_by: { shares: desc }, limit: 30) {\n id\n shares\n account_id\n }\n\n counter_positions(order_by: { shares: desc }, limit: 30) {\n id\n shares\n account_id\n }\n }\n}\n',{subjectId:t.term_id,predicateId:n,objectId:r});return{origin:t,triple:(null===(i=o.data.triples)||void 0===i?void 0:i[0])||null,hostname:e}}catch{return{origin:t,triple:null,hostname:e}}},st=36e5;async function lt(t){try{const n=await snap.request({method:"snap_manageState",params:{operation:"get"}});if(!n)return null;const r=n[t.toLowerCase()];return r?(e=r.timestamp,Date.now()-e<st?r.contacts:null):null}catch{return null}var e}async function ct(t){const e=await lt(t);if(null!==e)return e;const n=await async function(t){var e,n;const{hasTagAtomId:r,trustworthyAtomId:i}=p,o=(null===(n=await h(_,{userAddress:t,predicateId:r,objectId:i}))||void 0===n||null===(e=n.data)||void 0===e?void 0:e.positions)||[],a=new Map;for(const t of o){const{subject_id:e,subject:n}=t.triple;var s;a.has(e)||a.set(e,{accountId:e,label:(null===(s=n)||void 0===s?void 0:s.label)||e})}return Array.from(a.values())}(t);return await async function(t,e){try{const n=await snap.request({method:"snap_manageState",params:{operation:"get"}}),r=t.toLowerCase(),i={contacts:e,timestamp:Date.now()},o={...n||{},[r]:i};await snap.request({method:"snap_manageState",params:{operation:"update",newState:o}})}catch{}}(t,n),n}function dt(t,e,n){const r=new Set(t.map((t=>t.accountId.toLowerCase()))),i=new Map(t.map((t=>[t.accountId.toLowerCase(),t.label]))),o=[];for(const t of e){var a;const e=null===(a=t.account_id)||void 0===a?void 0:a.toLowerCase();var s;if(e&&r.has(e))o.push({accountId:t.account_id,label:i.get(e)||(null===(s=t.account)||void 0===s?void 0:s.label)||ut(t.account_id)})}const l=[];for(const t of n){var c;const e=null===(c=t.account_id)||void 0===c?void 0:c.toLowerCase();var d;if(e&&r.has(e))l.push({accountId:t.account_id,label:i.get(e)||(null===(d=t.account)||void 0===d?void 0:d.label)||ut(t.account_id)})}return{forContacts:o,againstContacts:l}}function ut(t){return!t||t.length<12?t||"Unknown":`${t.slice(0,6)}...${t.slice(-4)}`}const pt=async({transaction:t,chainId:e,transactionOrigin:i})=>{let o;try{var s;o=null===(s=await ethereum.request({method:"eth_accounts"}))||void 0===s?void 0:s[0]}catch(t){}const[l,c,d]=await Promise.all([it(t,e),ot(i),o?ct(o):Promise.resolve([])]),u=(t=>{const{account:e,triple:n}=t;return e?null===n?f.AtomWithoutTrustTriple:f.AtomWithTrustTriple:f.NoAtom})(l),p=((t,e)=>{if(!e)return b.NoOrigin;const{origin:n,triple:r}=t;return n?r?b.AtomWithTrustTriple:b.AtomWithoutTrustTriple:b.NoAtom})(c,i);let h,m;if(d.length>0&&l.triple){h=dt(d,l.triple.positions||[],l.triple.counter_positions||[]),0===h.forContacts.length&&0===h.againstContacts.length&&(h=void 0)}if(d.length>0&&c.triple){m=dt(d,c.triple.positions||[],c.triple.counter_positions||[]),0===m.forContacts.length&&0===m.againstContacts.length&&(m=void 0)}const g={...l,accountType:u,address:t.to,userAddress:o,chainId:e,transactionOrigin:i,trustedCircle:h},_={...c,originType:p,originUrl:i,trustedCircle:m},v=(t=>{const{accountType:e}=t;return R[e](t)})(g),w=(t=>{const{originType:e}=t;return Z[e](t)})(_),y=n(nt,{accountProps:g,originProps:_}),T=r(a,{children:[v,w,y]}),A=(t=>JSON.parse(JSON.stringify(t)))({account:g,origin:_});return{id:await snap.request({method:"snap_createInterface",params:{ui:T,context:A}})}},ht=async t=>{},mt=async()=>({content:r(a,{children:[n(s,{children:"Welcome to Hive Mind, powered by Intuition"}),n(l,{children:"Real-time trust and sentiment insights for every transaction."}),n(c,{}),n(l,{children:"Hive Mind shows you community trust data from the Intuition knowledge graph during transactions."}),r(a,{children:[n(d,{href:"https://hivemindhq.io",children:"Check out Hive Mind's product suite"}),n(d,{href:"https://intuition.systems",children:"Learn about Intuition"})]})]})});var gt=exports;for(var _t in e)gt[_t]=e[_t];e.__esModule&&Object.defineProperty(gt,"__esModule",{value:!0})})();
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@hivemindhq/snap",
3
+ "version": "1.1.0",
4
+ "description": "Real-time trust and sentiment insights for every transaction. Powered by Intuition",
5
+ "contributors": [
6
+ {
7
+ "name": "Kylan Hurt",
8
+ "email": "kylan@hivemindhq.io"
9
+ }
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/hivemindhq-io/snap"
14
+ },
15
+ "license": "Apache-2.0",
16
+ "main": "./dist/bundle.js",
17
+ "files": [
18
+ "dist/",
19
+ "src/images/logo.svg",
20
+ "snap.manifest.json"
21
+ ],
22
+ "scripts": {
23
+ "allow-scripts": "yarn workspace root allow-scripts",
24
+ "build": "mm-snap build",
25
+ "build:clean": "yarn clean && yarn build",
26
+ "clean": "rimraf dist",
27
+ "lint": "yarn lint:eslint && yarn lint:misc --check",
28
+ "lint:eslint": "eslint . --cache --ext js,ts",
29
+ "lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write",
30
+ "lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' --ignore-path .gitignore",
31
+ "prepublishOnly": "mm-snap manifest",
32
+ "serve": "mm-snap serve",
33
+ "start": "CHAIN=testnet mm-snap watch",
34
+ "start:mainnet": "CHAIN=mainnet mm-snap watch",
35
+ "start:testnet": "CHAIN=testnet mm-snap watch",
36
+ "test": "jest",
37
+ "test:watch": "jest --watch",
38
+ "test:integration": "jest --testPathPattern=onTransaction.test",
39
+ "test:components": "jest --testPathPattern=components",
40
+ "test:coverage": "jest --coverage"
41
+ },
42
+ "dependencies": {
43
+ "@metamask/snaps-sdk": "^6.10.0"
44
+ },
45
+ "devDependencies": {
46
+ "@jest/globals": "^29.5.0",
47
+ "@metamask/auto-changelog": "^3.4.4",
48
+ "@metamask/eslint-config": "^12.2.0",
49
+ "@metamask/eslint-config-jest": "^12.1.0",
50
+ "@metamask/eslint-config-nodejs": "^12.1.0",
51
+ "@metamask/eslint-config-typescript": "^12.1.0",
52
+ "@metamask/snaps-cli": "^6.2.1",
53
+ "@metamask/snaps-jest": "^8.2.0",
54
+ "@typescript-eslint/eslint-plugin": "^5.42.1",
55
+ "@typescript-eslint/parser": "^5.42.1",
56
+ "eslint": "^8.45.0",
57
+ "eslint-config-prettier": "^8.5.0",
58
+ "eslint-plugin-import": "~2.26.0",
59
+ "eslint-plugin-jest": "^27.1.5",
60
+ "eslint-plugin-jsdoc": "^41.1.2",
61
+ "eslint-plugin-n": "^15.7.0",
62
+ "eslint-plugin-prettier": "^4.2.1",
63
+ "eslint-plugin-promise": "^6.1.1",
64
+ "jest": "^29.5.0",
65
+ "prettier": "^2.7.1",
66
+ "prettier-plugin-packagejson": "^2.2.11",
67
+ "rimraf": "^3.0.2",
68
+ "ts-jest": "^29.1.0",
69
+ "typescript": "^4.7.4"
70
+ },
71
+ "packageManager": "yarn@3.2.1",
72
+ "engines": {
73
+ "node": ">=18.6.0"
74
+ },
75
+ "publishConfig": {
76
+ "access": "public",
77
+ "registry": "https://registry.npmjs.org/"
78
+ }
79
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "version": "1.1.0",
3
+ "description": "Community trust signals for every transaction, powered by Intuition.",
4
+ "proposedName": "Hive Mind",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/hivemindhq-io/snap"
8
+ },
9
+ "source": {
10
+ "shasum": "vLpQcSb97+LD46+U1u7AofVyrTtWWqWW7z0Uz+07LCQ=",
11
+ "location": {
12
+ "npm": {
13
+ "filePath": "dist/bundle.js",
14
+ "iconPath": "src/images/logo.svg",
15
+ "packageName": "@hivemindhq/snap",
16
+ "registry": "https://registry.npmjs.org/"
17
+ }
18
+ }
19
+ },
20
+ "initialPermissions": {
21
+ "endowment:transaction-insight": {
22
+ "allowTransactionOrigin": true
23
+ },
24
+ "endowment:page-home": {},
25
+ "endowment:network-access": {},
26
+ "endowment:rpc": {
27
+ "dapps": true,
28
+ "snaps": false
29
+ },
30
+ "snap_manageState": {}
31
+ },
32
+ "manifestVersion": "0.1"
33
+ }
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" width="29.62148" height="34.33696" viewBox="-4.23164 -4.90528 29.62148 34.33696">
3
+ <g id="Layer_4" data-name="Layer 4">
4
+ <path d="M21.1582,6.1641L10.9077.1514l-.4019-.1514L.0005,6.165l-.0005,12.2197,10.4644,6.1416.231-.0015,10.5132-6.1426-.0503-12.2183ZM19.1802,12.2734l-3.4512,2.1265-3.6367-2.1265,3.6401-2.1582,3.4478,2.1582ZM14.9927,15.7437v3.6025l-3.6646-2.1187-.0117-3.6509,3.6763,2.167ZM9.8115,13.6294v3.6323l-3.645,2.1167v-3.6177l3.645-2.1313ZM6.1665,8.8047v-3.6323l3.645,2.1313v3.6177l-3.645-2.1167ZM14.1499,20.667l-3.5723,2.1304-3.5991-2.0859,3.6021-2.1431,3.5693,2.0986ZM6.979,3.895l3.606-2.1689,3.5654,2.124-3.5728,2.0991-3.5986-2.0542ZM11.3477,10.9214v-3.666l3.645-2.0874v3.6367l-3.645,2.1167ZM9.0654,12.2886l-3.6592,2.1182-3.4312-2.1484,3.4214-2.1421,3.6689,2.1724ZM1.4863,10.7681v-3.7148l3.1772-1.8481v3.5557l-3.1772,2.0073ZM4.6626,19.312l-3.1763-1.8335v-3.7012l3.1699,1.9697.0063,3.5649ZM19.6724,13.7812v3.6973l-3.1768,1.834v-3.5239l3.1768-2.0073ZM19.6724,7.1021v3.666l-3.1768-2.0073v-3.5503l3.1768,1.8916Z" fill="#e59200"/>
5
+ </g>
6
+ </svg>
7
+