diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 28f7e23ef..25a20390b 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -14,7 +14,7 @@ jobs:
- name: Set up node
uses: actions/setup-node@v3
with:
- node-version: 16
+ node-version: 20
- name: Install dependencies
run: yarn --frozen-lockfile
diff --git a/CODEOWNERS b/CODEOWNERS
index ed399c4b1..d36f3a489 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,2 +1,2 @@
-* @uniswap/developer-experience
+* @t1protocol/engineering-t1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 532fd077c..f66009a90 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,8 +17,8 @@ Thanks for giving a little extra love to our docs site! Below are some basic gui
Set up your fork with the following terminal commands, or an alteration of them to suit your environment:
```
-cd uniswap-docs
-git remote add upstream https://github.com/Uniswap/uniswap-docs.git
+cd docs
+git remote add upstream https://github.com/t1protocol/docs.git
git fetch upstream
git pull --rebase upstream main
git checkout -b "my-contribution"
diff --git a/README.md b/README.md
index 62749307c..d515b279f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# t1 Documentation
-This web application contains all documentation for t1. It was forked from the [Uniswap Docs](https://github.com/Uniswap/docs), which is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.
+This web application contains all documentation for t1. It was forked from the [Uniswap Docs](https://github.com/Uniswap/docs), and upgraded to use [Docusaurus 3](https://v3.docusaurus.io/), a modern static website generator.
# Project Layout
@@ -8,7 +8,7 @@ This web application contains all documentation for t1. It was forked from the [
- Concepts - General t1 information or concepts useful for using t1
- API - xChainRead API documentation
-### TODO:
+### TODOs:
- Add essential t1 contract docs, including technical method descriptions via `forge doc --serve`
- ~~Add more research entries in [Research](./docs/concepts/research.md)~~
- ~~Add all relevant glossary words and definitions in [Glossary](./docs/concepts/glossary.md)~~
diff --git a/blog/gas-optimization.md b/blog/gas-optimization.md
deleted file mode 100644
index 7b53e4b85..000000000
--- a/blog/gas-optimization.md
+++ /dev/null
@@ -1,145 +0,0 @@
----
-title: An Introduction to Gas Optimization
-authors:
- - name: Moody Salem
- url: https://github.com/moodysalem
- - name: Noah Zinsmeister
- url: https://github.com/NoahZinsmeister
- - name: Connor Martin
- url: https://github.com/Yorkemartin
-hide_table_of_contents: true
-image: /use.png
-slug: intro-to-gas-optimization
----
-
-
-
-
.default})
-
-
-
-## Gas Optimization
-
-:::tip Get Started
-
-To help devs get their contracts into tip-top shape before deployment, we reconfigured our most used gas snapshot tool as a simple npm package: [The t1 Gas Snapshot Test](https://www.npmjs.com/package/@uniswap/snapshot-gas-cost)
-
-:::
-
-At t1 Labs, many of the smart contracts we’ve written have gone on to become the most frequently called smart contracts on the Ethereum blockchain.
-
-Tens of thousands of ETH are spent every month by users interacting with the t1 Protocol contracts. Multiples of that still are spent on the many protocol forks deployed across Ethereum and other environments.
-
-Due to the protocol’s significant use, and reuse in the form of forks, a change in the gas optimization of a piece of protocol code that saves 1% in gas translates to millions of dollars saved by the DeFi community over the lifetime of the contracts.
-
-As a result, it is difficult to overstate the significance of these optimizations. Considerable effort goes into this work, [which](https://github.com/Uniswap/v3-core/commit/705be1eefc56a3620afe96a725c3a68951e8d4a9) [frequently](https://github.com/Uniswap/v3-core/commit/7689aa8e2adecbcf94198f79cb4f230d0419d009) [continues](https://github.com/Uniswap/v3-core/commit/225399176cf1fa562aa74345b7885e1244d95417) [right](https://github.com/Uniswap/v3-core/commit/ebcdb5225a3cf4188f4752f59fe52e6b0071909d) [up](https://github.com/Uniswap/v3-core/commit/49ce1c3a600e4c0e22e272b2144a3082663cb1ea) [to](https://github.com/Uniswap/v3-core/commit/5b485192df944273882397d804d13c2e4ebb25da) [deployment](https://github.com/Uniswap/v3-core/commit/723f90cbea93fc09ff06303bd4db03ce3b0847a1).
-
-While much of the discourse around gas optimization takes the form of specific implementation techniques, which can be quite fun to read and experiment with, we think a more helpful thing to write about is the development of a process in pursuit of gas optimization, rather than a collection of specific optimizations which may become dated as Ethereum progresses.
-
-## Measurement
-
-If there’s one lesson to learn from this post, it’s that all optimization starts with measurement. The single biggest tool in our arsenal of gas optimization is the [snapshot test](https://jestjs.io/docs/snapshot-testing) borrowed from Jest snapshot testing. For V3, we used a snippet in combination with the [mocha-chai-jest-snapshot](https://www.npmjs.com/package/mocha-chai-jest-snapshot) plugin to record gas costs in [hundreds of situations.](https://github.com/Uniswap/v3-core/blob/ed88be38ab2032d82bf10ac6f8d03aa631889d48/test/__snapshots__/UniswapV3Pool.gas.spec.ts.snap)
-
-The code below, which we use in our development process, has been implemented in an NPM package for easy use in your project: [The t1 Gas Snapshot Test.](https://www.npmjs.com/package/@uniswap/snapshot-gas-cost)
-
-
- The Gas Snapshot Test Code
-
-```typescript
-import {
- TransactionReceipt,
- TransactionResponse,
-} from "@ethersproject/abstract-provider";
-import { expect } from "./expect";
-import { Contract, BigNumber, ContractTransaction } from "ethers";
-
-export default async function snapshotGasCost(
- x:
- | TransactionResponse
- | Promise
- | ContractTransaction
- | Promise
- | TransactionReceipt
- | Promise
- | BigNumber
- | Contract
- | Promise
-): Promise {
- const resolved = await x;
- if ("deployTransaction" in resolved) {
- const receipt = await resolved.deployTransaction.wait();
- expect(receipt.gasUsed.toNumber()).toMatchSnapshot();
- } else if ("wait" in resolved) {
- const waited = await resolved.wait();
- expect(waited.gasUsed.toNumber()).toMatchSnapshot();
- } else if (BigNumber.isBigNumber(resolved)) {
- expect(resolved.toNumber()).toMatchSnapshot();
- }
-}
-```
-
-
-
-This test allows us to see [every change](https://github.com/Uniswap/v3-core/pull/455/files#diff-9dd2638a0155da6d7dcf09f3866954da30e66e6a3569a6aa7794604e51ad030c) to the smart contracts - and surfaces the exact savings that the user would experience in a variety of situations. It’s essential to commit these snapshots to the repository so that future changes can be compared against the current gas costs of your smart contracts.
-
-Now that the basics of the concepts are covered, how do you decide where to spend your time optimizing?
-
-First, it’s important to understand what changes are relevant and what changes are not. A gas difference of 50 gas on a call that costs 100k gas is typically below the bar of relevance. However, several 50 gas optimizations, called multiple times per transaction, can add up to a 1% savings for a user action. The important thing here is the context: if you are saving 50 gas in a function that typically costs 1000 gas, you are saving 5% in that function. You should separate your code into function boundaries and measure at those boundaries. We do this with the many libraries in the t1 V3 codebase.
-
-Context is also relevant for where to spend your time in a codebase. For example, we know the majority of users will interact with t1 via calls to swap. So we should focus our energy primarily on the swap function.
-
-Sometimes optimization is less clear cut. In many cases, the code is strictly better after a change, whereas in others, certain scenarios become more expensive while making others less, e.g., mint is cheaper, but swap is more expensive. In order to understand whether to commit to a change, it’s important to understand how users will interact with a contract.
-
-An extreme example of this is the lack of proxies in the t1 V3 codebase. Using a proxy could save millions of gas every time you create a V3 pool. However, users will interact with a particular pool on average over a thousand times over the lifetime of the contracts. Assuming $O(1M)$ [^1] gas and $O(1k)$ calls per contract, the proxy must have an overhead of less than $O(1M) / O(1K) = O(1K)$ gas. The overhead of a proxy, unfortunately, is more than that. A proxy contract means that an implementation address *and* a proxy address must be called to execute a swap. Calling a new address as part of a swap incurs an additional minimum $O(1K)$ gas. Interestingly, the Solidity optimizer ‘runs’ parameter does something like this: it optimizes your code such that the gas cost is minimized if you deployed and ran your contract `runs` times.
-
-## In Practice: Storage Packing
-
-When optimizing smart contracts, it’s important to identify areas of the code that are likely to yield the most significant returns (in terms of gas saved). To gain intuition about this, it’s important to take a step back and understand the fundamental constraints at play.
-
-The most expensive operations on Ethereum (and most other L1 blockchains) typically involve storing and fetching data that must persist across transactions and blocks. The totality of this data is referred to as the blockchain’s *state*. If we zoom in to the subset of that state associated with a particular smart contract, we refer to it as the contract’s *storage*.
-
-:::note Disk vs Memory
-A quick aside: storing and retrieving state is so expensive because it must reside on [disk](https://en.wikipedia.org/wiki/Disk_storage), as it’s too large to fit in [memory](https://en.wikipedia.org/wiki/Random-access_memory). For more information on these types of tradeoffs in blockchain settings, see [The Limits to Blockchain Scalability](https://vitalik.eth.limo/general/2021/05/23/scaling.html).
-:::
-
-So, returning to optimization, it’s clear that one of our primary goals should be to minimize our contract’s use of storage, as this can lead to massive savings for end-users.
-
-Now that we know what to focus on, it’s time to operationalize this insight. To do so, we’ll need to peek into the internals of the Ethereum Virtual Machine, or EVM for short. The EVM is the engine that processes transactions on Ethereum (similar to how your browser is the engine that renders websites you visit). It defines the rules governing what contracts can do, including how they use storage! One of these rules states that when contracts are writing to or reading from storage, they must do so in increments of 256 bits. Each 256-bit chunk is referred to as a [word](
).
-
-Of course, it’s possible to store more than 256 bits of data per contract, but the given data will then span multiple words, each of which costs gas to update. To illustrate how one can accommodate these limitations, consider the case when we need to track multiple pieces of data, which are considerably smaller than 256 bits. For example, a boolean is a simple yes/no flag that can be stored in a single bit, and we may want to track several mutually independent booleans in our contract. If we can manage to pack the representations of these variables within the bounds of a single word, we can read and write to them in bulk - ensuring that we are only charged gas for using a single word of storage. This is probably the single-most important gas golfing technique, which we use widely at t1.
-
-In V3, seven (!) different variables are packed into a single word (also referred to as a slot):
-
-```solidity
-struct Slot0 {
- // the current price
- uint160 sqrtPriceX96;
- // the current tick
- int24 tick;
- // the most-recently updated index of the observations array
- uint16 observationIndex;
- // the current maximum number of observations that are being stored
- uint16 observationCardinality;
- // the next maximum number of observations to store, triggered in observations.write
- uint16 observationCardinalityNext;
- // the current protocol fee as a percentage of the swap fee taken on withdrawal
- // represented as an integer denominator (1/x)%
- uint8 feeProtocol;
- // whether the pool is locked
- bool unlocked;
-}
-
-Slot0 public slot0;
-```
-
-To verify that this is the case, we can simply add up the number of bits used by each variable. e.g., `uint160 sqrtPriceX96` uses 160 bits, `int24 tick` uses 24 bits, etc.
-
-> $160 + 24 + 16 + 16 + 16 + 8 + 1 = 241$
-
-This tells us we actually have 15 bits to spare! This contract stores many more variables, some of which take up entire slots on their own, but by carefully selecting the variables with compact representations and declaring them side-by-side, we’ve achieved our aim of gas optimization. By this point, it should be apparent that gas optimization is not just a matter of clever tricks and novel expressions of data; but also a matter of foundational decision-making made while designing the architecture of your smart contracts.
-
-For a deeper look into slot packing in Solidity, a good place to start is the [Solidity Documentation](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html).
-
-[^1] [Big O Notation](https://en.wikipedia.org/wiki/Big_O_notation)
-
-
diff --git a/blog/use.png b/blog/use.png
deleted file mode 100644
index 68adaef47..000000000
Binary files a/blog/use.png and /dev/null differ
diff --git a/config.json b/config.json
index d047e9463..04411d784 100644
--- a/config.json
+++ b/config.json
@@ -1,7 +1,7 @@
{
"index_name": "v3-docs",
- "start_urls": ["https://docs.uniswap.org/"],
- "sitemap_urls": ["https://docs.uniswap.org/sitemap.xml"],
+ "start_urls": ["https://docs.t1protocol.com/"],
+ "sitemap_urls": ["https://docs.t1protocol.com/sitemap.xml"],
"sitemap_alternate_links": true,
"stop_urls": [],
"selectors": {
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 8e010b101..ba88fcda3 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -1,14 +1,16 @@
-const math = require('remark-math')
-const katex = require('rehype-katex')
+const remarkMath = require('remark-math')
+const rehypeKatex = require('rehype-katex')
+const math = remarkMath.default || remarkMath
+const katex = rehypeKatex.default || rehypeKatex
require('dotenv').config()
module.exports = {
+ themes: ['@docusaurus/theme-mermaid'],
+ markdown: {
+ mermaid: true,
+ },
customFields: {
- // Analytics proxy URL
- // analyticsProxyUrl: process.env.REACT_APP_AMPLITUDE_PROXY_URL,
- // Determines if staging env
stagingEnv: process.env.REACT_APP_STAGING,
- // From node
nodeEnv: process.env.NODE_ENV,
},
title: 't1',
@@ -16,16 +18,25 @@ module.exports = {
url: 'https://docs.t1protocol.com',
baseUrl: '/',
onBrokenLinks: 'warn',
- onBrokenMarkdownLinks: 'ignore',
+ onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
- organizationName: 't1', // Usually your GitHub org/user name.
- projectName: 't1-docs', // Usually your repo name.
+ organizationName: 't1protocol',
+ projectName: 't1-docs',
themeConfig: {
image: 'img/t1-rollup.png',
prism: {
additionalLanguages: ['solidity'],
},
- algolia: null,
+ mermaid: {
+ theme: { light: 'neutral', dark: 'dark' },
+ },
+ // not using search for now
+ // algolia: {
+ // appId: 'PLACEHOLDER',
+ // apiKey: 'PLACEHOLDER',
+ // indexName: 't1-docs',
+ // contextualSearch: true,
+ // },
navbar: {
title: 't1 Docs',
items: [
@@ -42,7 +53,6 @@ module.exports = {
className: 'V3_active',
},
{
- // TODO(docs): Publish docs repo and make public at this URL
href: 'https://github.com/t1protocol/',
label: 'GitHub',
position: 'right',
@@ -54,11 +64,28 @@ module.exports = {
// style: "dark",
links: [
{
- title: 'Developers',
+ title: 'Documentation',
+ items: [
+ {
+ label: 'Concepts',
+ to: '/concepts/protocol/introduction',
+ },
+ {
+ label: 'Integration',
+ to: '/integration/xChainRead/overview',
+ },
+ ],
+ },
+ {
+ title: 'Resources',
items: [
{
- label: 'How it works',
- href: 'https://www.t1protocol.com/#how-it-works',
+ label: 'Website',
+ href: 'https://www.t1protocol.com',
+ },
+ {
+ label: 'GitHub',
+ href: 'https://github.com/t1protocol',
},
],
},
@@ -70,7 +97,7 @@ module.exports = {
href: 'https://discord.com/invite/nbvyXZHgke',
},
{
- label: 'X',
+ label: 'X (Twitter)',
href: 'https://x.com/t1protocol',
},
{
@@ -80,7 +107,7 @@ module.exports = {
],
},
],
- // copyright: `unlicensed`,
+ copyright: `© ${new Date().getFullYear()} t1 Protocol. Built with Docusaurus.`,
},
colorMode: {
// "light" | "dark"
@@ -103,13 +130,12 @@ module.exports = {
routeBasePath: '/',
sidebarPath: require.resolve('./sidebars.js'),
remarkPlugins: [math],
- rehypePlugins: [katex],
+ rehypePlugins: [[katex, { strict: false }]],
editUrl: 'https://github.com/t1protocol/docs/tree/main/',
includeCurrentVersion: true,
},
theme: {
- customCss: require.resolve('./src/css/custom.css'),
- customCss2: require.resolve('./src/css/colors.css'),
+ customCss: [require.resolve('./src/css/custom.css'), require.resolve('./src/css/colors.css')],
},
},
],
@@ -122,5 +148,5 @@ module.exports = {
crossorigin: 'anonymous',
},
],
- plugins: [['@saucelabs/theme-github-codeblock', {}]],
+ plugins: [],
}
diff --git a/package.json b/package.json
index e7eda9357..d10eadbc0 100644
--- a/package.json
+++ b/package.json
@@ -1,44 +1,40 @@
{
- "name": "@uniswap/docs",
- "description": "Uniswap docs",
+ "name": "@t1/docs",
+ "description": "t1 Protocol Documentation",
+ "license": "MIT",
"scripts": {
"docusaurus": "docusaurus",
- "start": "docusaurus start",
- "build": "docusaurus build",
+ "start": "NODE_OPTIONS='--openssl-legacy-provider' docusaurus start",
+ "build": "NODE_OPTIONS='--openssl-legacy-provider' docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
- "serve": "docusaurus serve",
+ "serve": "NODE_OPTIONS='--openssl-legacy-provider' docusaurus serve",
"clear": "docusaurus clear",
"lint": "yarn eslint src"
},
"dependencies": {
"@algolia/autocomplete-preset-algolia": "^1.1.0",
"@algolia/client-search": "^4.9.1",
- "@babel/core": "^7.14.6",
- "@docusaurus/core": "^2.0.0-beta.17",
- "@docusaurus/plugin-client-redirects": "2.0.0-beta.17",
- "@docusaurus/plugin-content-docs": "^2.0.0-beta.17",
- "@docusaurus/preset-classic": "^2.0.0-beta.17",
- "@docusaurus/remark-plugin-npm2yarn": "^2.0.0-beta.17",
- "@docusaurus/theme-search-algolia": "^2.0.0-beta.17",
+ "@docusaurus/core": "^3.8.1",
+ "@docusaurus/plugin-client-redirects": "^3.8.1",
+ "@docusaurus/plugin-content-docs": "^3.8.1",
+ "@docusaurus/preset-classic": "^3.8.1",
+ "@docusaurus/remark-plugin-npm2yarn": "^3.8.1",
+ "@docusaurus/theme-mermaid": "^3.8.1",
+ "@docusaurus/theme-search-algolia": "^3.8.1",
"@emotion/react": "^11.4.0",
"@emotion/styled": "^11.3.0",
- "@mdx-js/react": "^1.6.21",
- "@saucelabs/theme-github-codeblock": "https://github.com/Uniswap/docusaurus-theme-github-codeblock.git#f55fe4caed9fce974c9b82bf2164f76cc5509eef",
- "@types/react": "^17.0.11",
- "@uniswap/analytics": "1.1.0",
- "@uniswap/analytics-events": "2.0.0",
+ "@mdx-js/react": "^3.0.0",
+ "@types/react": "^18.0.0",
"algoliasearch": "^4.9.1",
- "caniuse-lite": "^1.0.30001519",
"clsx": "^1.1.1",
"hast-util-is-element": "1.1.0",
"intl-locales-supported": "^1.8.12",
"react": "18",
"react-dom": "18",
"react-feather": "^2.0.10",
- "rehype-katex": "5",
- "remark-math": "3",
- "web-vitals": "2.1.0"
+ "rehype-katex": "^7.0.0",
+ "remark-math": "^6.0.0"
},
"browserslist": {
"production": [
@@ -53,7 +49,7 @@
]
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^2.1.0",
+ "@docusaurus/module-type-aliases": "^3.8.1",
"@tsconfig/docusaurus": "^1.0.6",
"@typescript-eslint/eslint-plugin": "^4",
"@typescript-eslint/parser": "^4",
@@ -72,7 +68,8 @@
},
"engines": {
"npm": "please-use-yarn",
- "node": "16",
+ "node": ">=18",
"yarn": ">=1.22"
- }
-}
\ No newline at end of file
+ },
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
+}
diff --git a/src/components/SentimentTracking/index.tsx b/src/components/SentimentTracking/index.tsx
index d1973d7ec..49f198ba8 100644
--- a/src/components/SentimentTracking/index.tsx
+++ b/src/components/SentimentTracking/index.tsx
@@ -1,6 +1,4 @@
import styled from '@emotion/styled'
-import { TraceEvent } from '@uniswap/analytics'
-import { BrowserEvent, DocsSentiment, DocsSentimentSection, SharedEventName } from '@uniswap/analytics-events'
import React, { useCallback, useState } from 'react'
import { Frown, Meh, Smile } from 'react-feather'
@@ -23,6 +21,7 @@ const Container = styled.div`
const PositiveSentimentIcon = styled(Smile)<{ selected: boolean }>`
fill: ${(props) => (props.selected ? colors.greenVibrant : 'transparent')};
opacity: ${(props) => (props.selected ? Opacity.FULL : Opacity.MEDIUM)};
+ cursor: pointer;
&:hover {
fill: ${colors.greenVibrant};
@@ -32,6 +31,7 @@ const PositiveSentimentIcon = styled(Smile)<{ selected: boolean }>`
const NegativeSentimentIcon = styled(Frown)<{ selected: boolean }>`
fill: ${(props) => (props.selected ? colors.redVibrant : 'transparent')};
opacity: ${(props) => (props.selected ? Opacity.FULL : Opacity.MEDIUM)};
+ cursor: pointer;
&:hover {
fill: ${colors.redVibrant};
@@ -42,6 +42,7 @@ const NeutralSentimentIcon = styled(Meh)<{ selected: boolean }>`
fill: ${(props) => (props.selected ? colors.yellowVibrant : 'transparent')};
opacity: ${(props) => (props.selected ? Opacity.FULL : Opacity.MEDIUM)};
margin: 0 0.2rem;
+ cursor: pointer;
&:hover {
fill: ${colors.yellowVibrant};
@@ -53,7 +54,7 @@ const StyledTextDiv = styled.div`
padding-right: 0.5rem;
`
-export default function SentimentTracking({ analyticsSection }: { analyticsSection: DocsSentimentSection }) {
+export default function SentimentTracking() {
const [selectedSentiment, setSelectedSentiment] = useState