Merge branch 'main' into feat/ts-support
This commit is contained in:
@@ -5,7 +5,8 @@ GITHUB_ID=""
|
||||
NEXT_PUBLIC_COMPILE_API_ENDPOINT="http://localhost:9000/api/build"
|
||||
NEXT_PUBLIC_COMPILE_API_BASE_URL="http://localhost:9000"
|
||||
NEXT_PUBLIC_LANGUAGE_SERVER_API_ENDPOINT="ws://localhost:9000/language-server/c"
|
||||
NEXT_PUBLIC_TESTNET_URL="hooks-testnet-v2.xrpl-labs.com"
|
||||
NEXT_PUBLIC_DEBUG_STREAM_URL="hooks-testnet-v2-debugstream.xrpl-labs.com"
|
||||
NEXT_PUBLIC_EXPLORER_URL="hooks-testnet-v2-explorer.xrpl-labs.com"
|
||||
NEXT_PUBLIC_SITE_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_TESTNET_URL="hooks-testnet-v3.xrpl-labs.com"
|
||||
NEXT_PUBLIC_DEBUG_STREAM_URL="hooks-testnet-v3-debugstream.xrpl-labs.com"
|
||||
NEXT_PUBLIC_EXPLORER_URL="hooks-testnet-v3-explorer.xrpl-labs.com"
|
||||
NEXT_PUBLIC_NETWORK_ID="21338"
|
||||
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -34,3 +34,7 @@ yarn-error.log*
|
||||
# vercel
|
||||
.vercel
|
||||
.vscode
|
||||
|
||||
# yarn
|
||||
.yarnrc.yml
|
||||
.yarn/
|
||||
|
||||
@@ -33,6 +33,7 @@ import { addFunds } from '../state/actions/addFaucetAccount'
|
||||
import { deleteHook } from '../state/actions/deployHook'
|
||||
import { capitalize } from '../utils/helpers'
|
||||
import { deleteAccount } from '../state/actions/deleteAccount'
|
||||
import { xrplSend } from '../state/actions/xrpl-client'
|
||||
|
||||
export const AccountDialog = ({
|
||||
activeAccountAddress,
|
||||
@@ -301,7 +302,7 @@ const Accounts: FC<AccountProps> = props => {
|
||||
const fetchAccInfo = async () => {
|
||||
if (snap.clientStatus === 'online') {
|
||||
const requests = snap.accounts.map(acc =>
|
||||
snap.client?.send({
|
||||
xrplSend({
|
||||
id: `hooks-builder-req-info-${acc.address}`,
|
||||
command: 'account_info',
|
||||
account: acc.address
|
||||
@@ -329,7 +330,7 @@ const Accounts: FC<AccountProps> = props => {
|
||||
}
|
||||
})
|
||||
const objectRequests = snap.accounts.map(acc => {
|
||||
return snap.client?.send({
|
||||
return xrplSend({
|
||||
id: `hooks-builder-req-objects-${acc.address}`,
|
||||
command: 'account_objects',
|
||||
account: acc.address
|
||||
|
||||
@@ -15,7 +15,7 @@ const contentShow = keyframes({
|
||||
'100%': { opacity: 1 }
|
||||
})
|
||||
const StyledOverlay = styled(DialogPrimitive.Overlay, {
|
||||
zIndex: 10000,
|
||||
zIndex: 3000,
|
||||
backgroundColor: blackA.blackA9,
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
|
||||
@@ -21,7 +21,7 @@ import { saveFile } from '../../state/actions/saveFile'
|
||||
import { getErrors, getTags } from '../../utils/comment-parser'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
const generateHtmlTemplate = (code: string, data?: Record<string, any>) => {
|
||||
const generateHtmlTemplate = async (code: string, data?: Record<string, any>) => {
|
||||
let processString: string | undefined
|
||||
const process = { env: { NODE_ENV: 'production' } } as any
|
||||
if (data) {
|
||||
@@ -29,8 +29,10 @@ const generateHtmlTemplate = (code: string, data?: Record<string, any>) => {
|
||||
process.env[key] = data[key]
|
||||
})
|
||||
}
|
||||
|
||||
processString = JSON.stringify(process)
|
||||
|
||||
const libs = (await import("xrpl-accountlib/dist/browser.hook-bundle.js")).default;
|
||||
return `
|
||||
<html>
|
||||
<head>
|
||||
@@ -72,7 +74,9 @@ const generateHtmlTemplate = (code: string, data?: Record<string, any>) => {
|
||||
|
||||
window.addEventListener('error', windowErrorHandler);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
${libs}
|
||||
</script>
|
||||
<script type="module">
|
||||
${code}
|
||||
</script>
|
||||
@@ -100,6 +104,7 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => {
|
||||
const [fields, setFields] = useState<Fields>({})
|
||||
const [iFrameCode, setIframeCode] = useState('')
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const getFields = useCallback(() => {
|
||||
const inputTags = ['input', 'param', 'arg', 'argument']
|
||||
@@ -127,16 +132,31 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => {
|
||||
return fields
|
||||
}, [content])
|
||||
|
||||
const runScript = useCallback(() => {
|
||||
const runScript = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
// Show loading toast only after 1 second, otherwise skip it.
|
||||
let loaded = false
|
||||
let toastId: string | undefined;
|
||||
setTimeout(() => {
|
||||
if (!loaded) {
|
||||
toastId = toast.loading('Loading packages, may take a few seconds...', {
|
||||
position: 'bottom-center',
|
||||
})
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
let data: any = {}
|
||||
Object.keys(fields).forEach(key => {
|
||||
data[key] = fields[key].value
|
||||
})
|
||||
const template = generateHtmlTemplate(content, data)
|
||||
|
||||
const template = await generateHtmlTemplate(content, data)
|
||||
setIframeCode(template)
|
||||
|
||||
loaded = true
|
||||
if (toastId) {
|
||||
toast.dismiss(toastId)
|
||||
}
|
||||
state.scriptLogs = [{ type: 'success', message: 'Started running...' }]
|
||||
} catch (err) {
|
||||
state.scriptLogs = [
|
||||
@@ -145,6 +165,7 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => {
|
||||
{ type: 'error', message: err?.message || 'Could not parse template' }
|
||||
]
|
||||
}
|
||||
setIsLoading(false);
|
||||
}, [content, fields, snap.scriptLogs])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -174,11 +195,11 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => {
|
||||
|
||||
const isDisabled = Object.values(fields).some(field => field.required && !field.value)
|
||||
|
||||
const handleRun = useCallback(() => {
|
||||
const handleRun = useCallback(async () => {
|
||||
if (isDisabled) return toast.error('Please fill in all the required fields.')
|
||||
|
||||
state.scriptLogs = []
|
||||
runScript()
|
||||
await runScript();
|
||||
setIsDialogOpen(false)
|
||||
}, [isDisabled, runScript])
|
||||
|
||||
@@ -279,7 +300,7 @@ const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => {
|
||||
<DialogClose asChild>
|
||||
<Button outline>Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button variant="primary" isDisabled={isDisabled} onClick={handleRun}>
|
||||
<Button variant="primary" isDisabled={isDisabled || isLoading} isLoading={isLoading} onClick={handleRun}>
|
||||
Run script
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
@@ -245,5 +245,14 @@
|
||||
}
|
||||
},
|
||||
"Sequence": 12
|
||||
},
|
||||
{
|
||||
"TransactionType": "Invoke",
|
||||
"Fee": "12"
|
||||
},
|
||||
{
|
||||
"TransactionType": "UriToken",
|
||||
"Fee": "12",
|
||||
"URI": "697066733A2F2F516D614374444B5A4656767666756676626479346573745A626851483744586831364354707631686F776D424779"
|
||||
}
|
||||
]
|
||||
@@ -20,7 +20,7 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
config.module.rules.push({
|
||||
test: /\.md$/,
|
||||
test: [/\.md$/, /hook-bundle\.js$/],
|
||||
use: 'raw-loader'
|
||||
})
|
||||
return config
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"format": "prettier --write .",
|
||||
"postinstall": "patch-package"
|
||||
"postinstall": "patch-package && yarn run postinstall-postinstall",
|
||||
"postinstall-postinstall": "./node_modules/.bin/browserify -r ripple-binary-codec -r ripple-keypairs -r ripple-address-codec -r ripple-secret-codec -r ./node_modules/xrpl-accountlib/dist/index.js:xrpl-accountlib -o node_modules/xrpl-accountlib/dist/browser.hook-bundle.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codingame/monaco-jsonrpc": "^0.3.1",
|
||||
@@ -66,8 +67,8 @@
|
||||
"vscode-languageserver": "^7.0.0",
|
||||
"vscode-uri": "^3.0.2",
|
||||
"wabt": "^1.0.32",
|
||||
"xrpl-accountlib": "^1.5.2",
|
||||
"xrpl-client": "^1.9.4"
|
||||
"xrpl-accountlib": "^1.6.1",
|
||||
"xrpl-client": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dinero.js": "^1.9.0",
|
||||
@@ -76,6 +77,7 @@
|
||||
"@types/lodash.xor": "^4.5.6",
|
||||
"@types/pako": "^1.0.2",
|
||||
"@types/react": "17.0.31",
|
||||
"browserify": "^17.0.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-next": "^13.1.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
5
raw-loader.d.ts
vendored
5
raw-loader.d.ts
vendored
@@ -2,3 +2,8 @@ declare module '*.md' {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module '*.hook-bundle.js' {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { ref } from 'valtio'
|
||||
import estimateFee from '../../utils/estimateFee'
|
||||
import { SetHookData } from '../../utils/setHook'
|
||||
import ResultLink from '../../components/ResultLink'
|
||||
import { xrplSend } from './xrpl-client'
|
||||
|
||||
export const sha256 = async (string: string) => {
|
||||
const utf8 = new TextEncoder().encode(string)
|
||||
@@ -64,9 +65,6 @@ export const prepareDeployHookTx = async (
|
||||
if (!activeFile?.compiledContent) {
|
||||
return
|
||||
}
|
||||
if (!state.client) {
|
||||
return
|
||||
}
|
||||
const HookNamespace = (await sha256(data.HookNamespace)).toUpperCase()
|
||||
const hookOnValues: (keyof TTS)[] = data.Invoke.map(tt => tt.value)
|
||||
const { HookParameters } = data
|
||||
@@ -87,12 +85,13 @@ export const prepareDeployHookTx = async (
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
if (typeof window !== 'undefined') {
|
||||
if (typeof window === 'undefined') return
|
||||
const tx = {
|
||||
Account: account.address,
|
||||
TransactionType: 'SetHook',
|
||||
Sequence: account.sequence,
|
||||
Fee: data.Fee,
|
||||
NetworkID: process.env.NEXT_PUBLIC_NETWORK_ID,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
@@ -111,36 +110,31 @@ export const prepareDeployHookTx = async (
|
||||
}
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
/* deployHook function turns the wasm binary into
|
||||
* hex string, signs the transaction and deploys it to
|
||||
* Hooks testnet.
|
||||
/*
|
||||
* Turns the wasm binary into hex string, signs the transaction and deploys it to Hooks testnet.
|
||||
*/
|
||||
export const deployHook = async (account: IAccount & { name?: string }, data: SetHookData) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const activeFile = state.files[state.active]?.compiledContent
|
||||
? state.files[state.active]
|
||||
: state.files.filter(file => file.compiledContent)[0]
|
||||
state.deployValues[activeFile.name] = data
|
||||
|
||||
const tx = await prepareDeployHookTx(account, data)
|
||||
if (!tx) {
|
||||
return
|
||||
}
|
||||
if (!state.client) {
|
||||
return
|
||||
}
|
||||
const keypair = derive.familySeed(account.secret)
|
||||
|
||||
const { signedTransaction } = sign(tx, keypair)
|
||||
|
||||
const currentAccount = state.accounts.find(acc => acc.address === account.address)
|
||||
if (currentAccount) {
|
||||
currentAccount.isLoading = true
|
||||
}
|
||||
let submitRes
|
||||
|
||||
let submitRes
|
||||
try {
|
||||
submitRes = await state.client?.send({
|
||||
submitRes = await xrplSend({
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
})
|
||||
@@ -185,7 +179,7 @@ export const deployHook = async (account: IAccount & { name?: string }, data: Se
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
console.error(err)
|
||||
state.deployLogs.push({
|
||||
type: 'error',
|
||||
message: 'Error occurred while deploying'
|
||||
@@ -196,22 +190,18 @@ export const deployHook = async (account: IAccount & { name?: string }, data: Se
|
||||
}
|
||||
return submitRes
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteHook = async (account: IAccount & { name?: string }) => {
|
||||
if (!state.client) {
|
||||
return
|
||||
}
|
||||
const currentAccount = state.accounts.find(acc => acc.address === account.address)
|
||||
if (currentAccount?.isLoading || !currentAccount?.hooks.length) {
|
||||
return
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
const tx = {
|
||||
Account: account.address,
|
||||
TransactionType: 'SetHook',
|
||||
Sequence: account.sequence,
|
||||
Fee: '100000',
|
||||
NetworkID: process.env.NEXT_PUBLIC_NETWORK_ID,
|
||||
Hooks: [
|
||||
{
|
||||
Hook: {
|
||||
@@ -221,25 +211,22 @@ export const deleteHook = async (account: IAccount & { name?: string }) => {
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const keypair = derive.familySeed(account.secret)
|
||||
try {
|
||||
// Update tx Fee value with network estimation
|
||||
const res = await estimateFee(tx, account)
|
||||
tx['Fee'] = res?.base_fee ? res?.base_fee : '1000'
|
||||
tx['Fee'] = res?.base_fee || '1000'
|
||||
} catch (err) {
|
||||
// use default value what you defined earlier
|
||||
console.log(err)
|
||||
console.error(err)
|
||||
}
|
||||
const { signedTransaction } = sign(tx, keypair)
|
||||
|
||||
if (currentAccount) {
|
||||
currentAccount.isLoading = true
|
||||
}
|
||||
let submitRes
|
||||
const toastId = toast.loading('Deleting hook...')
|
||||
try {
|
||||
submitRes = await state.client.send({
|
||||
submitRes = await xrplSend({
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
})
|
||||
@@ -279,4 +266,3 @@ export const deleteHook = async (account: IAccount & { name?: string }) => {
|
||||
}
|
||||
return submitRes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import { derive, sign } from 'xrpl-accountlib'
|
||||
|
||||
import state from '..'
|
||||
import type { IAccount } from '..'
|
||||
|
||||
interface TransactionOptions {
|
||||
TransactionType: string
|
||||
Account?: string
|
||||
Fee?: string
|
||||
Destination?: string
|
||||
[index: string]: any
|
||||
}
|
||||
interface OtherOptions {
|
||||
logPrefix?: string
|
||||
}
|
||||
|
||||
export const sendTransaction = async (
|
||||
account: IAccount,
|
||||
txOptions: TransactionOptions,
|
||||
options?: OtherOptions
|
||||
) => {
|
||||
if (!state.client) throw Error('XRPL client not initalized')
|
||||
|
||||
const { Fee = '1000', ...opts } = txOptions
|
||||
const tx: TransactionOptions = {
|
||||
Account: account.address,
|
||||
Sequence: account.sequence,
|
||||
Fee, // TODO auto-fillable default
|
||||
...opts
|
||||
}
|
||||
const { logPrefix = '' } = options || {}
|
||||
try {
|
||||
const signedAccount = derive.familySeed(account.secret)
|
||||
const { signedTransaction } = sign(tx, signedAccount)
|
||||
const response = await state.client.send({
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
})
|
||||
if (response.engine_result === 'tesSUCCESS') {
|
||||
state.transactionLogs.push({
|
||||
type: 'success',
|
||||
message: `${logPrefix}[${response.engine_result}] ${response.engine_result_message}`
|
||||
})
|
||||
} else {
|
||||
state.transactionLogs.push({
|
||||
type: 'error',
|
||||
message: `${logPrefix}[${response.error || response.engine_result}] ${
|
||||
response.error_exception || response.engine_result_message
|
||||
}`
|
||||
})
|
||||
}
|
||||
const currAcc = state.accounts.find(acc => acc.address === account.address)
|
||||
if (currAcc && response.account_sequence_next) {
|
||||
currAcc.sequence = response.account_sequence_next
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
state.transactionLogs.push({
|
||||
type: 'error',
|
||||
message:
|
||||
err instanceof Error
|
||||
? `${logPrefix}Error: ${err.message}`
|
||||
: `${logPrefix}Something went wrong, try again later`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import state from '..'
|
||||
import type { IAccount } from '..'
|
||||
import ResultLink from '../../components/ResultLink'
|
||||
import { ref } from 'valtio'
|
||||
import { xrplSend } from './xrpl-client'
|
||||
|
||||
interface TransactionOptions {
|
||||
TransactionType: string
|
||||
@@ -21,20 +22,19 @@ export const sendTransaction = async (
|
||||
txOptions: TransactionOptions,
|
||||
options?: OtherOptions
|
||||
) => {
|
||||
if (!state.client) throw Error('XRPL client not initalized')
|
||||
|
||||
const { Fee = '1000', ...opts } = txOptions
|
||||
const tx: TransactionOptions = {
|
||||
Account: account.address,
|
||||
Sequence: account.sequence,
|
||||
Fee, // TODO auto-fillable default
|
||||
Fee,
|
||||
NetworkID: process.env.NEXT_PUBLIC_NETWORK_ID,
|
||||
...opts
|
||||
}
|
||||
const { logPrefix = '' } = options || {}
|
||||
try {
|
||||
const signedAccount = derive.familySeed(account.secret)
|
||||
const { signedTransaction } = sign(tx, signedAccount)
|
||||
const response = await state.client.send({
|
||||
const response = await xrplSend({
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
})
|
||||
|
||||
7
state/actions/xrpl-client.ts
Normal file
7
state/actions/xrpl-client.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { XrplClient } from 'xrpl-client';
|
||||
import state from '..';
|
||||
|
||||
export const xrplSend = async(...params: Parameters<XrplClient['send']>) => {
|
||||
const client = await state.client.ready()
|
||||
return client.send(...params);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export interface IState {
|
||||
splits: {
|
||||
[id: string]: SplitSize
|
||||
}
|
||||
client: XrplClient | null
|
||||
client: XrplClient
|
||||
clientStatus: 'offline' | 'online'
|
||||
mainModalOpen: boolean
|
||||
mainModalShowed: boolean
|
||||
@@ -114,7 +114,7 @@ let initialState: IState = {
|
||||
tabSize: 2
|
||||
},
|
||||
splits: {},
|
||||
client: null,
|
||||
client: undefined!, // set below only.
|
||||
clientStatus: 'offline' as 'offline',
|
||||
mainModalOpen: false,
|
||||
mainModalShowed: false,
|
||||
@@ -154,9 +154,9 @@ const state = proxy<IState>({
|
||||
})
|
||||
// Initialize socket connection
|
||||
const client = new XrplClient(`wss://${process.env.NEXT_PUBLIC_TESTNET_URL}`)
|
||||
state.client = ref(client);
|
||||
|
||||
client.on('online', () => {
|
||||
state.client = ref(client)
|
||||
state.clientStatus = 'online'
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import toast from 'react-hot-toast'
|
||||
import { derive, sign } from 'xrpl-accountlib'
|
||||
import state, { IAccount } from '../state'
|
||||
import { IAccount } from '../state'
|
||||
import { xrplSend } from '../state/actions/xrpl-client'
|
||||
|
||||
const estimateFee = async (
|
||||
tx: Record<string, unknown>,
|
||||
@@ -22,7 +23,7 @@ const estimateFee = async (
|
||||
const keypair = derive.familySeed(account.secret)
|
||||
const { signedTransaction } = sign(copyTx, keypair)
|
||||
|
||||
const res = await state.client?.send({ command: 'fee', tx_blob: signedTransaction })
|
||||
const res = await xrplSend({ command: 'fee', tx_blob: signedTransaction })
|
||||
if (res && res.drops) {
|
||||
return res.drops
|
||||
}
|
||||
|
||||
@@ -29,17 +29,15 @@ export const tts = {
|
||||
export type TTS = typeof tts
|
||||
|
||||
const calculateHookOn = (arr: (keyof TTS)[]) => {
|
||||
let start = '0x000000003e3ff5bf'
|
||||
let s = '0x3e3ff5bf'
|
||||
arr.forEach(n => {
|
||||
let v = BigInt(start)
|
||||
v ^= BigInt(1) << BigInt(tts[n as keyof TTS])
|
||||
let s = v.toString(16)
|
||||
let l = s.length
|
||||
if (l < 16) s = '0'.repeat(16 - l) + s
|
||||
s = '0x' + s
|
||||
start = s
|
||||
let v = BigInt(s)
|
||||
v ^= BigInt(1) << BigInt(tts[n])
|
||||
s = "0x" + v.toString(16)
|
||||
})
|
||||
return start.substring(2)
|
||||
s = s.replace('0x', '')
|
||||
s = s.padStart(64, '0')
|
||||
return s
|
||||
}
|
||||
|
||||
export default calculateHookOn
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,6 +22,7 @@ import hooksFloatManipPure from './md/hooks-float-manip-pure.md'
|
||||
import hooksFloatOnePure from './md/hooks-float-one-pure.md'
|
||||
import hooksFloatPure from './md/hooks-float-pure.md'
|
||||
import hooksGuardCalled from './md/hooks-guard-called.md'
|
||||
import hooksGuardCallNonConst from './md/hooks-guard-call-non-const.md'
|
||||
import hooksGuardInFor from './md/hooks-guard-in-for.md'
|
||||
import hooksGuardInWhile from './md/hooks-guard-in-while.md'
|
||||
import hooksHashBufLen from './md/hooks-hash-buf-len.md'
|
||||
@@ -70,6 +71,7 @@ const docs: { [key: string]: string } = {
|
||||
'hooks-float-one-pure': hooksFloatOnePure,
|
||||
'hooks-float-pure': hooksFloatPure,
|
||||
'hooks-guard-called': hooksGuardCalled,
|
||||
'hooks-guard-call-non-const': hooksGuardCallNonConst,
|
||||
'hooks-guard-in-for': hooksGuardInFor,
|
||||
'hooks-guard-in-while': hooksGuardInWhile,
|
||||
'hooks-hash-buf-len': hooksHashBufLen,
|
||||
|
||||
6
xrpl-hooks-docs/md/hooks-guard-call-non-const.md
Normal file
6
xrpl-hooks-docs/md/hooks-guard-call-non-const.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# hooks-guard-call-non-const
|
||||
|
||||
Only compile-time constants can be used as an argument in loop GUARD call. This check warns if a non compile-time constant is used.
|
||||
It also checks whether a compile-time constant is used as a first argument of `_g()` call and whether it is a unique value. If not - it warns.
|
||||
|
||||
[Read more](https://xrpl-hooks.readme.io/v2.0/docs/loops-and-guarding)
|
||||
@@ -1,14 +1,35 @@
|
||||
# hooks-guard-in-for
|
||||
|
||||
A guard is a marker that must be placed in your code at the top of each loop. Consider the following for-loop in C:
|
||||
Consider the following for-loop in C:
|
||||
|
||||
```c
|
||||
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
|
||||
|
||||
for (int i = 0; GUARD(3), i < 3; ++i)
|
||||
```
|
||||
|
||||
<BR/>
|
||||
This is the only way to satisfy the guard rule when using a for-loop in C.
|
||||
To satisfy the guard rule when using a for-loop in C guard should be
|
||||
placed either in the condition part of the loop, or as a first call in loop body, e.g.
|
||||
|
||||
```c
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
GUARD(3);
|
||||
}
|
||||
```
|
||||
|
||||
In case of nested loops, the guard limit value should be
|
||||
multiplied by a number of iterations in each loop, e.g.
|
||||
|
||||
```c
|
||||
for(int i = 0; GUARD(3), i < 3; ++i) {
|
||||
for (int j = 0; GUARD(17), j < 5; ++j)
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
(most descendant loop iterations + 1) * (each parent loops iterations) - 1
|
||||
```
|
||||
|
||||
This check will warn if the GUARD call is missing and also it will propose a GUARD value based on the for loop initial value,
|
||||
the increment and loop condition.
|
||||
|
||||
[Read more](https://xrpl-hooks.readme.io/v2.0/docs/loops-and-guarding)
|
||||
|
||||
Reference in New Issue
Block a user