📜 [專欄新文章] Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound
✍️ 田少谷 Shao
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound
V̶y̶p̶e̶r̶ Solidity coding time!
Image source: https://uniswap.org/
Outline
一. 前言二. 程式碼結構 1. Wrapped Ether(WETH)? 2. Impermanent Loss三. 創建交易對 - 準備 Interfaces四. 注入資金 - 注意事項五. 兌換虛擬貨幣六. 取得報價作為預言機七. 自行兌換 WETH八. 結語
一. 前言
暨上一篇解釋了 Uniswap 的演算法後,由於個人有使用 Uniswap v2 的需求,因此整理後寫成本篇,希望能幫助到其他也需要用 Uniswap 的讀者!(不熟 Uniswap 的人也可以參考區塊勢 許明恩 Astro Hsu 寫的介紹文:點我)
Uniswap 解析:恆定乘積做市商模型 Constant Product Market Maker Model 的 Vyper 實作
本文希望透過實際操作 Uniswap 我個人會用到、我認為大家比較常會用到的功能,來讓不熟悉的讀者快速了解其程式架構(v2 相較 v1 繁複)、熟悉實作方法,無法顧及全部還請見諒。
以下實作的測試環境為 Rinkeby 測試網,由於只是要講解使用方法,因此選擇在 Remix 上操作。
而 Uniswap v2 跟 v1 的差異,個人沒有很認真研究,大致列舉以下幾點,本文只會就其中幾點在後方進行較詳細的解釋:
使用 Wrapped Ether, WETH (於 二. 程式碼結構 解釋),讓 ERC20 交易對不再需要透過 Ether ,降低 gas 的消耗,但還是可以用 Ether 支付
加入時間權重的預言機,降低被操縱價格的風險,於 六. 取得報價作為預言機 中舉例說明,有興趣者可以看看 白皮書 有詳細介紹
閃電貸
使用 Solidity 而非 Vyper,因為 Solidity 功能上較齊全,於 五. 兌換虛擬貨幣 中舉例說明原因
在開始之前,本文超長,播個背景音樂吧:
二. 程式碼結構
本段落簡單描述 Uniswap 程式碼各部分的功能。若讀者要自己實作,可以參考此處得知該去哪一份程式碼找相應的功能:
Factory / UniswapV2Factory.sol : 創建交易對、查詢交易對的地址與總數;查詢、指定交易對手續費的收款地址
Pair(ERC-20) / UniswapV2ERC20.sol : Uniswap 流動性代幣 ERC20 的部分
Pair / UniswapV2Pair.sol : Uniswap 流動性代幣的其他部分;查詢交易對資訊
Router / UniswapV2Router01.sol : 注入、取出流動性/資金;兌換虛擬貨幣。此合約看似最複雜,其實只是因為收付款的單位可以是 Ether 或是 ERC20,所以有很多重複的函式
ExampleOracleSimple.sol, ExampleSlidingWindowOracle.sol : 預言機的範例程式碼
Library / UniswapV2OracleLibrary.sol : 供預言機調用的函式
Library / UniswapV2Library.sol : 供內部調用的函式
除了描述程式碼結構,為了以下的實作我們還需要知道 Wrapped Ether 是什麼,順便了解其使用原因:
1. Wrapped Ether (WETH) ?
從字面上來解釋,Wrapped Ether 是被包起來的 Ether。那為什麼好好的 Ether 不用還要創造出另一版本,嫌這小小世界的術語不夠多嗎 (ETH, WETH, Dai, aDai, cDai, sDai…)?xD
wETH | ERC20 tradable version of ETH
主因有兩個:廣泛地說,Ether 是以太坊上的原生虛擬貨幣,但它與廣為使用的 ERC20 標準並不相容( ERC20 有 approve(), transfer() 等等功能);而針對 Uniswap 的場景來說,v1 的交易對都一定有 Ether,而使用 Ether 可能會造成 Impermanent Loss,於下方解釋。
因此,就以上兩點的解決方法個別是:
部署一 ERC20 <-> Ether 的兌換合約:使用者將 Ether 付給 Wrapped Ether (ERC20) 的智能合約,合約就會給使用者同等數目的 WETH;拿回 Ether 則有點不太一樣,方法是告訴 WETH 的合約使用者要 withdraw(),WETH 的合約就會把使用者 WETH 擁有的額度設回 0 (或減少) 並返還 Ether,於 五. 兌換虛擬貨幣 中舉例說明
v2 交易對的建立不再只能是 (Ether, ERC20),可以是 (ERC20, ERC20)
2. Impermanent Loss
Impermanent loss 在 DeFi 指的是像 Uniswap 這類用演算法的去中心化交易所,如果交易對是兩幣價不相干的虛擬貨幣,例如:穩定幣 (Dai, USDC, etc) 和 Ether,流動性提供者 liquidity provider 會因為幣價的相對波動而比起直接持有兩幣還損失了一筆。
容我舉個例解釋清楚點,可以搭配我上一篇所寫的 Uniswap 的演算法 來理解:假設一開始 1 Ether 幣價為 100 Dai,只有一流動性提供者 LP 投入了 1 Ether 及 100 Dai (1 * 100 = 100 = k,k值要維持不變),總價值為 200 Dai。當 Ether 的幣價來到 200 Dai,眼尖者會發現資金池中的 Ether 價格低、有利可圖,因此會進行套利,例如:拿 33 Dai 約可以換到 0.25 Ether (0.75 * 133 ≒ 100),比起市場上要用 50 Dai 才能換到 0.25 Ether,套利者賺到了。此時,流動性提供者若將自己的資金提出,0.75 Ether 和 133 Dai 此時的總價值是 283 Dai,看似比當初的 200 Dai 還多,但其實將兩幣放著不動 1 Ether + 100 Dai 在此時就已經是 300 Dai 的價值了。於是,impermanent loss 就變成了 permanent loss :(
三. 創建交易對
- 準備 Interfaces
在開始之前,由於使用到的合約不少,所以我將全部所需整理在此:點我。其中,UniswapImplementation.sol 是本文實作的檔案。
若讀者在自己調用 Interface 時遇到版本問題,就依照 compiler 提供的指示稍作修改即可。我所整理的合約都修正過版本的差異、以下的實作也測試了可行,因此可以安心使用。
進入正題
通常大家使用的 Uniswap 資金池都是已經存在的,而如果想要上架自己的虛擬貨幣就要自己創建一組新的交易對,有兩種方式:在 Uniswap 官網上執行或是透過呼叫 Uniswap 的合約來建立,本文使用合約的方式。
首先,我們需要決定資金池為哪兩種虛擬貨幣,那就很普通地選 ETH 和 Dai 吧。雖然選了 ETH,但如同上方所述實際上必須使用 WETH,於是記下其在 Rinkeby 上的位置 。Dai 就使用 Compound 部署在 Rinkeby 上的版本,位置在 0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa。
接著,打開 IUniswapVFactory.sol,依照官方文件的指示將此合約部署在 Rinkeby 上的 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f。以下會有許多由 Uniswap 文件得知的合約地址及其他資訊等等,就不再一一附上來源或畫面截圖!
如上圖黑框所示,輸入了地址後按下藍色按鍵就完成部署了。接著,如下圖將 Dai 的地址 及 WETH 的地址輸入 createPair():
由於這個交易對我已經部署過了,因此讀者若想嘗試就麻煩去找別的 Rinkeby 上的測試幣了、或自己發一個! 完成後可以用 getPair() 輸入兩幣地址來確認交易對被建立成功:
如果想要進一步核對,可以先呼叫下圖紅框中的 allPairsLength(),得知當前總共有幾組交易對,再將 (交易對數 - 1) 輸入 allPairs(),就能得到和上圖一樣的地址。需要減 1 是因為陣列的 index 從 0 開始。
allPairsLength 的值會因為其他人的使用而增加,故日後可能會和本圖產出的 9 不同
四. 注入資金
看到標題的讀者可能會想:為何要把注入資金/流動性和上方的創建交易對分開呢?因為注入流動性這個功能被放在了 UniswapV2Router01.sol 中,所以就分開解釋。
雖然上一節只需要複製貼上按按鍵,但接下來要探討的注入資金 addLiquidity() 及虛擬貨幣的交換 swap()比起創建交易對 createPair() 是較有可能被融入到其他 DeFi 服務的功能(應該不太會有人會一直需要創建新的交易對),因此打開 UniswapImplementation.sol、要開始 Solidity coding!
如果不熟悉為何別的 DeFi 會需要在自己的服務中使用 Uniswap,可以搜尋 DeFi Money Lego/ DeFi 樂高,顧名思義就是在一個 DeFi 服務上使用另一個 DeFi 服務。實際的例子有:Aave 的新功能是可以拿往 Uniswap 注入流動性後得到的流動性代幣再投入 Aave 來賺取利息,以及下一節兌換虛擬貨幣的功能可以在 Pelith 的輕鬆貸 EasyDai、一站式 DeFi 組合工具 Furucombo 等場景中看到他們如何將 Uniswap 銜接上其他的 DeFi 服務。
回歸正題
在開始之前,先簡單提及一下有哪些變數、instance 需要初始化:
我們要呼叫 Uniswap 合約的 instance 來進行互動: IUniswapV2Router01
不只需要 Dai 的 instance,也需要 Dai 和 WETH 的地址;DaiAmount 和 ETHAmount 是為了稍後注入流動性所設置的,本文假設第一筆流動性我們使用 200 Dai + 1 Ether
immutable 是版本 0.6.5 加入的,用途是讓變數只能被讀取 read-only,但不同於 constant 的是能夠在 constructor() 中賦值。之所以各 instance 的地址不一起加上 immutable ,是因為若加上了,這些地址就不能在 constructor() 中被使用
p.s. 由於 gist 沒有 Solidity 的 syntax highlighting,所以隨便用了 .js 請忽略
看完了初始設定後,由於我們目前鎖定的資金池是 Dai 及 ETH,因此使用如下的 addLiquidityETH() 此函式,可以直接匯入 ETH 及 Dai。
本處我使用長度為 3 的陣列 addLiquidityResult 來記錄注入資金後的返回值:注入 Ether 的數量、Dai 的數量及返回的 Uniswap 流動性代幣的數量。實際上應該要依照不同使用者記錄的他們執行 addLiquidity() 後各自的返還值
第五行中的 approve() 是為了讓 UniswapV2Router01 的合約能夠從我們部署的合約 UniswapImplementation 取得 200 Dai 的使用權
於第六行 addLiquidityETH() 後方的大括號 {value: ETHAmount},這是 Solidity 0.6.0 後版本如果要在呼叫 function 的同時送入 Ether 的標準寫法,以前的寫法 .value() 目前也還能用但 compiler 會給提示
addLiquidityETH() 的第三、四個參數為最少要成功注入的數量。使用者能夠成功注入的數量取決於資金池中兩虛擬貨幣當下的數量,而本處直接給 0 比較方便
這邊非常重要的是上述程式碼還欠缺了一個無法被寫在合約內的步驟:使用者要同意這個被部署的合約 UniswapImplementation 可以從自己的帳戶中轉出 200 Dai。因此,將 ERC20 (Dai) 部署在 Rinkeby 上的位置,也就是0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa,接著輸入被部署合約的地址以及 200 Dai = 200000000000000000000、按下 approve() 後準備作業完成,如下圖。
終於可以呼叫 addLiquidity() 了! 如下圖,在紅框中以 1 Ether 呼叫黑框中的 addLiquidity() 後,就能成功將資金注入到 liquidity pool 了! 由於本文寫在測試後,因此沒有留下第一次 addLiquidity() 的結果 :(
此處被部署的合約位置跟上方截圖不同,因為其中測試了一些東西所以重新部署qq
接著,可以拿出 IUniswapV2Pair.sol,將其部署在 三. 創建交易對 中成功部署的位置 0x03E6c12eF405AC3F642B9184eDed8E1322de1a9e,使用黑框中的 getReserves() 就可以看到資金池中確實有匯入的資金! (本處依然沒有第一次使用後的截圖,因此截圖只是為了讓讀者看到 getReserves() 的結果)
此圖黑框中的值代表:在資金池中,Dai的數量、Ether的數量及上一次匯入資金的時間戳記
- 注意事項
使用 addLiquidity() 時需要小心的地方是:除了第一筆注入的資金可以自行決定兩虛擬貨幣的數量,第二筆開始就會依照其演算法算出兩幣可以投入的各自數量,因此使用者放入的兩幣中可能會有部分的其中一幣被 Uniswap 返回。
上方的程式碼只是為了第一筆流動性所寫,如果不是第一筆的情況就需要用成功注入流動性後的返回值(例如筆者的作法是用一陣列 addLiquidityResult 來存結果)來把沒有成功注入的資金返回給使用者。
五. 兌換虛擬貨幣
本節使用的兌換功能依舊是來自 IUniswapV2Router01.sol。
由於兌換虛擬貨幣實際上只有五行不到的程式碼,那麼就來把兌換 Ether 而得到的 Dai… 投到 Compound 來賺取放款利息吧! (雖然只是在測試網) 如果覺得這個場景似曾相識,沒錯,這就是上面提到的 輕鬆貸 EasyDai 的不專業版本!
首先將 Ether 和 Dai 互換的邏輯完成:
Ether 換 Dai : 使用 swapExactETHForTokens(),給某數量的 Ether 能換多少 Dai 是多少
Dai 換 Ether : 使用 swapExactTokensForETH(),作法只差在要把 Dai 轉到當前合約,再同意 UniswapV2Router01 可以從當前合約把 Dai 轉走
兩個做法的第二個參數都是可以自行指定兌換的路徑,此處就直接給 WETH 和 Dai 的地址即可(順序有差)。需要注意的是這個路徑要是動態陣列 dynamic array,而這就是 Vyper 所不支援的功能! 動態陣列跟靜態陣列宣告方式的差別我有註解在程式碼中
此處就先來試試 Dai 換 Ether 吧!和上方一樣,在使用時也要先 approve() 當前合約,當前合約才能轉走使用者的 Dai。
由上方的截圖可以很清楚的看到 Dai 換 Ether 這個動作牽涉到的資金轉移路徑:
Dai: 我的帳戶→當前合約→交易對所在合約
WETH: 交易對所在合約→UniswapV2Router01
Ether: WETH 合約→UniswapV2Router01→我的帳戶
以上的路徑有些人稍微思考後可能會納悶:為什麼上方沒有一筆 WETH 從 UniswapV2Router01 再轉到 WETH 合約的動作呢? 這就是在 Wrapped Ether (WETH) ? 中提到的案例。原因是:把 WETH 還回 WETH 的合約時實際上使用的函示是 withdraw() 而非 transfer(),而在 WETH 合約中發生的只是把使用者 WETH 擁有的額度歸零或減少而已。
接下來就是把 Dai 轉到 Compound 的部分。由於 Compound 不是本文重點,此處只求功能正常,因此比起真正的實作方法當然是簡化許多。
一如往常初始化 Compound 合約的 instance
ETH 換 Dai 後放入 Compound : 將用 ETH 換得的 Dai 的數量,也就是 swapExactETHForTokens() 返回的第二個值,approve() Compound 的合約後就可以用 mint() 匯入了! 要注意的是,ETH 換成 Dai 後的收款地址(第四個參數)是當前合約,才能從此合約轉 Dai 到 Compound
還款給使用者: 用 redeem() 取出 Dai,一如往常同意 UniswapV2Router01 使用 Dai 的權力
之所以說這個程式碼不能真的拿來用是因為:cDai 轉給使用者、讓使用者自己持有是比較安全的作法;即使選擇把 cDai 留在當前合約,以上程式碼檢查 cDai 數量是用當前合約 address(this) 去檢查,實際上應該要去記錄每個使用者所擁有的 cDai 數量
最後附上截圖,可以看一下資金的轉移路徑:
ETH -> WETH -> Dai -> cDai (Compound)
cDai -> Dai -> WETH -> ETH
六. 取得報價作為預言機
若使用 Uniswap v1的報價作為預言機,攻擊者可以利用其演算法造成的滑點來操控價格。為此,Uniswap v2 提供了兩個加入時間權重的合約範例:
ExampleOracleSimple.sol : 簡單版
ExampleSlidingWindowOracle.sol : 複雜版;Sliding Window 在此場景是指透過改變擷取資料(歷史價格)的片段,用該特定期間的價格來做成時間權重,讓使用上更靈活!
本處以簡單版為例。打開 ExampleOracleSimple.sol,由於一些匯入檔案的問題我將 UniswapV2OracleLibrary 也放在這份檔案中。
做法非常簡單:將 UniswapV2Factory、Dai 及 WETH 所在的地址作為部署合約 ExampleOracleSimple 時的輸入值就完成了。部署成功後會有個 24 小時的鎖 Time lock,因為這個預言機是有時間權重的,所以並不是一部署完就能立刻使用。若要體驗更新價格此功能可以使用我部署的兩個,其位置我寫在註解中。
將 WETH 或是 Dai 的地址和要查詢的數量輸入 consult() 就能查到兩虛擬貨幣的價格:
1 ETH 價格約為 97 Dai
1 Dai 價格約為 0.01 ETH
然而,在測試網上我們沒辦法拿著預言機查到的價格套入演算法來核對,因為測試網上的 Uniswap 沒有啟用收費機制,而 k 值要在收費機制啟動時才能被計算,欲知詳情者就麻煩去看官方文件了!
七. 自行兌換 WETH
上方雖然有提到 WETH 在 Uniswap 中的使用原因及場合,但或許有人想試著自己動手將 Ether 換成 WETH、把 WETH 換回 Ether。方法非常簡單,將 WETH.sol 部署到 0xc778417E063141139Fce010982780140Aa0cD5Ab 就能使用,如下圖:
按下綠框中的 At Address 後,使用下方黑框中的 deposit 搭配在中間的黑框輸入所要兌換 Ether 的量,就能成功換到 WETH。同理,圖中未顯示的 withdraw 功能就是讓人輸入 WETH 來換回等量的 Ether。
稍微提一下,如果是第一次兌換,將 WETH 所在的地址輸入 Metamask 就能在錢包中看到自己擁有的 WETH 的數量,如下兩圖:
Voila!
八. 結語
呼,雖然上述操作及程式碼的撰寫其實還蠻簡單的,但畢竟 Uniswap 的功能不少、我個人也希望能將小細節解釋清楚些,因此長度遠超過預期...有看到結尾處的讀者,辛苦了xD 希望大家現在對於 Uniswap v2 的內容跟實作方法都很清楚了!
最後,如果本文有任何錯誤,請不吝提出,我會盡快做修正;而如果我的文章有幫助到你,可以看看我的其他文章,歡迎一起交流 :)
田少谷 Shao - Medium
Uniswap v2 實作 : 從創建交易對到Ether 換 Dai 投入 Compound was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
更新功能變數全部 在 侯漢廷 Facebook 的最佳解答
【漢廷說歷史】週末討論
今天是星期天,恭喜所有學習完一周的朋友。在周日我會挑選3-4個網友的留言,並回答問題,希望大家能一起學習。
第一集留給大家思考的問題是,你覺得養蠶取絲織衣服是嫘祖一人生而知之該這麼做嗎?比較有可能的狀況是什麼?如果一個創新是植基於多樣的基礎或多人的合作,那說明什麼?
【Wei Bang Liu:嫘祖取絲織衣服是經過前人不斷探索的經驗和實踐活動得來的,所以認識和實踐的辯證統一關係可以回答這個問題。創新是一個民族進步的靈魂,是一個國家興旺發達的不竭動力。】
【用戶6432355226:人類學會養蠶取絲織布制衣,肯定不是一個人的智慧,是集體智慧的結晶,人類是群居動物,三個臭皮匠,頂個諸葛亮,找到社會痛點,然後提供解決的辦法,這就是創新,也是商機。】
【李光懋:古時很多創意確實需要長時間的知識累積,或是經驗的傳承,後來更需要共同的努力。】
【lier11041988:創新=市場需求+人才+資金+技術+配套政策】
這四位朋友說的都很正確,偉大的產品和創新往往不是一蹴而就的,而是奠基在許多前人的技術和成果,組合成新的方式,優化並發揮到極致。學者馬祖卡托(Mariana Mazzucato)說,IPHONE的誕生,需要如微處理器、存儲晶片、固態硬盤、液晶顯示、觸摸屏等12個關鍵技術的儲備,這12項技術都不是專門為了IPHONE發明的,但IPHONE能將過去所有的技術組合,加以創新。再比如沃爾瑪,郊區選址、商品低價、店鋪做到大規模、商品包羅萬象,並且利用技術優化運營,每一項都不是沃爾瑪最先發明的。但是,它的真正厲害之處,就是把每一項都發揮到了極致。
第二集留給大家思考的問題是,哪些企業是像王石所說的,培養團隊為主,不特別培養接班人呢?
【專業鏟貓砂:所以小平同志很聰明啊,培養兒子不如建立制度,現在中國的崛起全賴當初他的改開。誰一提到今日中國,都回避不了他,這才是大智慧。】
【耶列納:地產企業傳給二代比較多吧。很多二代從小被培養,素質很高。不過企業興衰也並不是僅有賢人就行,還是要有一套自我適應,更新反覆運算的體系。】
大陸官員選拔精準來說是要貼近「選賢任能」。大陸最高決策機構,即中共中央政治局常委的候選人幾乎都擔任過兩任省委書記或具有其他相應的工作歷練。在中國大陸,治理一個省的工作,對才幹和能力的要求非常之高,因為一個省的平均規模幾乎是歐洲四五個國家的規模。
學者張維為認為,中國近年已經把「選拔」和「選舉」較好地結合起來。因為高級幹部的晉升必須經過大量的基層鍛煉,經過不同崗位的工作實踐,經過包括初步考察、徵求意見、民調、評估、投票、公示等一系列程式,最後才能擔任關鍵職務。
也就是說,民主能保證壞人出局,防止「下下策」,卻未能保證好人當選。但大陸儒家選賢任能的體制能盡力「上上策」選出經考驗的有能者,又能保底完成「下下策」,讓不適任者淘汰。西方有選舉民主,東方有選賢任能,孰優孰劣,時間驗證一切。
第三集留給大家思考的問題是,不論在政界或商界,你有印象中危機公關處理得好的例子嗎?如果人人皆知危機公關如何處理,可能還會發生什麼事呢?
【Filostrato_趙:個人也認同“堵不如疏”,但是應該警醒一個誤區:“疏”是疏導,不等於完全不加幹預讓民意發酵,而是積極地澄清事實,引導輿論。因為在集體無意識下,民眾並不真正地渴求真相,你不重視引導,自然有人趁機攪渾水。所以,“堵不如疏”裡,“疏”也是一個主動作為的動作,而不是被動地招架。】
【耶列納:危機公關確實如你所分析的,要快准狠,不過如果人人都按套路來先臨時應付過去,沒有實質改正,可能反而也會引人反感的】
【Maggie Gu:我以為討論危機處理,前題當然是品質重要。但維持品質一但沒做好,就需要討論危機如何化為轉機。車廠發現氣囊故障,第一時間立刻召回處理,對大眾道歉,對消費者補償,可以將傷害降低。食品業被查獲過期品,對外回應:是為了累積一定數量再行銷毀。公關危機處理是一間公司(或組織)本來就必需具備的能力。】
【Barbara Shen:危機公關處理的好不好有這麼重要嗎?知道是危機公關處理,就表示政客,公關講的話都是相對的假話。公關處理的修辭與方法,就跟政客的修辭一樣,全部抵制。我認為怎麼處理不重要,我認為事實的品質更重要。談這個話題的目的就是要教消費者如何認識企業危機處理的方式,從而選擇對的企業。道歉誰都會道。但是道德不是每個人都有的。】
這四位網友說的都很好,我想表達就是,如果人人都懂了危機處理的套路,忽略了本身品質,是捨本逐末。因此大家需要關注那些在看似誠懇道歉的背後,是否拿出具體的措施與保證。
第四集的問題是,你還知道哪些方式能夠優化用戶體驗嗎?哪些企業或商家,是讓你覺得在用戶體驗上下過功夫的呢?
【Maggie Gu:某間位於西門町的青年旅館,設計了一面格子牆,方格內可放置個人盥洗用品。跟一般青旅需把濕漉漉的用品收納回床位,小小設計,大大貼心。】
好的設計不需要昂貴與技術,而是在某些細節之處能夠帶給使用者意想不到的便利。
【溫如言:大家都在說優化用戶體驗的,我想起個反例(或者說特別的例子):派派app。介面極其簡陋,但他偏偏能盈利。】
偷紅包跟整人的體驗非常吸引人,符合時下青年的範兒。
【耶列納:我覺得從用戶投訴中提煉也是很有效的,比廣泛撒網詢問客戶需求更精准。做得好的企業我認為微軟可以算上。之前Xbox送修,電話回訪很敬業。如果只是發問卷,我可能敷衍填下,但經歷了售後流程,再接到回訪電話,就很有話可說。】
台灣的許多電信公司也是客服結束後會有電話打來詢問剛才服務的滿意度。不過從用戶的投訴中提煉,讓我想起某位創業大神說的話,與其努力讓給你50分的客人變成給你70分,不如讓原本給你70分的客人給你到90分。乍聽違反常理,但細思很受啟發。
【David MengKe Lee:足夠理解市場、意味著開發方面相當瞭解目標客群以及知道利基市場所在。都已經夠瞭解了、幹嘛把自己當白癡來開發設計?直接設計客戶想掏錢買的產品就好啦!保時捷的設計概念不會與豐田一樣就是這個道理!因為區隔出自己的市場、滿足這個市場需求且足夠有發展就好。中高低階商品都出、最終下場看HTC應該就很好理解了。所以、別以為僅把自己當白癡就會開發出夠好的產品!消費者如今已經沒有這麼笨了~】
指涉的應該是兩個概念,你說的是市場區隔,針對目標客戶發展產品。但產品的設計,「把自己當白癡」是讓用戶能以極簡便的方式便能體驗產品。比如賈伯斯對IPOD的要求是找一首歌或使用一個功能,按鍵次數不能超過三次、對IPAD的要求是小朋友不看說明書都要會操作。
第五集留給大家討論的是,你知道哪些輕視對手、最後反被對手打敗的例子嗎?除了驕傲自大,還可能是那些原因?
【耶列納:除了驕傲自大,還有就是懶於去分析、適應新形勢吧。碰到一個問題,最便捷最懶的方法就是直接照搬以前的做法,但事物不是一成不變的,要保持警惕敏捷,注意變數,調整己方策略。當然這說來容易做來難啊】
【席睿:我認為敗因不是輕視對手,而是自身做得不好。】
兩位朋友說的都很正確,自己做不好的失敗可以理解,但問題往往在自己沒錯,卻還是失敗了。就是我們在第六集引用《創新者的兩難》一書所說,「就算我們把每件事情都做對了,也有可能錯失城池。」「面對新技術和新市場,往往導致失敗的恰恰是完美無瑕的管理。」能否適時的創新才是關鍵,《浪潮之巔》這本書提到「基因決定定律」,一家已經成功的公司,一旦新業務和傳統業務有衝突,通常的策略是犧牲新業務,畢竟既有業務多賺錢,新業務前途茫茫,讓轉型多了一個隱形的障礙。縱使下定決心開創新領域,也會不自覺用舊有的做事方法、思維方式去應對新市場,也難以真正開創新局面。
當然,在這一集,許多朋友都糾正,妹喜應該讀「末喜」,感謝朋友指正!
第六集請大家討論的是,大企業做了哪些錯誤的判斷,後來者又是如何創新的呢?大企業該如何避開既有局限,自我成長呢?
【耶列納:是的,體積大了就尾大不掉。而且大企業試錯成本高,面對各式新技術,如何能確定哪個是正確的選擇?對新創小企業來說卻不需要過多顧慮,如果找准切入點抓住機遇,更可能成功。】
這位朋友說得非常正確,GOOGLE的業務拆分、騰訊讓好幾個團隊同時設計即時通訊程式,都可作為借鑒。
【吳政億:紂王的淫亂殘暴 - 聽最近有文章出來 說都是封神演義杜撰的】
【林佳謀:其實子受辛恐怕不是歷史上所說的那麼暴虐無道,因為他被述說的無道行為和姒履癸太相似了,簡直是一模一樣!!所以姬發伐紂,恐怕有很多罪名是周王朝所杜撰出來的,把夏桀罪名如法泡製在商紂身上~~藉以證明自己反叛有理…】
兩位朋友說的沒錯,如郭沫若便寫過未紂王翻案的文章。〈牧誓〉最早記載紂王的罪過才四項,一是聽婦人言,二是不重視祭祀自己的祖先,三是不重用自己的兄弟,四是起用他國的逃犯。未提及酒池肉林或剖孕婦與炮烙等事,而四件事以現代角度看,根本沒多壞。紂王的腐敗,是後代加工而來。
綜觀這四點,我看來只有一個目的:團結同志。
周聯合了許多部落攻打商,包括許多商朝的舊有貴族,武王的說服對像是他們:紂王太壞了,他不聽你們大臣的話,去聽妲己的;他連你們家的祖先都不祭祀、禁止你們用奴隸殉葬,實在管太多;你們身為親戚的本來都可以當官,想不到紂王沒用你們,還用一堆戰犯;讓奴隸與咱平起平坐,大大損害我們貴族的利益!
〈牧誓〉指紂王提拔奴隸戰犯當官,「俾暴虐於百姓」,當時平民無姓,百姓指的是百官或貴族。罵完了紂王如何對大家不公平,接著武王說「今予發,惟恭行天之罰。」我姬發就代替上天懲罰紂王。
所以紂王有那麼壞嗎?還是子貢說的好。「君子惡居下流,天下之惡皆歸焉。」
感謝所有參與討問互動的朋友,每一則留言我都會親自看過,並逐一挑選。大家的建議我都看到了,髒話在後面會以消音形式播出,謝謝所有支持並給予鼓勵的朋友。至於來謾罵的也非常歡迎增加我們討論的熱度,但請不要罵到別人。「漢廷說歷史」是寒假期間的特別企劃,每天都有,祝福大家都能開心學歷史。我們明天見。
更新功能變數全部 在 如何知道你的word檔案中含有功能變數? - YouTube 的推薦與評價
![影片讀取中](/images/youtube.png)
請先下載測試word檔案1)選取 全部 後,查看底色不同的部份2)... ... 《尋找與取代》中的《到》功能3)顯現 功能變數 的程式碼~~幾行程式碼,勝過千軍萬馬~~. ... <看更多>
更新功能變數全部 在 [問題] Word問題:怎樣一口氣更新所有功能變數- 看板Office 的推薦與評價
軟體: word 2003
版本:?
因為在修文件 如果砍了其中一個方程式或圖片
我就是一個個去更新其他的標號的功能變數
這樣會累死人啦
有沒有方法點幾下就可以更新所有的功能變數
--
上半身 ◢◣ 我發誓我沒說謊! ◣ 下半身 ◢‧██‧◣ What Disney
◢██◣ ╯ ◣ ████ 《木偶奇遇記》
▄▄▄▄▄ ◣ ████
█-▇-▇ ◣ ██████████████
◤ > ◣ ◤ ◥
◥ ▼◤ ◣ ψdiabloq13
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.227.191.181
... <看更多>